Не удается найти правильный способ получить номера деталей с веб-страницы с помощью запросов

Я пытаюсь создать скрипт для анализа различных номеров деталей с веб-страницы с использованием запросов. Если вы проверите эту ссылку и нажмете на вкладку Product list, вы увидите номера деталей.

Не удается найти правильный способ получить номера деталей с веб-страницы с помощью запросов

представляет, где находятся номера деталей.

Я пробовал с:

import requests

link = 'https://www.festo.com/cat/en-id_id/products_ADNH'
post_url = 'https://www.festo.com/cfp/camosHTML5Client/cH5C/HRQ'

payload = {"q":4,"ReqID":21,"focus":"f24~v472_0","scroll":[],"events":["e468~12~0~472~0~4","e468_0~6~472"],"ito":22,"kms":4}

with requests.Session() as s:
    s.headers['user-agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
    s.headers['referer'] = 'https://www.festo.com/cfp/camosHTML5Client/cH5C/go?q=2'
    s.headers['content-type'] = 'application/json; charset=UTF-8'
    r = s.post(post_url,data=payload)
    print(r.json())

Когда я выполняю приведенный выше скрипт, я получаю следующий результат:

{'isRedirect': True, 'url': '../../camosStatic/Exception.html'}

Как я могу получить номера деталей с этого сайта с помощью запросов?

В случае с селеном я попытался, как показано ниже, получить номера деталей, но, похоже, скрипт не может щелкнуть вкладку списка продуктов, если я отключу от нее жестко запрограммированную задержку. Учитывая, что я не хочу использовать какую-либо жестко запрограммированную задержку в сценарии.

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
 
link = 'https://www.festo.com/cat/en-id_id/products_ADNH'
 
with webdriver.Chrome() as driver:
    driver.get(link)
    wait = WebDriverWait(driver,15)
    wait.until(EC.frame_to_be_available_and_switch_to_it(wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "object")))))
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#btn-group-cookie > input[value='Accept all cookies']"))).click()
    driver.switch_to.default_content()
    wait.until(EC.frame_to_be_available_and_switch_to_it(wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "iframe#CamosIFId")))))
    
    time.sleep(10)   #I would like to get rid of this hardcoded delay
    
    item = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "[id='r17'] > [id='f24']")))
    driver.execute_script("arguments[0].click();",item)
    for elem in wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "[data-ctcwgtname='tabTable'] [id^='v471_']")))[1:]:
        print(elem.text)

Если вы точно не знаете, какую полезную нагрузку вы должны предоставить, мы мало чем можем помочь. Их API кажется очень громоздким, поскольку в качестве параметров используются отдельные буквы. Возврат, который вы получаете, кажется, связан с недопустимым запросом. Я бы предложил посмотреть на селен в таком случае.

Nic Laforge 22.12.2020 05:50

Ключи и значения полезной нагрузки, которые я использовал, я взял из инструментов разработки.

MITHU 22.12.2020 05:56

Вы не можете сделать это! Каждый запрос будет иметь разные значения, если вы не знаете, как их использовать. Это безнадежное дело с использованием запроса. Это должно быть простой задачей с использованием селена, если вы знакомы с ним.

Nic Laforge 22.12.2020 05:58

Это определенно не безнадежное дело с использованием запросов, как вы упомянули. Всегда есть способы, которые я пытаюсь выяснить. К вашему сведению, я очень хорошо знаком с селеном, но я не хочу идти по этому пути. Спасибо.

MITHU 22.12.2020 06:05

Не сказал невозможно.. удачи! Удалось ли вам понять данные ответа?

Nic Laforge 22.12.2020 06:37

Обычно предпочитают имитировать запросы, но в данном случае я признаю, что Selenium — лучшая идея.

xwhitelight 22.12.2020 08:53

Я не могу ответить на вопрос, но могу высказать свое мнение. Сначала я подумал, что это проблема с файлами cookie, но я повторил запрос несколько раз, и все это привело к ответу "{"RID":0}". Хотя параметры запроса просты, я заметил небольшие различия между запросами, и я думаю, что ответом является правильная комбинация параметров запроса (и, возможно, файлов cookie). Если вы настаиваете на использовании запросов, вы можете посетить вкладку «Инициатор» запроса и изучить, как Js создает эти параметры. Скрипт не запутан, и в Chrome есть отличные инструменты для отладки, но Js-R.E. может занять некоторое время.

t.m.adam 22.12.2020 18:56

Чтобы помочь вам начать работу, в SubmitPostData() (функции, которая отправляет запрос) мы видим, что данные публикации хранятся в gPOSTData, который создается в DoSubmit() и содержит n.ReqID = ++gRequestID_Posted, r && (n.focus = r), n.scroll = SaveScrollEvents(), n.events = gArrEvents, n.externaldata = gExternalEventDataArray.arrData,n.ito = gEventController.GetIdleTime(), n.kms = EncodeMouseState());. Названия создают у меня впечатление, что большинство параметров выполняют некоторые базовые действия по снятию отпечатков пальцев клиента, возможно, для обнаружения автоматизации.

