Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 获取具有任意嵌套度的html元素的内容(以及内容的xpath)_Python_Html_Parsing_Xpath_Beautifulsoup - Fatal编程技术网

Python 获取具有任意嵌套度的html元素的内容(以及内容的xpath)

Python 获取具有任意嵌套度的html元素的内容(以及内容的xpath),python,html,parsing,xpath,beautifulsoup,Python,Html,Parsing,Xpath,Beautifulsoup,我正在寻找一种方法来读取任意嵌套程度的HTML元素的文本内容(即没有HTML代码) 如果没有嵌套,那就很容易了,但由于HTML不是一种常规语言 可以用漂亮的汤来做这个吗?比如: page = soup.find('*').getText() # obviously this won't give xpath info ('text of div 1', '/div'), ('text of span 1', '/div/span'), ('text of span 2', '/div/spa

我正在寻找一种方法来读取任意嵌套程度的HTML元素的文本内容(即没有HTML代码)

如果没有嵌套,那就很容易了,但由于HTML不是一种常规语言

可以用漂亮的汤来做这个吗?比如:

page = soup.find('*').getText()  # obviously this won't give xpath info
('text of div 1', '/div'), ('text of span 1', '/div/span'), ('text of span 2', '/div/span/span')
我可以想象使用生成器将不同的标记名输入到
find
函数中,但我不知道标记名是什么。我还需要返回一些类似于xpath的内容引用,以便我知道最终从
find
函数返回的内容的来源

因此,对于以下HTML:

<div>
  text of div 1
  <span>
     text of span 1
     <span>
       text of span 2
     </span>
  </span>
</div>
那么这个呢:

result_set = []

for tag in soup.find_all():
    parent_list = []
    content_of_tag = tag.find(text=True)

    parent_list.append(tag.name)

    while tag.parent is not None:
        tag = tag.parent
        parent_list.append(tag.name)

    result_set.append((content_of_tag, parent_list))

第一个
find_all()
将查找所有级别上所有类型的所有标记。迭代这些
tag.find(text=True)
查找每个标记中的第一个文本
parent\u list.append(tag.name)
在循环将当前标记名称添加到父列表之前。然后,while循环查找所有标记的父项,并将它们的名称添加到父项列表中。

我编写了一个递归函数,该函数将返回字典中标记中所有文本的XPath,格式如下:

{'xpath1': {'text': 'text1'}, 'xpath2': {'text': 'text2'}, ...}
代码:

我知道这不是您期望的输出格式。但是,您可以将其转换为您想要的任何格式。例如,要将其转换为预期输出,只需执行以下操作:

expected_output = [(v['text'], k) for k, v in xpaths.items()]
print(expected_output)
输出:

{'/div': {'text': 'text of div 1', 'count': 1}, '/div/span': {'text': 'text of span 1.1', 'count': 1}, '/div/span/span': {'text': 'text of span 2.1', 'count': 2}, '/div/span/span[2]': {'text': 'text of span 2.2'}, '/div/span/span[2]/span': {'text': 'text of span 3', 'count': 1}}
[('text of div 1', '/div'), ('text of span 1.1', '/div/span'), ('text of span 2.1', '/div/span/span'), ('text of span 2.2', '/div/span/span[2]'), ('text of span 3', '/div/span/span[2]/span')]
一些解释:

字典中的额外键
count
用于存储当前标记中具有相同名称的标记数。使用这种格式(字典)可以大大优化代码。您将只访问每个标签一次

奖金:

由于该函数返回一个以XPATH为键的字典,因此可以使用XPATH获取任何文本。例如:

xpaths = get_xpaths_dict(soup.div)
print(xpaths['/div/span/span[2]/span']['text'])
# text of span 3

这种逻辑对我来说是有意义的,但是如果在同一级别上有多个具有相同名称的标记,那么父列表不会产生非唯一标识符吗?例如
12
@DavidJ。是的,对于具有相同父级的同一级别的标记,父级列表将是非唯一的。我真的想不出一个好的解决方案,但如果你想,请分享你的解决方案。很好的答案,这正是我想要的。
xpaths = get_xpaths_dict(soup.div)
print(xpaths['/div/span/span[2]/span']['text'])
# text of span 3