-3

Нужно чтобы при вводе марки и модели авто выдавалось масло которое подходит под конкретный автомобиль.

Сайт с которого нужно спарсить поиск: https://www.kroon-oil.com/ru/

import requests
from bs4 import BeautifulSoup as BS
query = input('Введите марку и модель авто: ')
api_url = 'https://www.kroon-oil.com/api/carlist.json'
car_models = requests.post(api_url, json={"query":query}).json()

try: car = car_models['response'][0] except: car = car_models['response'][1] base_url = 'https://www.kroon-oil.com/ru/product-recommendation/cars/{}/{}/{}/{}' url = base_url.format(car['make_url_name'], car['model_url_name'], car['type_url_name'], car['type_id']) soup = BS(requests.get(url).content, 'lxml') sections = soup.find_all('h2') for section in sections: print(section.text.strip('\n')) section_url = url+'/'+section.parent['data-componentid'] soup = BS(requests.get(section_url).content, 'lxml') try: products = soup.find('ul', class_='recommended-products').find_all('h3') except: break for product in products: print('\t{}'.format(product.text))

2 Answers2

1

Весь представленный вами код можно сократить до нескольких строчек, если использовать XHR. Как анализировать сайты в браузере в вкладке Network можно посмотреть в других моих ответах, например здесь.

import requests
query = 'Touareg'
api_url = 'https://www.kroon-oil.com/api/carlist.json'
car_models = requests.post(api_url, json={"query":query}).json()

Всё, теперь у нас в car_models список всех автомобилей найденных по запросу.
Но дальше необходимо выбрать автомобиль и получить масло, верно?
Возьмём какую-нибудь отдельно взятую модель, например мою любимую, дизельную. Посмотрим что есть в выданном .
car_models['response'][1]:

{'label_minimal': 'Volkswagen (VW) (EU) Touareg 2.5 TDI DPF (2006-2010)',
 'label': 'Volkswagen (VW) (EU) Touareg 7L Touareg 2.5 TDI DPF (2006-2010)',
 'type_id': 31013,
 'type_url_name': 'touareg-25-tdi-dpf',
 'model_url_name': 'touareg-7l',
 'model_name': 'Touareg 7L',
 'make_url_name': 'volkswagen-vw-eu',
 'make_name': 'Volkswagen (VW) (EU)',
 'category_url_name': 'cars',
 'category_name': 'Cars'}

Ссылка на результирующую страницу собирается из этих данных, и по ней уже, к сожалению, api нет, придётся парсить масло со страницы.
Причём сами рекомендации масла по секциям загружаются в отдельных страницах, так что запросов будет много. Если, конечно, необходимо раскрыть все секции.

from bs4 import BeautifulSoup as BS

car = car_models['response'][1] base_url = 'https://www.kroon-oil.com/ru/product-recommendation/cars/{}/{}/{}/{}' url = base_url.format(car['make_url_name'], car['model_url_name'], car['type_url_name'], car['type_id']) soup = BS(requests.get(url).content, 'lxml') sections = soup.find_all('h2') for section in sections: print(section.text.strip('\n')) section_url = url+'/'+section.parent['data-componentid'] soup = BS(requests.get(section_url).content, 'lxml') products = soup.find('ul', class_='recommended-products').find_all('h3') for product in products: print('\t{}'.format(product.text))

Вывод:

Двигатель BPD, BPE
    Helar SP LL-03 5W-30
Дифференциал задний 
    SP Gear 1011
    Syngear TDL 75W-90
Дифференциал задний самоблокирующийся (4x4)
    SP Gear 1071
Дифференциал передний 
    SP Gear 1011
    Syngear TDL 75W-90
Коробка передач в блоке с главной передачей автом 09D 6/1
    SP Matic 4026
Коробка передач в блоке с главной передачей механ 08D 6/1
    SP Gear 5015
Раздаточная коробка 0AD
    SP Gear 1081
Гидравлические тормоза/система сцепления 
    Drauliquid-LV Super DOT 4
Усилитель рулевого управления 
    SP Fluid 3013
Система охлаждения 
    Coolant SP 13
    Coolant SP 12

По вашему коду. Лучше использовать lxml, если он отрабатывает, он быстрее. html.parser стоит использовать только когда что-то парсится неправильно и / или отсуствует.

