Python Selenium - 提交表单后等到下一页加载
Posted
技术标签:
【中文标题】Python Selenium - 提交表单后等到下一页加载【英文标题】:Python Selenium - Wait until next page has loaded after form submit 【发布时间】:2017-06-23 11:54:33 【问题描述】:我正在使用 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
...
好点,操作已更新
【参考方案1】:
如果您想创建一个通用算法来确定任意网页是否已加载,您会感到失望,因为这是不可能的。检查 url 更改是不够的。问题是驱动程序无法知道最终将在任意网页上出现或可见的所有元素。某些元素可能需要很长时间才能加载(变为存在或可见)。
你可以自己看看:
-
首先手动提交表单并估计新网页完全加载需要多少秒。
运行您的程序并让驱动程序在提交表单后立即将其页面源写入 .html;
让您的程序在第 1 步确定的时间内休眠;
将驱动程序的页面源代码写入新的 .html。
当您比较两个 html 文件时,您会发现第二个文件中存在第一个文件中不存在的元素。
因此,您必须根据具体情况处理页面加载问题。要确定网页是否已加载,首先手动确定哪个元素最后出现或显示在页面上,然后硬编码检查该元素。
我在提交登录表单后让我的驱动程序从网页收集超链接时遇到了这个问题。我的程序会在崩溃之前通过超链接的一部分,因为当新元素突然出现或可见时页面源会发生变化。为了解决这个问题,我必须先硬编码检查该元素是否存在,然后再执行其他任何操作。
【讨论】:
【参考方案2】:来自expected_conditions
的url_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以上是关于Python Selenium - 提交表单后等到下一页加载的主要内容,如果未能解决你的问题,请参考以下文章