如何使用 Selenium xpath 查找包含“下载”一词的所有元素?
Posted
技术标签:
【中文标题】如何使用 Selenium xpath 查找包含“下载”一词的所有元素?【英文标题】:How to find all elements containing the word "download" using Selenium x-path? 【发布时间】:2016-02-23 06:20:44 【问题描述】:我正在使用 Selenium 进行一些网页抓取,现在我想找到用户可以点击的所有元素,并且在链接文本、按钮文本、元素id
、元素class
或href
。这可以包括链接、按钮或任何其他元素。
在this answer 中,我找到了一个 xpath 供某人寻找 xpath 以根据特定文本(或不区分大小写和部分匹配)搜索按钮:
text = 'download'
driver.find_elements_by_xpath("(//*[contains(text(), 'download')]")
但是在this page 上没有返回任何结果,即使下面的链接在那里:
<a id="downloadTop" class="navlink" href="javascript:__doPostBack('downloadTop','')">Download</a>
有人知道我如何在网站中找到所有包含“下载”一词的元素吗?
[编辑]
此问题被标记为与获得an answer 的问题重复,建议将其更改为"//*[text()[contains(.,'download')]]"
。所以我尝试了以下方法:
>>> from selenium import webdriver
>>> d = webdriver.Firefox()
>>> link = 'https://www.yourticketprovider.nl/LiveContent/tickets.aspx?x=492449&y=8687&px=92AD8EAA22C9223FBCA3102EE0AE2899510C03E398A8A08A222AFDACEBFF8BA95D656F01FB04A1437669EC46E93AB5776A33951830BBA97DD94DB1729BF42D76&rand=a17cafc7-26fe-42d9-a61a-894b43a28046&utm_source=PurchaseSuccess&utm_medium=Email&utm_campaign=SystemMails'
>>> d.get(link)
>>> d.find_elements_by_xpath("//*[text()[contains(.,'download')]]")
[] # As you can see it still doesn't get any results..
>>>
有谁知道我如何获取用户可以点击的所有元素,并且在链接文本、按钮文本、元素id
、元素class
或@ 中包含“下载”一词987654333@?欢迎所有提示!
【问题讨论】:
【参考方案1】:试试这个:
//*[(@id|@class|@href|text())
[contains(translate(.,'DOWNLOAD','download'), 'download')]]
此 Xpath 1.0 表达式选择:所有具有 id
或 class
或 href
属性或文本节点子节点的元素,其字符串值包含字符串 "download: in any大写。
这是一个运行证明。下面的 XSLT 转换用于评估 XPath 表达式并将所有选定的节点复制到输出:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select=
"//*[(@id|@class|@href|text())
[contains(translate(.,'DOWNLOAD','download'), 'download')]]
"/>
</xsl:template>
</xsl:stylesheet>
当我们将转换应用于以下测试文档时:
<html>
<a id="downloadTop" class="navlink"
href="javascript:__doPostBack('downloadTop','')">Download</a>
<b id="y" class="x_downLoad"/>
<p>Nothing to do_wnLoad</p>
<a class="m" href="www.DownLoad.com">Get it!</a>
<b>dOwnlOad</b>
</html>
选择想要的元素,然后复制到输出:
<a id="downloadTop" class="navlink" href="javascript:__doPostBack('downloadTop','')">Download</a>
<b id="y" class="x_downLoad"/>
<a class="m" href="www.DownLoad.com">Get it!</a>
<b>dOwnlOad</b>
【讨论】:
【参考方案2】:因为您需要不区分大小写的匹配项和XPath 1.0 does not support it - you'll have to use translate()
function。另外,由于您需要通配符匹配 - 您需要使用 contains()
。而且,由于您还想检查id
、class
和href
属性以及文本:
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://www.yourticketprovider.nl/LiveContent/tickets.aspx?x=492449&y=8687&px=92AD8EAA22C9223FBCA3102EE0AE2899510C03E398A8A08A222AFDACEBFF8BA95D656F01FB04A1437669EC46E93AB5776A33951830BBA97DD94DB1729BF42D76&rand=a17cafc7-26fe-42d9-a61a-894b43a28046&utm_source=PurchaseSuccess&utm_medium=Email&utm_campaign=SystemMails")
condition = "contains(translate(%s, 'DOWNLOAD', 'download'), 'download')"
things_to_check = ["text()", "@class", "@id", "@href"]
conditions = " or ".join(condition % thing for thing in things_to_check)
for elm in driver.find_elements_by_xpath("//*[%s]" % conditions):
print(elm.text)
这里我们基本上是通过字符串格式化和连接来构造表达式,对text()
、class
、id
和href
属性进行不区分大小写的检查,并将条件与or
连接起来。
【讨论】:
请注意,@Dimitre's answer 在这种情况下使动态 XPath 构造完全没有必要(您可能应该接受他的回答是最简单直接的)。【参考方案3】:嗯,你找到的答案已经告诉你如何做你想做的事。我看到的问题是text = 'download'
以小写开头,而<a id="downloadTop" class="navlink" href="javascript:__doPostBack('downloadTop','')">Download</a>
中的文本以大写开头。
首先将您的文本更改为text = 'Download'
,然后看看它现在是否找到了您的元素。如果这是问题所在,那么您可以使用像
text = 'ownload'
driver.find_elements_by_xpath("(//*[contains(text(), '" + text + "')] | //*[@value='" + text + "'])")
忽略第一个字符。
编辑:是的,你可以让它不区分大小写。
driver.find_elements_by_xpath("(//*[contains(translate(text(), 'DOWNLOAD', 'download'), 'download')])")
【讨论】:
问题是我想定义它不区分大小写。包含 id="DOWNLOAD" 或 id="dOwNLoAd" 并且还包含通配符的元素也一样,例如 id="downloadthisstuff" 或 id="yourdownloadishere"。有什么想法可以做到吗?【参考方案4】:您可以使用下面的翻译功能,它对任何单词都不区分大小写:
driver.find_elements_by_xpath("//*[translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = 'download']")
>>> driver.find_elements_by_xpath("//*[translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = 'download']")
[<selenium.webdriver.remote.webelement.WebElement (session="0b07fcba-86ee-3945-a0ae-85619e97ca31", element="4278753b-8b59-bf45-ae3b-f60f40aed071")>, <selenium.webdriver.remote.webelement.WebElement (session="0b07fcba-86ee-3945-a0ae-85619e97ca31", element="8aed425c-063e-7846-915d-d8948219cc12")>]
【讨论】:
【参考方案5】:如果您仍然想要更多地概括 xpath
并且不想使用 translate
函数,您可以使用 itertools.product
并将字符串 download
的所有变体生成为 @ 987654325@文本属性如下。
from itertools import product
from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://www.yourticketprovider.nl/LiveContent/tickets.aspx?x=492449&y=8687&px=92AD8EAA22C9223FBCA3102EE0AE2899510C03E398A8A08A222AFDACEBFF8BA95D656F01FB04A1437669EC46E93AB5776A33951830BBA97DD94DB1729BF42D76&rand=a17cafc7-26fe-42d9-a61a-894b43a28046&utm_source=PurchaseSuccess&utm_medium=Email&utm_campaign=SystemMails")
txt = 'Download' # text to be searched
#Generate variants of that txt
l = [(c, c.lower()) if not c.isdigit() else (c,) for c in txt.upper()] #make tuple of upper and lower of each lettern that string (Download)
variants = ["".join(item) for item in product(*l)] # make all variant of the string Download
anchors = ["text()", "@class", "@id", "@href"] #node attribute to be searched
#Generate xpaths
xpaths_or = " or ".join(["contains(%s,'%s')"%(i,j) for i in anchors for j in variants])
xpaths = "//*[%s]" %xpaths_or
for download_tag in driver.find_elements_by_xpath(xpaths):
print(download_tag.text)
driver.quit()
输出-
Download
Download
注意isdigit
函数可避免更改数字的大小写(如果存在)。
【讨论】:
【参考方案6】:但是在这个没有返回结果的页面上,即使下面的链接在那里:
这是因为有不同的文字。看:
Download
download
一个字母是大写的。 因此,您需要为此使用不区分大小写的 xpath:
driver.find_elements_by_xpath("(//*[contains(lower-case(text()), 'download')]")
它必须对你足够好
【讨论】:
【参考方案7】:好吧,我不太了解硒,但我可以提出一个可行的解决方案。您可以使用正则表达式首先解析整个页面源。例如,如果您只需要具有属性的元素,包含“下载”子字符串,请使用此正则表达式:
<\w*([a-zA-Z]+).*\w+([a-zA-Z]+)="(.*?download.*?)"?\/?>
然后使用 re.finditer 函数查找所有数学,每个匹配对象将包含标签名称(组(1)),属性名称(组(2)和属性值(组(3))
import re
# wd == webdriver
for m in re.finditer('<\w*([a-zA-Z]+).*\w+([a-zA-Z]+)="(.*?download.*?)"?\/?>', wd.page_source):
tag, attr, val = m.group(1), m.group(2), m.group(3)
然后,您可以使用 wd.find_elements_by_css_selector (或其他)查找硒树结构中的所有标签:
wd.find_elements_by_css_selector('0[1=2]'.format(tag, attr, val))
【讨论】:
Aaargh ... 是的,你不能解析html并制作树形结构,因为它不是常规语言。您甚至无法使用正则表达式找到任意数量的左括号和右括号。但是这种情况下我不想找到结束标签,我只想按顺序找到所有开始标签,用正则表达式完全可行。 只要这些标签都没有出现在其他文本中是可行的,例如在 JavaScript 中。【参考方案8】:在使用 Selenium 并查找 Web 元素时,最好始终先搜索“ID”或“类名”,因为它比使用 XPath 更可靠、更容易,通常只有在使用前 2 个找不到元素时才使用 XPath提到的方法。
在这种情况下,您在该网站的下载元素中有一个非常清晰的 ID 标签。
尝试改用这个:
downloadButton = driver.find_element_by_id('downloadTop')
然后你可以用它来点击它:
downloadButton.click()
【讨论】:
问题是这次是“downloadTop”。然而,由于我正在构建一个刮板,我希望它更通用。所以我希望所有包含“下载”一词的元素不区分大小写。包含id="DOWNLOAD"
或id="dOwNLoAd"
并且还包含通配符(例如id="downloadthisstuff"
或id="yourdownloadishere"
)的元素也是如此。有什么想法可以做到吗?以上是关于如何使用 Selenium xpath 查找包含“下载”一词的所有元素?的主要内容,如果未能解决你的问题,请参考以下文章
按文本查找元素并获取xpath - selenium webdriver junit
如何使用 Xpath、css 或 Selenium 中的任何其他定位器在 html 中的结束标记后查找带有“== $0”的元素