Всё что ниже, в супе, как указал выше в ответе, найдётся в лучшем случае только одна секция.

А ещё всем новичкам крайне полезно пройти тур.

DiMithras
  • 2,658
  • спасибо) но етсь момент, добавил код и ругается на одну переменную: Traceback (most recent call last): File "D:\Python home\mytelebot1\Test.py", line 32, in url = base_url.format(car['make_url_name'], ^^^ NameError: name 'car' is not defined. Did you mean: 'chr'? все "car" подсвечивает красным как ошибка – Анатолий Кузьмич May 13 '23 at 16:16
  • Может что-то схрючил, когда код выкладывал, перепроверю позже – DiMithras May 13 '23 at 17:09
  • Так, поправил с мобильного, должно работать, просто я переменную переименовал в процессе и она у меня в IPython отработала. – DiMithras May 13 '23 at 17:13
  • да. подбравил все заработало, только мне надо чтобы выводило не только по туарегу. а чтобы введите авто: например: volvo s80 D5 (D5 это модификация мотора) – Анатолий Кузьмич May 13 '23 at 17:23
  • @АнатолийКузьмич Так замените query = 'Touareg' на input или сообщение из бота, который изначально обсуждался. Если рассматривать вариант с ботом, то, если по поиску выводит одну позицию (модель) — продолжать, если моделей несколько, вывести пользователю список в inline keyboard, чтобы можно было выбрать нужную. – DiMithras May 14 '23 at 14:24
  • ,import requests from bs4 import BeautifulSoup as BS query = input('Введите марку и модель авто: ') api_url = 'https://www.kroon-oil.com/api/carlist.json' car_models = requests.post(api_url, json={"query":"тут тоже тогда надо: querty??"}).json() , но если так прописать то выбивает ошибку: Введите марку и модель авто: volvo s80 Traceback (most recent call last): File "D:\Python home\mytelebot1\Test.py", line 31, in car = car_models['response'][1] ~~~~~~~~~~~~~~~~~~~~~~^^^ IndexError: list index out of range – Анатолий Кузьмич May 14 '23 at 14:34
  • @АнатолийКузьмич не понимаю, что у вас не получается. Вот. – DiMithras May 14 '23 at 14:39
  • нашел ошибку , да, теперь показывает: volvo s80 d5, но например запрос Volvo s80 d2 выдет ошибку: Введите марку и модель авто: volvo s80 d2 2013 Traceback (most recent call last): File "D:\Python home\mytelebot1\Test.py", line 31, in car = car_models['response'][1] ~~~~~~~~~~~~~~~~~~~~~~^^^ IndexError: list index out of range – Анатолий Кузьмич May 14 '23 at 14:59
  • @АнатолийКузьмич смотрите, Анатолий. Ошибка в том, что вы пытаетесь обратиться к списку, вероятно полностью копируя вторую часть кода из ответа, и используете индекс 1, но т.к. по данному запросу находит единственную модель, в списке всего одна позиция доступная по индексу 0. Вопрос был про то как спарсить, ответ дан. Читайте выше по комментариям, если вы будете делать бота, то вам между первым блоком кода и вторым необходимо сделать обвязку и проверку на количество. Если только одна позиция — выводить её, если несколько — спрашивать пользователя, какая именно ему необходима. – DiMithras May 14 '23 at 15:23
  • добавил через try, exept, теперь без ошибок проверяет два вариант, но есть пару авто в который есть раздел кондиционирования и там выдает ошибку Компрессор кондиционера Traceback (most recent call last): File "D:\Python home\mytelebot1\Test.py", line 45, in products = soup.find('ul', class_='recommended-products').find_all('h3') ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'find_all' , запрос был по авто: renault scenic 2016 , на сайте пишет: Мы не можем предоставить стандартные реко.. – Анатолий Кузьмич May 14 '23 at 15:56
  • как я понял в этом разделе оно не может найти текст h3 и падает в ошибку, поставил тоже try и exept , все изменения внес в шапке кода. Верно же? – Анатолий Кузьмич May 14 '23 at 16:01
  • и что если наш пользователь не додумается написать на англ. языке , а таких будет большинство то оно упадет в ошибку и бот встанет же? как решить этот момент? – Анатолий Кузьмич May 14 '23 at 16:13
  • Первый try / except очень плохой, во втором есть смысл не break ставить, а pass или continue. Если пользователь не додумается написать на английском языке, то будет пустой массив. А тут надо либо: 1. уведомить пользователя, что он не прав; 2. Перевести ввод на русском на английский, для этого есть библиотеки. В любом случае, всё это выходит за рамки заданного вопроса. – DiMithras May 14 '23 at 16:19
  • а чем плох первый try / except ? как лучше его правильно написать? второй изменил на continue но тогда во всех разделах которые пустые остаются без какого либо описания, как там написать что то типо: не найдено ? – Анатолий Кузьмич May 14 '23 at 16:26
  • @АнатолийКузьмич тем что он не несёт никакого логического смысла. Моделей может не быть, может быть одна, а может быть 50. Вы своим try / except смотрите только первую, а если её не будет (пусто), то обращаетесь к второй. Это очень плохо. как написать, что не найдено? except: print('\t Не найдено') – DiMithras May 14 '23 at 16:42
  • по поводу не найдено я так уже пробовал и оно пишет вот так: Система охлаждения Coolant SP 16 Компрессор кондиционера Не найдено Coolant SP 16 Кондиционирование воздуха Не найдено Coolant SP 16 , т.е оно берет последнее найденное из раздела Система охлаждения и дублирует в последующие разделы + добавляет не найдено, как то не очень выходит... – Анатолий Кузьмич May 14 '23 at 16:48
  • @АнатолийКузьмич давайте так. Я попробовал ввести очень редкий автомобиль и там секций в разы меньше. 4 секции простив 10 на Touareg. Если на какую-то секцию нет товаров, то она просто не будет отображаться. try / except здесь не нужен в принципе. Я не понимаю, что вы хотите. Если у вас что-то не получается, я бы предложил вам оформить это в новый вопрос, т.к. в текущей ситуации комментарии вышли за рамки изначального вопроса. – DiMithras May 14 '23 at 21:01
0

введите сюда описание изображенияМожно это реализовать вот так:

import requests
from bs4 import BeautifulSoup
import re
query = "тут поидее должен быть input"
query = query.replace(' ', '+')
URL = f"https://www.kroon-oil.com/ru/product-recommendation/cars/nissan-eu/100-nx/100-nx-16-b13/24048/1577/#!/component:1577/"
USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0"
headers = {"user-agent": USER_AGENT}
resp = requests.get(URL, headers=headers)
dict_fuel = []
if resp.status_code == 200:
    soup = BeautifulSoup(resp.content, "lxml")
    for i in range(len(soup.find_all('h3'))):
    val = soup.find_all('h3')[i].text
    print(re.sub('[ЁёА-я]', '', val).rstrip())

  • в вашем коде показывает только по указанной ссылке на ниссан. Нужно чтобы был ввод марки и модели и по этому запросу выбивало на любое авто – Анатолий Кузьмич May 14 '23 at 09:36
  • я думаю автору кода не составить труда прописать input – Алексндр Босов May 14 '23 at 11:20
  • я добавил input , можете посмотреть в шапке (отредактировал весь код) , но не понятно какую ссылку ставить, перепробовал уже много разных, покажите пожалуйста полностью исправный варинат – Анатолий Кузьмич May 14 '23 at 14:29
  • я добавил изображение примера – Алексндр Босов May 14 '23 at 15:16
  • попробовал ваш вариант но оно ищет только по тому автомобилю который указан в ссылке, в данном случае это только ауди, если я ввожу в инпут любой другой бренд то выдает тоже самое по ауди – Анатолий Кузьмич May 14 '23 at 15:28
  • @АнатолийКузьмич как по Audi? В ответе статичная ссылка на Nissan – DiMithras May 14 '23 at 15:42
  • @DiMithras там чуть выше есть скрин с кодом , там прописан ауди) – Анатолий Кузьмич May 14 '23 at 16:02
  • @АнатолийКузьмич то что на скрине, да, динамики прибавилось, но динамика исключительно на производителя. Если его сменить, то ссылка битая будет. Я вам расписал как такая ссылка формируется, пожалуйста, ознакомьтесь. – DiMithras May 14 '23 at 21:05