#python #selenium #web-scraping #timeoutexception
Вопрос:
Проблема
Я хочу извлечь истории версий приложений на веб-сайте Apple App Store. Это элементы в модальном контейнере, который появляется при нажатии кнопки История версий.
Я ни за что на свете не могу понять, почему исключение TimeoutException возникает периодически, когда я пытаюсь получить доступ к элементам в модальном — независимо от того, неправильно ли я написал CSS_SELECTOR или недостаточно долго продлил время ожидания. Иногда код выполняется успешно и возвращает мне желаемый список историй версий, но в большинстве случаев это не работает.
Я буду признателен за любую помощь.
Соответствующий HTML
Веб-сайт, о котором идет речь: Магазин приложений Twitter.
Кнопка для нажатия:
<div class="version-history">
<button class="we-modal__show link section__nav__see-all-link" id="modal-trigger-ember215599187" data-metrics-click="{amp;quot;actionTypeamp;quot;:amp;quot;openamp;quot;,amp;quot;targetTypeamp;quot;:amp;quot;buttonamp;quot;,amp;quot;targetIdamp;quot;:amp;quot;ModalVersionHistoryamp;quot;}" type="button">Version History</button>
</div>
Модальный, когда кнопка не нажата:
<div id="modal-container"></div>
Модальный при нажатии кнопки:
<div id="modal-container">
<div class="we-modal we-modal--page-overlay we-modal--open version-history" role="dialog" aria-hidden="false" aria-labelledby="modal-trigger-ember148" tabindex="0">
<div class="we-modal__content large-10 medium-12 " id="modal-content-ember148" role="document" tabindex="0" data-focus-method="mouse">
<div class="we-modal__content__wrapper">
<h3 class="version-history__headline">Version History</h3>
<ul class="version-history__items">
<li class="version-history__item">
<h4 class="version-history__item__version-number">8.86</h4>
<time data-test-we-datetime="" datetime="2021-10-07T00:00:00.000Z" aria-label="October 7, 2021" class="version-history__item__release-date">Oct 7, 2021</time>
<div class="we-truncate we-truncate--multi-line we-truncate--interactive version-history__item__release-notes" dir="" aria-label="">
<div data-clamp="" class="we-clamp">
<p dir="ltr" data-test-bidi="">We made improvements and squashed bugs so Twitter is even better for you.</p>
</div>
</div>
</li>
<!-- More li content follows -->
</div>
</div>
</div>
</div>
Мой код
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless")
url = "https://apps.apple.com/us/app/twitter/id333903271?ign-mpt=uo=4"
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
driver.get(url)
# click on Version History button
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.version-history > button[class="we-modal__show link section__nav__see-all-link"]')))
button = driver.find_element_by_css_selector('.version-history > button[class="we-modal__show link section__nav__see-all-link"]')
button.click()
# get all versions into an array
modal = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, 'div[id="modal-container"]')))
version_items = modal.find_elements_by_tag_name("h4")
versions = list(map(lambda v: v.text, version_items))
driver.close()
Ошибка, которую я испытываю
TimeoutException Traceback (most recent call last)
~AppDataLocalTemp/ipykernel_60716/874757843.py in <module>
18 #version_items = driver.find_elements_by_css_selector('#modal-container > h4')
19
---> 20 modal = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, 'div[id="modal-container"]')))
21 version_items = modal.find_elements_by_tag_name("h4")
22
~miniconda3libsite-packagesseleniumwebdriversupportwait.py in until(self, method, message)
78 if time.time() > end_time:
79 break
---> 80 raise TimeoutException(message, screen, stacktrace)
81
82 def until_not(self, method, message=''):
TimeoutException: Message:
Ответ №1:
Измените также строку, в которой вы получаете модальное значение с visibility_of_element_located на presence_of_element_located; Я рекомендую использовать XPATH.
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import time
url = "https://apps.apple.com/us/app/twitter/id333903271?ign-mpt=uo=4"
driver = webdriver.Chrome('chromedriver.exe')
driver.get(url)
# click on Version History button
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[4]/div/main/div[2]/section[4]/div[1]/div/button')))
button = driver.find_element_by_xpath('/html/body/div[4]/div/main/div[2]/section[4]/div[1]/div/button')
button.click()
# get all versions into an array
modal = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '/html/body/div[5]')))
version_items = modal.find_elements_by_tag_name("h4")
versions = list(map(lambda v: v.text, version_items))
print(versions)
time.sleep(10)
Комментарии:
1. Эй! Спасибо, это сработало. Я немного сбит с толку, хотя я думал, что в этом случае потребуется, чтобы модальный элемент был видимым, а не просто присутствовал в DOM? И почему использование XPATH работает лучше, чем другие способы поиска элементов?