如果在Python Selenium上找不到备用元素,是否有更有效的方法来设置备用元素?

时间:2017-04-14 20:39:08

标签: python performance selenium

我有一些python 2.7脚本使用selenium从网站上抓取数据。我想要备份'元素,所以如果找不到第一个元素,它将转到下一个并尝试那个元素。这样一来,如果网站上的一件事情发生了变化,它就不会弄乱我的整个剧本。以下是我现在使用的内容,但是我有很多元素,想要知道是否有更高效,更短的方法来做到这一点而不会引发异常。

locators = [
    (By.NAME, "email"),
    (By.CSS_SELECTOR, "[name='email']"),
    (By.XPATH, '//*body/div/div[2]/div/'),
    (By.TAG_NAME, 'label')
    ]
for by, value in locators:
    try:
        elem = driver.find_element(by, value)
        break
    except NoSuchElementException:
        pass      
elem.send_keys('emailaddress@email.com')

1 个答案:

答案 0 :(得分:1)

这是一个值得思考的问题,需要进行性能测量以了解不同方法的速度。

将定位器组合成单个表达式

如您所知,每次find_element()次调用都会导致通过"FIND_ELEMENT"发送的Json Wire protocol selenium HTTP命令。这会带来很多开销,特别是如果你需要连续进行,直到找到所需的元素。

为了减少HTTP请求/响应的数量,我们可以将所有定位器组合成一个XPath表达式,如:

expression = "(//*[@name = 'email']|//*body/div/div[2]/div/|//label)"
elem = driver.find_element_by_xpath(expression)

当然,对于初学者来说,严重会降低可读性(但是,您可能会想出一个辅助函数,它会从不同定位器的列表中生成单个表达式)。并且,涉及多个DOM“扫描”会使表达速度变慢 - 尽管如此,我希望这比当前的方法更快,尤其是locators的数量越来越多。

使用HTML解析器

您也可以将“页面来源”(driver.page_source)传递给 HTML解析器,例如BeautifulSouplxml,以确定哪个定位器对你的元素有效。

您可能还会想到其他一些优化:

  • 而不是在find_element*()实例上调用driver,您可以在父容器元素上调用它,您希望找到所需的元素 - 这可以是body元素,或者它可以是带有div的{​​{1}}元素,具体取决于您的目标网站布局
  • 跟进@ TemporalWolf在评论中表达的想法:您可以跟踪每个定位器调整优先级的频率以及下次运行期间尝试它们的顺序。例如,它可以是带有(LOCATOR_TYPE,LOCATOR_VALUE,SCORE)表的SQLite数据库。
  • 你可以启动多个浏览器并行尝试多个定位器,看看哪一个成功 - 这更棘手,更复杂,但是,根据性能的重要程度和定位器的数量有多大,这可能是一个可行的选择
  • 使用最新的class="container"软件包和浏览器版本

请注意,您可能会在不同的浏览器中获得不同的效果结果 - 实验和衡量。