я пытаюсь отобразить цены на:
Я пробовал с запросами и запросами-html, но ни один из них не работает...
Вот мой код:
from requests_html import HTMLSession
session = HTMLSession()
from bs4 import BeautifulSoup
response = session.get('https://campervans.jeanlain.com/locations/?city-input=annecy&city-name=ANNECY&departure_date=06%2F01%2F2025&departure_time=11%3A00&return_date=10%2F01%2F2025&return_time=10%3A00')
response.html.render()
soup = BeautifulSoup(response.html.html, 'html.parser')
products = soup.find_all('section', class_='product')
for product in products:
title = product.find('h2', class_='woocommerce-loop-product__title')
if title:
print(title.text)
price_info = product.find('div', class_='content-right')
if price_info:
price = price_info.find('p', class_='price')
print(price)
else:
print("content-right not found")
Проблема в том, что div "content-right" отображается на странице, но не в ответе... Кажется, он загружен с помощью javascript...
Как получить цены, отображаемые с помощью запросов Python, только при загрузке JavaScript? Я не хочу использовать Selenium...
Спасибо :)
@jabaa, я отредактировал свой пост, вопрос в том, «как получить, чтобы цены отображались с помощью запросов Python только тогда, когда загружен JavaScript?»
Попробуйте selenium
.
@MSH «Я не хочу использовать Selenium…»
Я не уверен, использует ли requests_html
уже selenium
или использует PyQt
(QWebKit
) для имитации браузера и запуска JavaScript. Возможно, вам придется sleep()
подождать перед рендерингом данных.
@furas Согласно github.com/kennethreitz/requests-html , он использует pyppeteer
и pyppeteer
использует pupeteer
, но не поддерживается: github.com/pyppeteer/pyppeteer
@jabaa, спасибо :) Тем временем я проверял страницу запросов-html на предмет этой информации :) Теперь я пытаюсь выяснить, имеет ли requests_html
доступ к puppeteer
, чтобы контролировать, существует ли объект на странице - как в selenium
.
на основе документации вы можете использовать render(..., sleep=...)
, чтобы дождаться результатов — это может дать JavaScript время для отображения всей информации. Он также может использовать render(... script=...)
для запуска кода JavaScript — это может позволить выполнить код, который может получить какой-то элемент или щелкнуть какой-то элемент.
Возможно, вам повезет больше с Requests_html2
Если вы немного изучите HTML, в частности тег скрипта, в котором определена эта переменная const ajaxurl = "https://campervans.jeanlain.com/wp/wp-admin/admin-ajax.php";
, вы увидите, как это делает сам «клиент». Так что вам просто нужно сделать это еще раз, но на питоне. Вы можете увидеть это в моем ответе, возможно, это будет кому-то полезно.
Я не знаю, есть ли способ проверить, завершил ли работу JavaScript, но он позволяет использовать параметр sleep
, и у JavaScript может быть время для работы.
response.html.render(sleep=3)
и это дает результаты.
Он также позволяет отправлять код JavaScript, который может проверить, существует ли элемент.
response.html.render(script = "...")
но у меня нет кода для этого. И, вероятно, для этого также потребуется использовать sleep
.
Последняя идея: selenium
имеет функции Waits
, которые запускают цикл и периодически проверяют, существует ли элемент.
И requests_html
есть вариант keep_page
request_html.html.render(keep_page=True)
который позволяет взаимодействовать со страницей браузера через html.page
.
И вы можете использовать его для периодической проверки, существует ли элемент.
КСТАТИ:
Я получаю результат без сна, когда использую не BeautifulSoup
, а встроенные функции для поиска данных. Возможно, эти функции уже используют больше времени для проверки существования объекта. Или, может быть, это случайно.
В примере я использую xpath
для этого:
from requests_html import HTMLSession
session = HTMLSession()
response = session.get('https://campervans.jeanlain.com/locations/?city-input=annecy&city-name=ANNECY&departure_date=06%2F01%2F2025&departure_time=11%3A00&return_date=10%2F01%2F2025&return_time=10%3A00')
response.html.render()
products = response.html.xpath('//section[contains(@class, "product")]')
for product in products:
title = product.xpath('.//h2[contains(@class, "woocommerce-loop-product__title")]', first=True)
if title:
print(title.text)
price_info = product.xpath('.//div[contains(@class, "content-right")]', first=True)
if price_info:
price = price_info.xpath('.//p[contains(@class, "price")]', first=True)
if price:
print(price.text.strip())
else:
print(price)
else:
print("content-right not found")
Результат:
CITROEN AMENAGE
339,98 €
CITROEN AMENAGE
None
CITROEN AMENAGE
339,98 €
CITROEN AMENAGE
339,98 €
CITROEN AMENAGE
None
VW CALIFORNIA
400,00 €
VW CALIFORNIA
None
VW CALIFORNIA
None
VW CALIFORNIA
None
VW CALIFORNIA AT
None
VW CALIFORNIA 4M AT
None
VW CALIFORNIA 4M AT
400,00 €
VW CALIFORNIA AT
400,00 €
VW CALIFORNIA BEACH
360,00 €
Здравствуйте, спасибо за ваш ответ, кажется, это работает при добавлении «sleep=3» и использовании встроенных функций Requests-html для поиска данных, большое вам спасибо!
Вам не нужно использовать что-то, имитирующее браузер. Вам просто нужно сделать один дополнительный запрос. Если вы зайдете в инструменты разработки, вы увидите эту конечную точку и поймете, что это именно то, что вам нужно:
Вот сама конечная точка . Используйте библиотеку request
, чтобы отправить запрос POST
на получение данных из этой конечной точки, передав дополнительные параметры:
В итоге, если сделать это через Python, то получится что-то вроде этого:
import requests
response = requests.post(
'https://campervans.jeanlain.com/wp/wp-admin/admin-ajax.php',
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Cache-Control': 'no-cache',
},
data = {
'action': 'products_list_prices',
'agency': 'annecy',
'nonce': '839a81d954', # it's nailed down in the html
'agency_city': 'ANNECY',
'begin_date': '06/01/2025',
'begin_hour': '11:00',
'end_date': '10/01/2025',
'end_hour': '10:00',
},
)
data = response.json()
Вы сможете передавать все ключи, кроме action
и nonce
, динамически. Тогда это вопрос техники, чтобы сопоставить это при анализе html.
for product in products:
data_immatriculation = product['data-immatriculation']
title = product.find('h2', class_='woocommerce-loop-product__title')
price = data.get(data_immatriculation, {}).get('total_price')
# if price = None - not available product
print(f'{price=}')
ОБНОВЛЕНО
Чтобы исправить то, что вы написали в комментарии, вам нужно было просто получить данные (скриншот 1) из HTML
и передать их в запросе POST
. Или изначально сохраните данные запроса get
и передайте их (скриншот 2, я говорю о том, что прошло через URL).
Здравствуйте, спасибо за ваш ответ, я делал так, но проблема в том, что ajax-admin.php отображает цену даже для недоступного фургона, поэтому я хотел найти другой способ... Спасибо @furas, который нашел решение!
Я обновил ответ. Если вы правильно пишете запрос, цены на недоступный фургон нет, я это проверял. Я добавил, почему это, вероятно, не сработало для вас.
«Есть ли способ узнать цены?» Да, вы можете либо оценить код JavaScript, либо смоделировать его и напрямую получить доступ к API.