Skip to main content
 首页 » 编程设计

python之Selenium 的 XPath 问题

2025年05月04日13lovecherry

我想这是那些永恒的问题之一,但我需要一些有关 XPath 表达式的帮助。使用 Selenium 搜索的 HTML 如下所示:

<div class="container"> 
  <div class"row"> 
    <div class="col-md-6 col-md-offset-3 jumbotron"> 
      <div class="text-center"> 
        <h1>Start a new To-Do list</h1> 
        <form method="POST" action="/lists/new"> 
          <input name="item_text" id="id_new_item" 
            class="form-control input-lg" 
            placeholder="Enter a to-do item" /> 
          <input type="hidden" name="csrfmiddlewaretoken" value="***********"> 
          <div class="form-group has-error"> 
            <span class="help-block">You can&#39;t have an empty list item</span> 
          </div>     
        </form> 
      </div> 
    </div> 
  </div> 
</div> 

Python 中的搜索表达式如下所示:

self.wait_for(lambda: self.assertEqual( 
    self.browser.find_element_by_xpath( 
        "//span[contains(text(), 'You can&#39;t have an empty list item')]" 
        ) 
    ) 
) 

这是在测试中运行的,它无法找到文本,即使它显然存在。测试的 ttaceback 是:

ERROR: test_cannot_add_empty_list_items (functional_tests.test_list_item_validation.ItemValidationTest) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
  File "/home/eric/Git/TDD/functional_tests/test_list_item_validation.py", line 15, in test_cannot_add_empty_list_items 
    self.wait_for(lambda: self.assertEqual( 
  File "/home/eric/Git/TDD/functional_tests/base.py", line 40, in wait_for 
    raise e 
  File "/home/eric/Git/TDD/functional_tests/base.py", line 37, in wait_for 
    return fn() 
  File "/home/eric/Git/TDD/functional_tests/test_list_item_validation.py", line 17, in <lambda> 
    "//span[contains(text(), 'You can&#39;t have an empty list item')]" 
  File "/home/eric/Git/TDD/venv/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 394, in find_element_by_xpath 
    return self.find_element(by=By.XPATH, value=xpath) 
  File "/home/eric/Git/TDD/venv/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 978, in find_element 
    'value': value})['value'] 
  File "/home/eric/Git/TDD/venv/lib/python3.6/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute 
    self.error_handler.check_response(response) 
  File "/home/eric/Git/TDD/venv/lib/python3.6/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response 
    raise exception_class(message, screen, stacktrace) 
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: //span[contains(text(), 'You can&#39;t have an empty list item')] 
 
 
---------------------------------------------------------------------- 
Ran 4 tests in 34.851s 
 
FAILED (errors=1) 

编辑:断言应该是 assertTrue 而不是 assertEqual,因为我没有将结果与任何东西进行比较。

请您参考如下方法:

您的 HTML 文档中没有 '。有一个'。

' 只是通知 HTML 解析器在文档树的这个位置插入一个单引号,它实际上并没有作为您可以搜索的内容结束。

你可以这样做:

self.wait_for(lambda: self.assertEqual( 
    self.browser.find_element_by_xpath( 
        '//span[contains(text(), "You can\'t have an empty list item")]' 
        ) 
    ) 
) 

但这只有在引号完全按照这种方式时才有效。当您的搜索文本包含双引号时,上述内容就会中断,您必须以另一种方式转义。只要搜索文本是预定义的,这是可行的。

只要生成的 XPath 有效,您就可以开始了。在这种情况下,上面的结果是这个完全有效的 XPath 表达式:

//span[contains(text(), "You can't have an empty list item")] 

但如果搜索文本是可变的(例如用户定义的),那么事情就会变得棘手。 Python 知道字符串转义序列,您始终可以使用 \" 或 \' 将引号放入字符串中。XPath 不知道这样的事情。

假设搜索文本为 您不能有“空”列表项。这很容易用 Python 生成,但行不通:

//span[contains(text(), "You can't have an "empty" list item")] 
-------------------------------------------^ breaks here 

而且这个 XPath 也不起作用:

//span[contains(text(), 'You can't have an "empty" list item')] 
--------------------------------^ breaks here 

这个也不会,因为 XPath 没有转义序列:

//span[contains(text(), 'You can\'t have an "empty" list item')] 
---------------------------------^ breaks here 

在 XPath 中可以解决此问题的方法是连接不同引用的字符串。这:

//span[contains(text(), concat('You can', "'" ,'t have an "empty" list item'))] 

完全有效,将搜索文本 You can't have an "empty"list item。

在 Python 中你可以做的就是创建这个结构:

  1. 在'处拆分搜索字符串
  2. 用 ', "'", ' 加入部分
  3. 前置 concat(', append ')
  4. 插入到 XPath 表达式中

以下将允许字符串搜索永远不会因格式错误的 XPath 而引发运行时错误:

search_text = 'You can\'t have an "empty" list item' 
 
concat_expr = "', \"'\", '".join(search_text.split("'")) 
concat_expr = "concat('" + concat_expr + "')" 
 
xpath = "//span[contains(text(), %s)]" % concat_expr 

xpath,作为 Python 字符串文字(将其打印到控制台时会看到的内容):

'//span[contains(text(), concat(\'You can\', "\'", \'t have an "empty" list item\'))]' 

XPath 引擎查看它的方式(即内存中的实际字符串):

//span[contains(text(), concat('You can', "'", 't have an "empty" list item'))] 

lxml 库允许 XPath variables ,这比那要优雅得多,但我怀疑 Selenium 的 find_elements_by_xpath 是否支持它们。