【问题标题】:Get xpath to tag which contains certain text获取包含特定文本的标记的 xpath
【发布时间】:2019-07-31 18:53:13
【问题描述】:

我正在尝试查找网页上某些文本的 xpath。如果您要去https://www.york.ac.uk/teaching/cws/wws/webpage1.html 并尝试获取“EXERCISE”的xpath,它看起来像“html body html table tbody tr td div h4”。如果您进入该页面,右键单击“EXERCISE”并检查它,您可以在代码底部看到路径(在 chrome 中)。

我尝试了很多方法。这些都没有得到预期的结果。这是我得到的最接近的:

soup = BS(page, 'html.parser')
tags = [{"name":tag.name,"text":tag.text,"attributes":tag.attributes} for tag in soup.find_all()]
s = ''
for t in tags:
    if "EXERCISE" in t['text']:
        s = s + t['name'] + " "
print(s)

一开始我需要获取“html body html table tbody tr td div h4”,但最终对于更复杂的页面,我还需要获取标签属性

谢谢!

【问题讨论】:

  • 您没有使用 xpath 来定位元素。这是故意的吗?
  • 没错,我正在使用确切的文本来定位元素,并希望返回它的路径。
  • 你标记了 BeautifulSoup - 你想要 xpath 吗?它可以通过多种方式完成......也可以使用 CSS 选择器
  • 我真的很乐意使用任何方式。我只需要找出可以返回给soup.select() 的路径,这样它就可以再次返回文本。我标记 xpath 的原因是因为我在一次尝试中使用了它
  • 可以使用lxml吗?

标签: python xpath beautifulsoup


【解决方案1】:

使用 lxml:

url = 'https://www.york.ac.uk/teaching/cws/wws/webpage1.html'

import requests
from lxml import etree
parser = etree.HTMLParser()
page  = requests.get(url,headers={"User-Agent":"Mozilla/5.0"})

root = etree.fromstring(page.content,parser)

tree = etree.ElementTree(root)
e = root.xpath('.//*[text()="EXERCISE"]')
print(tree.getpath(e[0]))

输出:

/html/body/hmtl/table/tr/td/div[2]/h4

【讨论】:

  • 这很有帮助。我最终使用了它,拆分输出,然后循环遍历每个执行 soup.select() 并获取属性。不错的一个
【解决方案2】:

CSS 选择器:contains(EXERCISE):not(:has(:contains(EXERCISE))) 将选择包含字符串“EXERCISE”的最内层标签。

然后我们使用方法find_parents() 找到这个标签的所有父母并打印他们的名字:

import requests
from bs4 import BeautifulSoup

url = 'https://www.york.ac.uk/teaching/cws/wws/webpage1.html'

soup = BeautifulSoup(requests.get(url).text, 'html.parser')

t = soup.select_one(':contains(EXERCISE):not(:has(:contains(EXERCISE)))')
# you can use also this:
# t = soup.find(text="EXERCISE").find_parent()    

#lets print the path
tag_names = [t.name, *[t.name for t in t.find_parents()]]
print(' > '.join(tag_names[::-1]))

打印:

[document] > hmtl > body > table > tr > td > div > p > p > p > p > h4

【讨论】:

    【解决方案3】:

    如果你知道你想要的标签总是有“EXERCISE”的确切文本(没有引号,或者后面的不同情况,空格等),那么你可以在上面使用.find确切的文字。尽管您也可以使用正则表达式来代替,以防您确实想检查空格变化等等。

    从那里,您可以利用.parents 获取对象祖先的列表,即包含它的元素、包含该元素的元素等等,直到文档的顶部。然后只需提取标签名称,反转列表,然后将所有内容连接在一起。

    thetag = soup.find(string="EXERCISE")
    parent_tags = [ p.name for p in list(thetag.parents) ]
    print('/'.join(parent_tags[::-1]))
    

    输出:

    [文档]/html/body/hmtl/table/tr/td/div/h4

    如果您不想在开头显示“[document]”,您可以通过多种方式将其取出,例如使用这些行而不是最后两行:

    parent_tags = [ p.name for p in list(thetag.parents)[:-1] ]
    print('/' + '/'.join(parent_tags[::-1]))
    

    输出:

    /html/body/hmtl/table/tr/td/div/h4

    【讨论】:

    • 谢谢你,这很有意义,而且似乎非常有效。问题是输出是[document]/hmtl/body/table/tr/td/div/p/p/p/p/h4,所以里面有p。它们在 h4 之前打开和关闭,所以如果有意义的话,h4 实际上并不在其中?
    猜你喜欢
    • 2013-06-12
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    • 2017-01-24
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多