【问题标题】:Python Selenium - Wait until next page has loaded after form submitPython Selenium - 提交表单后等到下一页加载
【发布时间】:2025-12-28 00:05:11
【问题描述】:

我正在使用 Python3 和 Selenium firefox 提交表单,然后获取他们随后登陆的 URL。我就是这样做的

inputElement.send_keys(postnumber)
inputElement.submit()

time.sleep(5)

# Get Current URL
current_url = driver.current_url
print ( " URL : %s" % current_url )

这在大多数情况下都有效,但有时页面加载时间超过 5 秒,我得到旧 URL,因为新 URL 尚未加载。

我应该怎么做?

【问题讨论】:

  • current_url = driver.current_url 不会出错...这只会返回当前页面或新页面URL...
  • 好点,操作已更新

标签: python selenium selenium-webdriver


【解决方案1】:

如果您想创建一个通用算法来确定任意网页是否已加载,您会感到失望,因为这是不可能的。检查 url 更改是不够的。问题是驱动程序无法知道最终将在任意网页上出现或可见的所有元素。某些元素可能需要很长时间才能加载(变为存在或可见)。

你可以自己看看:

  1. 首先手动提交表单并估计新网页完全加载需要多少秒。
  2. 运行您的程序并让驱动程序在提交表单后立即将其页面源写入 .html;
  3. 让您的程序在第 1 步确定的时间内休眠;
  4. 将驱动程序的页面源代码写入新的 .html。

当您比较两个 html 文件时,您会发现第二个文件中存在第一个文件中不存在的元素。

因此,您必须根据具体情况处理页面加载问题。要确定网页是否已加载,首先手动确定哪个元素最后出现或显示在页面上,然后硬编码检查该元素。

我在提交登录表单后让我的驱动程序从网页收集超链接时遇到了这个问题。我的程序会在崩溃之前通过超链接的一部分,因为当新元素突然出现或可见时页面源会发生变化。为了解决这个问题,我必须先硬编码检查该元素是否存在,然后再执行其他任何操作。

【讨论】:

    【解决方案2】:

    来自expected_conditionsurl_changes 助手正是为此目的:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    # some work on current page, code omitted
    
    # save current page url
    current_url = driver.current_url
    
    # initiate page transition, e.g.:
    input_element.send_keys(post_number)
    input_element.submit()
    
    # wait for URL to change with 15 seconds timeout
    WebDriverWait(driver, 15).until(EC.url_changes(current_url))
    
    # print new URL
    new_url = driver.current_url
    print(new_url)
    

    【讨论】:

    • 大部分时间都在工作,但重定向到登录页面时无效。
    • 如果目标页面的URL与当前页面的URL相同也无效。
    【解决方案3】:

    方法一

    driver.find_element_by__link_text('Next').click()
    

    点击链接后,按钮跳转到新页面,您可以:

    等到一些不在旧页面中而是在新页面中的元素出现;

    WebDriverWait(driver, 600).until(expected_conditions.presence_of_element_located((By.XPATH, '//div[@id="main_message"]//table')))
    # or just wait for a second for browser(driver) to change
    driver.implicitly_wait(1)
    

    当新页面正在加载(或加载)时,现在您可以通过执行javascript脚本检查其readyState,该脚本将在页面加载时输出“完成”消息(值)。

    def wait_loading():
        wait_time = 0
        while driver.execute_script('return document.readyState;') != 'complete' and wait_time < 10:
            # Scroll down to bottom to load contents, unnecessary for everyone
            driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
            wait_time += 0.1
            time.sleep(0.1)
        print('Load Complete.')
    

    这个想法在我的情况下是为我写的,我认为它可以适用于大多数情况,而且很简单。

    方法2

    从 selenium.common.exceptions 导入 StaleElementReferenceException

    def wait_for(condition_function):
        start_time = time.time()
        while time.time() < start_time + 10:
            if condition_function:
                return True
            else:
                time.sleep(0.1)
        raise Exception(
            'Time out, waiting for {}'.format(condition_function.__name__)
        )
    def click_xpath(xpath):
        link = driver.find_element_by_xpath(xpath)
        link.click()
    
        def link_staled():
            try:
                link.find_element_by_id('seccode_cSA')
                return  False
            except StaleElementReferenceException:
                return True
    
        wait_for(link_staled())
    
    click_xpath('//button[@name="loginsubmit"]')
    

    这个方法来自'https://blog.codeship.com/get-selenium-to-wait-for-page-load/'(可能从其他地方共享)

    【讨论】:

      【解决方案4】:

      尝试以下方法:

      from selenium.webdriver.common.by import By
      from selenium.webdriver.support.ui import WebDriverWait as wait
      from selenium.webdriver.support import expected_conditions as EC
      
      title = driver.title
      inputElement.send_keys(postnumber)
      inputElement.submit()
      wait(driver, 15).until_not(EC.title_is(title))
      current_url = driver.current_url
      print ( " URL : %s" % current_url )
      

      这将允许您在表单提交后等待最多 15 秒直到页面标题更改(如果新旧页面上的标题不同)以获取新的URL。如果要处理新页面上的元素,则可能需要使用以下代码:

      inputElement.send_keys(postnumber)
      inputElement.submit()
      text_of_element_on_new_page = wait(driver, 15).until(EC.presence_of_element_located((By.ID, "some_element_id"))).text
      
      print ( " Text of element is : %s" % text_of_element_on_new_page )
      

      【讨论】:

      • 您应该指出,此解决方案仅适用于新页面的标题与当前页面不同的情况。我曾在几个并非如此的系统上工作过。
      • 哇,这是一个超级简单的解决方案——它可以用于任何expected_conditions ,所以在我的例子中,我用它来检查新的 URL:WebDriverWait(driver, 15).until(expected_conditions.url_changes('http://demo.com/newUrl'))。作为一种魅力:)
      【解决方案5】:

      在我的代码中,我创建了一个执行以下操作的上下文管理器:

      • 获取对“html”元素的引用
      • 提交表格
      • 等到对 html 元素的引用失效(这意味着页面已开始重新加载)
      • 等待document.readyState“完成”(这意味着页面已完成初始加载)

      如果页面的内容填充了额外的 ajax 调用,我可能会在此之后添加另一个等待,以等待我知道在上述四个步骤之后不会立即出现的元素。

      有关详细说明,请参阅此博客文章:How to get Selenium to wait for page load after a click

      【讨论】:

      • 在代码方面,第一步是old_page = driver.find_element_by_tag_name('html'),第三步是WebDriverWait(driver, timeout).until(staleness_of(old_page))。对于第 4 步,请参阅*.com/a/15124562/5267751
      最近更新 更多