等待页面加载Selenium WebDriver for Python

2024-05-20 23:18:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我想刮掉一个无限卷轴实现的页面的所有数据。下面的python代码可以工作。

for i in range(100):
    driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
    time.sleep(5)

这意味着每当我向下滚动到底部时,我需要等待5秒,这通常足以让页面完成加载新生成的内容。但是,这可能没有时间效率。页面可以在5秒内完成新内容的加载。如何检测每次向下滚动时页面是否已完成加载新内容?如果我能检测到这一点,我可以再次向下滚动查看更多的内容,一旦我知道页面完成加载。这样更省时。


Tags: 数据代码in内容forexecutedriverscript
3条回答

默认情况下,webdriver将通过.get()方法等待加载页面。

正如@user227215所说,您可能正在寻找某些特定元素,因此应该使用WebDriverWait来等待位于页面中的元素:

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.common.exceptions import TimeoutException

browser = webdriver.Firefox()
browser.get("url")
delay = 3 # seconds
try:
    myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'IdOfMyElement')))
    print "Page is ready!"
except TimeoutException:
    print "Loading took too much time!"

我用它来检查警报。您可以使用任何其他类型方法来查找定位器。

编辑1:

我应该提到,webdriver将在默认情况下等待页面加载。它不会等待帧内加载或ajax请求。这意味着当您使用.get('url')时,浏览器将等待页面完全加载,然后转到代码中的下一个命令。但是,当您发布ajax请求时,webdriver不会等待,您有责任等待适当的时间来加载页面或页面的一部分;因此有一个名为expected_conditions的模块。

找到以下3种方法:

就绪状态

正在检查页的readyState(不可靠):

def page_has_loaded(self):
    self.log.info("Checking if {} page is loaded.".format(self.driver.current_url))
    page_state = self.driver.execute_script('return document.readyState;')
    return page_state == 'complete'

The wait_for helper function is good, but unfortunately click_through_to_new_page is open to the race condition where we manage to execute the script in the old page, before the browser has started processing the click, and page_has_loaded just returns true straight away.

id

将新页ID与旧页ID进行比较:

def page_has_loaded_id(self):
    self.log.info("Checking if {} page is loaded.".format(self.driver.current_url))
    try:
        new_page = browser.find_element_by_tag_name('html')
        return new_page.id != old_page.id
    except NoSuchElementException:
        return False

It's possible that comparing ids is not as effective as waiting for stale reference exceptions.

staleness_of

使用staleness_of方法:

@contextlib.contextmanager
def wait_for_page_load(self, timeout=10):
    self.log.debug("Waiting for page to load at {}.".format(self.driver.current_url))
    old_page = self.find_element_by_tag_name('html')
    yield
    WebDriverWait(self, timeout).until(staleness_of(old_page))

有关详细信息,请检查Harry's blog

试图将find_element_by_id传递给presence_of_element_located的构造函数(如accepted answer所示)导致NoSuchElementException被引发。我不得不使用fragles'comment中的语法:

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.Firefox()
driver.get('url')
timeout = 5
try:
    element_present = EC.presence_of_element_located((By.ID, 'element_id'))
    WebDriverWait(driver, timeout).until(element_present)
except TimeoutException:
    print "Timed out waiting for page to load"

这与example in the documentation匹配。这是指向documentation for By的链接。

相关问题 更多 >