【问题标题】:Search both elements and attributes for string在元素和属性中搜索字符串
【发布时间】:2016-01-05 14:13:51
【问题描述】:

我正在尝试查询一些 HTML 以查找以某种方式包含“下载”一词的链接。所以它可以在

  1. id
  2. class
  3. href
  4. 正文
  5. a 标记内的任何 html。

所以使用Python lxml library 应该会在 test-html 中找到所有 7 个链接:

html = """
<html>
<head></head>
<body>
1 <a href="/test1" id="download">test 1</a>
2 <a href="/test2" class="download">test 2</a>
3 <a href="/download">test 3</a>
4 <a href="/test4">DoWnLoAd</a>
5 <a href="/test5">ascascDoWnLoAdsacsa</a>
6 <a href="/test6"><div id="test6">download</div></a>
7 <a href="/test7"><div id="download">test7</div></a>
</body>
</html>
"""

from lxml import etree

tree = etree.fromstring(html, etree.HTMLParser())
downloadElementConditions = "//a[(@id|@class|@href|text())[contains(translate(.,'DOWNLOAD','download'), 'download')]]"
elements = tree.xpath(downloadElementConditions)

print 'FOUND ELEMENTS:', len(elements)
for i in elements:
    print i.get('href'), i.text

但是,如果运行它,它只会找到前五个元素。这意味着如果文本不包含进一步的 html,xpath 只能在文本中找到“下载”。

有没有办法将a 标记的内容视为常规字符串并查看其中是否包含“下载”?欢迎所有提示!

[编辑]

使用下面 heinst 答案中的提示,我编辑了下面的代码。这现在有效,但它不是很优雅。有人知道纯 xpath 的解决方案吗?

from lxml import etree
tree = etree.fromstring(html, etree.HTMLParser())
downloadElementConditions = "//*[(@id|@class|@href|text())[contains(translate(.,'DOWNLOAD','download'), 'download')]]"
elements = tree.xpath(downloadElementConditions)

print 'FOUND ELEMENTS:', len(elements)
for el in elements:
    href = el.get('href')
    if href:
        print el.get('href'), el.text
    else:
        elparent = el
        for _ in range(10):  # loop over 10 parents
            elparent = elparent.getparent()
            href = elparent.get('href')
            if href:
                print elparent.get('href'), elparent.text
                break

【问题讨论】:

    标签: python html xml xpath lxml


    【解决方案1】:

    纯 XPath 解决方案

    text() 更改为. 并在descendent-or-self 轴上搜索属性:

    //a[(.|.//@id|.//@class|.//@href)[contains(translate(.,'DOWNLOAD','download'),'download')]]
    

    解释

    • text() vs .:这里text()将匹配a的直接文本节点子节点; . 将匹配 a 元素的字符串值。在 为了捕获有a 的子元素的情况 包含目标文本,您要匹配的字符串值 a
    • descendant-or-self:为了匹配 a 及其任何后代的属性,使用了 descendant-or-self 轴 (.//)。

    有关 XPath 中字符串值的更多详细信息,请参阅Matching text nodes is different than matching string values.

    【讨论】:

      【解决方案2】:

      将您的 Xpath 选择从严格匹配的 a 标记更改为通配符应该可以解决问题: "//*[(@id|@class|@href|text())[contains(translate(.,'DOWNLOAD','download'), 'download')]]"

      【讨论】:

      • 感谢您的建议,但是当使用通配符时,它会在 a 元素中找到 div,而不是在 a 元素本身。最后我需要a中的href,所以我真的需要找到a元素。还有其他想法吗?
      • 您可以在 for 循环中获取父节点并以这种方式获取 a 标签
      • 谢谢,这是一个很好的提示。我设法让它工作(请参阅我的问题中添加的代码),但它不是很优雅。有没有办法使用纯 xpath 做到这一点?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-29
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 2022-08-02
      • 1970-01-01
      相关资源
      最近更新 更多