【问题标题】:Selenium: Wait until text in WebElement changesSelenium:等到 WebElement 中的文本发生变化
【发布时间】:2015-06-21 13:16:09
【问题描述】:

我在 Python 2.7 中使用 selenium。从网页上的搜索框中检索内容。搜索框会动态检索并在框中显示结果。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import pandas as pd
import re
from time import sleep

driver = webdriver.Firefox()
driver.get(url)

df = pd.read_csv("read.csv")

def crawl(isin):
    searchkey = driver.find_element_by_name("searchkey")
    searchkey.clear()
    searchkey.send_keys(isin)
    sleep(11)

    search_result = driver.find_element_by_class_name("ac_results")
    names = re.match(r"^.*(?=(\())", search_result.text).group().encode("utf-8")
    product_id = re.findall(r"((?<=\()[0-9]*)", search_result.text)
    return pd.Series([product_id, names])

df[["insref", "name"]] = df["ISIN"].apply(crawl)

print df

相关部分代码可以在def crawl(isin):下找到

  • 程序在搜索框中输入要搜索的内容(该框被错误地命名为searchkey)。
  • 然后它执行sleep() 并等待内容显示在搜索框下拉字段ac_results 中。
  • 然后使用 Regex 获取两个变量 insrefsnames

我希望它等待 WebElement ac_results 中的内容加载,而不是调用 sleep()

由于它会不断地使用搜索框通过从列表中输入新的搜索词来获取新数据,因此可以使用 Regex 来识别ac_results 中何时有与先前内容不同的新内容。

有办法吗?需要注意的是,搜索框中的内容是动态加载的,因此该函数必须识别出 WebElement 中的某些内容发生了变化。

【问题讨论】:

    标签: python selenium selenium-webdriver


    【解决方案1】:

    您需要应用Explicit Wait 概念。例如。 等待一个元素变得可见

    wait = WebDriverWait(driver, 10)
    wait.until(EC.visibility_of_element_located((By.CLASS_NAME, 'searchbox')))
    

    在这里,它会等待 10 秒,每 500 毫秒检查一次元素的可见性。

    有一组内置的预期条件等待,写你的custom Expected Condition也很容易。


    仅供参考,这是我们在聊天中集思广益后的处理方式。我们引入了一个自定义的预期条件,该条件将等待元素文本更改。它帮助我们确定何时出现新的搜索结果:

    import re
    
    import pandas as pd
    from selenium import webdriver
    from selenium.common.exceptions import NoSuchElementException
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support.expected_conditions import _find_element
    
    class text_to_change(object):
        def __init__(self, locator, text):
            self.locator = locator
            self.text = text
    
        def __call__(self, driver):
            actual_text = _find_element(driver, self.locator).text
            return actual_text != self.text
    
    #Load URL
    driver = webdriver.Firefox()
    driver.get(url)
    
    #Load DataFrame of terms to search for
    df = pd.read_csv("searchkey.csv")
    
    #Crawling function    
    def crawl(searchkey):
        try: 
            text_before = driver.find_element_by_class_name("ac_results").text 
        except NoSuchElementException: 
            text_before = ""
    
        searchbox = driver.find_element_by_name("searchbox")
        searchbox.clear()
        searchbox.send_keys(searchkey)
        print "\nSearching for %s ..." % searchkey
    
        WebDriverWait(driver, 10).until(
            text_to_change((By.CLASS_NAME, "ac_results"), text_before)
        )
    
        search_result = driver.find_element_by_class_name("ac_results")
        if search_result.text != "none":
            names = re.match(r"^.*(?=(\())", search_result.text).group().encode("utf-8")
            insrefs = re.findall(r"((?<=\()[0-9]*)", search_result.text)
        if search_result.text == "none":
            names = re.match(r"^.*(?=(\())", search_result.text)
            insrefs = re.findall(r"((?<=\()[0-9]*)", search_result.text)
        return pd.Series([insrefs, names])
    
    #Run crawl    
    df[["Insref", "Name"]] = df["ISIN"].apply(crawl)
    
    #Print DataFrame    
    print df
    

    【讨论】:

    • 这并不是那么容易,因为searchbox 元素会在打开页面时立即加载。当我在元素中输入searchkey 时,最多需要 8-9 秒才能加载元素中的文本内容。正是我想等待的内容。
    • @Winterflags 是的,我刚刚提供了一个示例和提示:) 如果您知道要等待哪个文本,text_to_be_present_in_element 可能是您的理想选择。如果没有,那么您将需要一个自定义的预期条件。
    • 非常感谢,我遵循了您对正则表达式的自定义预期条件,如下所示:stackoverflow.com/questions/28240342/…。我设法让它等待与模式匹配的第一个回复,但是一旦它出现该模式,它就会继续运行循环搜索所有搜索键,但没有给它时间来召唤它们。您对如何让它等待匹配相同模式但不同的新内容有什么想法吗?
    • 模式如下所示:"Name ABC123 (01234)""Something 123DEF (432134)""Somethingsomething 123 GHI (07451)"。不变的是,末尾有括号内的文本后跟一系列可变长度的数字。
    • 感谢 alecxe in chat 解决了这个问题!超级有帮助。上面的自定义预期条件将证明对等待动态文本内容出现在 WebElement 中的 Selenium 用户很有用。
    【解决方案2】:

    我建议在 WebDriverWait 中使用以下预期条件。

    WebDriverWait(driver, 10).until(
        text_to_be_present_in_element((By.CLASS_NAME, "searchbox"), r"((?<=\()[0-9]*)")
    )
    

    WebDriverWait(driver, 10).until(
        text_to_be_present_in_element_value((By.CLASS_NAME, "searchbox"), r"((?<=\()[0-9]*)")
    )
    

    【讨论】:

    • 如果我没记错的话,那确实会等待搜索框中的第一个文本回复被加载。但是如果程序随后插入一个新的搜索词,它会从第一个结果中识别模式,而不是等待第二个结果加载。请参阅我在 OP 中“代码现在做什么”下的说明。
    • WebDriverWait,我们使用的是显式等待的示例,这意味着我们需要在每个元素查找之前设置等待。这就是为什么我们在 start 中使用隐式等待,它将为每个元素查找设置等待。
    • 我相信最好是在这里使用sleep或者写一个函数等待JQuery调用完成。
    【解决方案3】:

    为等待条件创建类

    class SubmitChanged(object):
        def __init__(self, element):
            self.element = element
    
        def __call__(self, driver):
            # here we check if this is new instance of element
            new_element = driver.find_element_by_xpath('<your xpath>')
            return new_element != self.element
    

    在你的程序中调用它

         wait = WebDriverWait(<driver object>, 3)
         wait.until(SubmitChanged(<web element>))
    

    更多信息https://selenium-python.readthedocs.io/waits.html

    【讨论】:

      猜你喜欢
      • 2021-05-30
      • 1970-01-01
      • 2021-09-18
      • 1970-01-01
      • 1970-01-01
      • 2020-11-18
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      相关资源
      最近更新 更多