Этот веб-сайт невозможно правильно очистить даже с помощью requets-html

я пытаюсь отобразить цены на:

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

Я пробовал с запросами и запросами-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...

Спасибо :)

«Есть ли способ узнать цены?» Да, вы можете либо оценить код JavaScript, либо смоделировать его и напрямую получить доступ к API.

jabaa 02.07.2024 12:59

@jabaa, я отредактировал свой пост, вопрос в том, «как получить, чтобы цены отображались с помощью запросов Python только тогда, когда загружен JavaScript?»

Gbn 02.07.2024 12:59

Попробуйте selenium.

MSH 02.07.2024 13:03

@MSH «Я не хочу использовать Selenium…»

jabaa 02.07.2024 13:03

Я не уверен, использует ли requests_html уже selenium или использует PyQt (QWebKit) для имитации браузера и запуска JavaScript. Возможно, вам придется sleep() подождать перед рендерингом данных.

furas 02.07.2024 13:37

@furas Согласно github.com/kennethreitz/requests-html , он использует pyppeteer и pyppeteer использует pupeteer, но не поддерживается: github.com/pyppeteer/pyppeteer

jabaa 02.07.2024 13:39

@jabaa, спасибо :) Тем временем я проверял страницу запросов-html на предмет этой информации :) Теперь я пытаюсь выяснить, имеет ли requests_html доступ к puppeteer, чтобы контролировать, существует ли объект на странице - как в selenium.

furas 02.07.2024 13:44

на основе документации вы можете использовать render(..., sleep=...), чтобы дождаться результатов — это может дать JavaScript время для отображения всей информации. Он также может использовать render(... script=...) для запуска кода JavaScript — это может позволить выполнить код, который может получить какой-то элемент или щелкнуть какой-то элемент.

furas 02.07.2024 13:49

Возможно, вам повезет больше с Requests_html2

SIGHUP 02.07.2024 15:18

Если вы немного изучите HTML, в частности тег скрипта, в котором определена эта переменная const ajaxurl = "https://campervans.jeanlain.com/wp/wp-admin/admin-ajax.php"‌​;, вы увидите, как это делает сам «клиент». Так что вам просто нужно сделать это еще раз, но на питоне. Вы можете увидеть это в моем ответе, возможно, это будет кому-то полезно.

Serhii Fomenko 02.07.2024 15:45
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
6
10
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я не знаю, есть ли способ проверить, завершил ли работу 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 для поиска данных, большое вам спасибо!

Gbn 02.07.2024 15:45

Вам не нужно использовать что-то, имитирующее браузер. Вам просто нужно сделать один дополнительный запрос. Если вы зайдете в инструменты разработки, вы увидите эту конечную точку и поймете, что это именно то, что вам нужно:

Вот сама конечная точка . Используйте библиотеку 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, который нашел решение!

Gbn 02.07.2024 15:44

Я обновил ответ. Если вы правильно пишете запрос, цены на недоступный фургон нет, я это проверял. Я добавил, почему это, вероятно, не сработало для вас.

Serhii Fomenko 02.07.2024 15:58

Другие вопросы по теме