t.m.adam 22.12.2020 19:45

Спасибо за ваши большие усилия и предложение t.m.adam. Я потратил значительное количество времени, чтобы решить эту проблему, используя запросы, но безуспешно. Итак, на данный момент мне кажется, что я должен придерживаться селена, чтобы избежать чрезмерной сложности, как в первую очередь предложил @Nic Laforge. Тем не менее, я прикрепил свой подход к селену выше, который также застревает, когда нужно щелкнуть вкладку списка продуктов. Спасибо.

MITHU 22.12.2020 21:32

Вы можете использовать селен. Обратите внимание, что ваша таблица FRAME. Просто переключитесь на фрейм и найдите числа с помощью xpath или другого локатора.

Gaj Julije 24.12.2020 13:55

Это то, что я сделал в моем вышеприведенном сценарии @Gaj Julije.

MITHU 24.12.2020 16:46

Я не уверен, что вы можете обойти кнопку «принять все файлы cookie» с запросами python. Когда вы физически нажимаете кнопку, для сеанса устанавливается файл cookie «ckns_policy» и 4 других файла cookie. Я попытался обойти эту кнопку, вручную добавив файл cookie «ckns_policy» и другие, но пока ничего не работает.

Life is complex 27.12.2020 16:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
12
628
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Чтобы получить номера деталей с веб-страницы с помощью Selenium, вам необходимо:

  • Вызовите WebDriverWait, чтобы кадр object стал доступным, и переключитесь на него.

  • Вызовите WebDriverWait, чтобы нужный элемент стал кликабельным, и нажмите на Accept all cookies.

  • Вернитесь к default_content()

  • Вызовите WebDriverWait, чтобы нужный кадр стал доступен, и переключитесь на него.

  • Вызовите WebDriverWait для staleness_of() устаревшего элемента.

  • Нажмите на вкладку с текстом в качестве списка продуктов, используя execute_script().

  • Вы можете использовать следующие стратегии поиска:

    driver.get('https://www.festo.com/cat/en-id_id/products_ADNH')
    WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME,"object")))
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.btn.btn-primary#accept-all-cookies"))).click()
    driver.switch_to.default_content()
    WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe#CamosIFId")))
    WebDriverWait(driver, 20).until(EC.staleness_of(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//div[text()='Product list']")))))
    driver.execute_script("arguments[0].click();", WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[text()='Product list']"))))
    print([my_elem.get_attribute("innerHTML") for my_elem in WebDriverWait(driver, 20).until(EC.visibility_of_all_elements_located((By.XPATH, "//div[@class='ah']/img//following::div[2]")))])
    driver.quit()
    
  • Примечание. Вы должны добавить следующие импорты:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
  • Выход консоли:

    ['539691', '539692', '539693', '539694']
    

Ссылка

Вы можете найти пару соответствующих обсуждений в:

Я попробовал ваш код, но он не сработал. Он зависает, когда он должен щелкнуть вкладку со списком продуктов, и в конечном итоге выдает исключение тайм-аута, указывающее на эту строку print(). Код, который я вставил выше, является рабочим, но мне пришлось использовать жестко запрограммированную задержку, чтобы заставить его работать.

MITHU 26.12.2020 07:02
Ответ принят как подходящий

Трудность для водителя состоит в том, чтобы нажать кнопку «Список продуктов», поэтому я нашел решение:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.common.exceptions import TimeoutException, StaleElementReferenceException
from selenium import webdriver
import time

class NoPartsNumberException(Exception):
    pass

driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)


driver.get("https://www.festo.com/cat/en-id_id/products_ADNH")
wait.until(ec.frame_to_be_available_and_switch_to_it(wait.until(ec.visibility_of_element_located((By.CSS_SELECTOR, "object")))))
wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "#btn-group-cookie > input[value='Accept all cookies']"))).click()
driver.switch_to.default_content()
wait.until(ec.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[@name='CamosIF']")))

endtime = time.time() + 30
while True:
    try:
        if time.time() > endtime:
            raise NoPartsNumberException('No parts number found')
        product_list = wait.until(ec.element_to_be_clickable((By.XPATH, "//div[@id='f24']")))
        product_list.click()
        part_numbers_elements = wait.until(ec.visibility_of_all_elements_located((By.XPATH, "//div[contains(@id, 'v471')]")))
        break
    except (TimeoutException, StaleElementReferenceException):
        pass

part_numbers = [p.text for p in part_numbers_elements[1:]]
print(part_numbers)

driver.close()

Таким образом, драйвер нажимает кнопку «Список продуктов», пока не откроется окно, содержащее номера деталей, и вам придется ждать гораздо меньше 10 секунд, как в вашем коде с жестко запрограммированным временем сна.

Если вы не дойдете до оператора break, этот цикл будет бесконечным. Вы повышаете/ререйзите TimeoutException и игнорируете это в своем заявлении о ловле. У вас должна быть проверка истечения времени в качестве условия для входа в цикл. Вам также нужно обработать, если он никогда не достигнет оператора break. ОП уже использует until() не вижу смысла создавать такой цикл while.

Nic Laforge 27.12.2020 03:50

Разрыв достижим, когда код достигает тайм-аута, в то время как он игнорирует исключение TimeoutException, заданное, когда он не находит элементы номеров деталей. Если он не находит номера деталей, он прерывает цикл while и вызывает исключение TimeoutException. По сути, то, что я написал, — это пользовательская функция, которая ждет, пока элемент действительно станет кликабельным. Вы пробовали мой код? Потому что я проверил это, и это работает очень хорошо

marco 27.12.2020 12:08

Я должен понизить это. Просто сказать, что это работает, не делает вышесказанное правильным. Вы точно не проверили время истекло. Опять же, это создаст бесконечный цикл. Я согласен, что вы создали еще один wait.until() с вашим кодом, но почему. Вы можете использовать until из селена и создать свой собственный класс (см. мой ответ). Устранение необходимости обрабатывать тайм-аут, исключение, повторяющийся код, подверженность ошибкам

Nic Laforge 27.12.2020 23:19

извините, вы правы, я написал свое собственное исключение TimeoutException, но это была плохая идея. Я отредактирую ответ с другим исключением

marco 28.12.2020 00:06

Я считаю, что вы хорошо рассмотрели концепцию iframe и WebDriverWait.

Сайт, кажется, повторно отображает контент несколько раз, прежде чем сможет получить нужный элемент и щелкнуть по нему. Поэтому вам пришлось добавить сон на 10 секунд.

Существует мнение, что при использовании EC необходимо использовать WebDriverWait. EC — это всего лишь набор хелперов класса для извлечения элемента с некоторыми определенными свойствами (например, видимый, скрытый, кликабельный...)

В вашем случае ec.visibility_of_all_elements_located был хорошим выбором. Но как только элемент получен, DOM повторно арендуется, и вы сгенерируете StaleElementReferenceException, если вы используете метод клика WebElement. Также полагайте, что щелчок с использованием JS будет просто проигнорирован, так как переданного элемента больше нет.

Поскольку until() можно использовать для определения момента возврата элемента, почему бы не использовать его и не создать собственный класс EC:

class SelectProductTab(object):
    def __init__(self, locator):
        self.locator = locator
        self._selected_background_image = 'url("IMG?i=ec2a883936d53541a030c2ddb511e7e8&s=p")'

    def __call__(self, driver):
        els = driver.find_elements(*self.locator)
        if len(els) > 0:
            els[0].click()
        else:
            return False
        return els[0] if self.__is_selected(els[0]) else False

    def __is_selected(self, el):
        return self._selected_background_image in el.get_attribute('style')

Этот класс будет делать следующее:

  1. Получить элемент
  2. Нажмите здесь
  3. Убедитесь, что нужная вкладка выбрана. В основном убедитесь, что щелчок сработал
  4. При выборе вкладки возвращает элемент обратно вызывающей стороне

Одна часть не обрабатывается, так как WebDriverWait уже поддерживает ее, это обработка исключения. В вашем случае вы столкнетесь с StaleElementReferenceException.

wait = WebDriverWait(driver, 30, ignored_exceptions=(StaleElementReferenceException, ))

Затем вызовите until() с собственной реализацией класса EC:

wait.until(SelectProductTab((By.CSS_SELECTOR, "[id='r17'] > [id='f24']")))

Полный код:

with webdriver.Chrome(ChromeDriverManager().install(), options=options) as driver:
    driver.get(link)
    wait = WebDriverWait(driver, 15)
    wait.until(EC.frame_to_be_available_and_switch_to_it(
        wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "object")))))
    wait.until(EC.presence_of_element_located(
        (By.CSS_SELECTOR, "#btn-group-cookie > input[value='Accept all cookies']"))).click()
    driver.switch_to.default_content()
    wait.until(EC.frame_to_be_available_and_switch_to_it(
        wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "iframe#CamosIFId")))))
    
    # Sleep was removed, click is now handled inside our own EC class + will ensure the tab is selected
    wait = WebDriverWait(driver, 30, ignored_exceptions=(StaleElementReferenceException, ))
    
    wait.until(SelectProductTab((By.CSS_SELECTOR, "[id='r17'] > [id='f24']")))
    
for elem in wait.until(
                EC.presence_of_all_elements_located((By.CSS_SELECTOR, "[data-ctcwgtname='tabTable'] [id^='v471_']")))[1:]:
            print(elem.text)

Выход:

539691
539692
539693
539694

Примечание для импорта следующего импорта:

from selenium.common.exceptions import StaleElementReferenceException

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