Исключение TimeoutException при доступе к элементу в модальном режиме с использованием Selenium

#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 работает лучше, чем другие способы поиска элементов?