Как дождаться с помощью Python полной загрузки страницы?

Есть список урлов, которые нужно обойти и собрать нужные элементы. Но иногда при проходе по этим урлам, некоторые из них как-будто не загружаются полностью и программа переходит к следующему урлу. Соответственно, нужные элементы не находятся, но они точно есть. Программа всегда по разному выполняется, иногда все ссылки открываются как надо, иногда рандомно с какой-то из них происходит такая ситуация. Подскажите, пожалуйста, как добавить обязательное условие, проверяющее загрузилась ли полностью страница перед поиском нужного элемента?

Например код:

from selenium import webdriver
from bs4 import BeautifulSoup

driver = webdriver.Chrome(executable_path='C:\\..\chromedriver.exe')
url = ['http://www.yandex.ru/', 'https://www.google.com/']
for i in url:
    driver.get(i)
    time.sleep(2)
    html = driver.find_element_by_xpath("//div[@id='content-all']").get_attribute("innerHTML")

Ответы (1 шт):

Автор решения: gil9red

1. Задавайте явное ожидание элемента, например:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Chrome(executable_path='C:\\..\chromedriver.exe')
driver.get('https://ya.ru')
timeout = 5
try:
    # Вместо body возможно нужен другой тег указывать, характерный для сайта
    element_present = EC.presence_of_element_located((By.TAG_NAME, 'body'))
    WebDriverWait(driver, timeout).until(element_present)
except TimeoutException:
    print("Timed out waiting for page to load")

Можно разные условия ожидания элемента ставить (например, visibility_of_element_located), смотрите в expected_conditions as EC и разные способы поиска, например по атрибуту id, смотрите в By:

element_present = EC.presence_of_element_located((By.ID, 'element_id'))

2. Можно задавать через set_page_load_timeout

from selenium import webdriver

driver = webdriver.Chrome(executable_path='C:\\..\chromedriver.exe')
driver.set_page_load_timeout(0.1)              # 100 ms явно не хватит :)
driver.get("https://www.google.com/maps")

3. Специфичный способ через проверку в js (источник) проверяя значение в document.readyState.

Но это сгодится когда используется подзагрузка данных, например через ajax.

Думаю, будет примерно так:

from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome(executable_path='C:\\..\chromedriver.exe')
driver.get(...)

timeout = 5

# Выполнение действий, затрагивающих подзагрузку, которая поменяет структуру страницы
# Например, пролистывание страницы
# driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

try:
    WebDriverWait(driver, timeout).until(
        lambda driver: driver.execute_script('return document.readyState') == 'complete'
    )
except TimeoutException:
    print("Timed out waiting for page to load")
→ Ссылка