python - 使用 BeautifulSoup 查找所有具有微小偏差的“ul”和“li”元素
问题描述
在 python 的爬虫脚本中,我使用 BeautifulSoup 解析一个 html 多列表,几乎类似于问题 { Using BeautifulSoup in order to find all "ul" and "li" elements } 并由 Martijn Pieters 使用他的 python 函数 parse_ul 回答()。
def parse_ul(elem):
result = {}
for sub in elem.find_all('li', recursive=False):
if sub.a is None:
continue
data = {k: v for k, v in sub.a.attrs.items() if k != 'class'}
if sub.ul is not None:
# recurse down
data['children'] = parse_ul(sub.ul)
result[sub.a.get_text(strip=True)] = data
return result
我需要解析一个不遵循 Martijn Pieters 解析器规则的多列表。这个 html 多列表<ul></ul>
在一个单中包含一个双精度<li> .. </li>
,其中最后一个部分有一个<a ... > text </a>
前缀(不带<li>
)
例如<li><a ...></a><ul> </ul> <a..></a><ul> </ul> </li>
见下文
<ul>
<li><a class="ref" href="#ref1">Data1</a></li>
<li><a class="ref" href="#ref2">Data2</a>
<ul>
<li><a class="ref" href="#ref4">Data4</a>
<ul>
<li><a class="ref" href="#ref5"><span class="pre">Data5</span></a>/li>
<li><a class="ref" href="#ref6"><span class="pre">Data6</span></a></li>
.
.
</ul>
<!-- a-tag without preceding <li> tag -->
<a class="ref" href="#ref4a">Data4a</a>
<ul>
<li><a class="ref" href="#ref5a"><span class="pre">Data5a</span></a></li>
<li><a class="ref" href="#ref6a"><span class="pre">Data6a</span></a></li>
.
.
</ul>
</li>
</ul>
</li>
.
.
</ul>
我不知道如何更改 parse_ul() 以便它接受这种偏差并输出这个?Martijn Pieters 解析器非常出色,我的问题也必须有一个出色的解决方案:-)
{'Data1': {'href': '#ref1'},
'Data2': {'children': {'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}}},
'href': '#ref4'},
{'Data4a': {'children':{'Data5a': {'href': '#ref5a'},
'Data6a': {'href': '#ref6a'}}},
'href': '#ref4a'},
'href': '#ref2'}
}
以下脚本:
from bs4 import BeautifulSoup
import pprint
pp = pprint.PrettyPrinter(indent=4) # Init pritty print (pprint)
soup = BeautifulSoup(html_contents, 'lxml')
menu_dict = parse_ul(soup.ul)
pp.pprint(menu_dict)
将生成以下输出,其中缺少包含在中的第二部分<a..></a><ul> </ul>
:
{'Data1': {'href': '#ref1'},
'Data2': {'children': {'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}}},
'href': '#ref4'},
'href': '#ref2'}
}
解决方案
一种可能的解决方案是在解析之前修改 HTML 代码。
这将找到所有<a>
具有先前兄弟姐妹的标签<ul>
并将它们插入到适当的位置:
txt = '''<ul>
<li><a class="ref" href="#ref1">Data1</a></li>
<li><a class="ref" href="#ref2">Data2</a>
<ul>
<li><a class="ref" href="#ref4">Data4</a>
<ul>
<li><a class="ref" href="#ref5"><span class="pre">Data5</span></a>/li>
<li><a class="ref" href="#ref6"><span class="pre">Data6</span></a></li>
</ul>
<!-- a-tag without preceding <li> tag -->
<a class="ref" href="#ref4a">Data4a</a>
<ul>
<li><a class="ref" href="#ref5a"><span class="pre">Data5a</span></a></li>
<li><a class="ref" href="#ref6a"><span class="pre">Data6a</span></a></li>
</ul>
</li>
</ul>
</li>
</ul>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(txt, 'html.parser')
# find "lone" <A>+<UL> tags, wrap them in new <LI> tag and append the li tag after parent <LI>:
for a in soup.select('a'):
prev = a.find_previous_sibling()
if prev and prev.name == 'ul':
parent_li = a.parent
next_ul = a.find_next('ul')
new_li = soup.new_tag("li")
new_li.append(a)
new_li.append(next_ul)
parent_li.insert_after(new_li)
# this is unchanged code from your question:
def parse_ul(elem):
result = {}
for sub in elem.find_all('li', recursive=False):
if sub.a is None:
continue
data = {k: v for k, v in sub.a.attrs.items() if k != 'class'}
if sub.ul is not None:
# recurse down
data['children'] = parse_ul(sub.ul)
result[sub.a.get_text(strip=True)] = data
return result
from pprint import pprint
pprint(parse_ul(soup.ul))
印刷:
{'Data1': {'href': '#ref1'},
'Data2': {'children': {'Data4': {'children': {'Data5': {'href': '#ref5'}},
'href': '#ref4'},
'Data4a': {'children': {'Data5a': {'href': '#ref5a'},
'Data6a': {'href': '#ref6a'}},
'href': '#ref4a'}},
'href': '#ref2'}}
推荐阅读
- python - 如何修复“ValueError:没有足够的值来解包(预期 2,得到 1)”
- ios - 是否可以在不使用第三方解决方案的情况下创建在 iOS 应用安装后仍然存在的深层链接?
- python - TensorFlow 中 model.predict 的进展?
- php - 如何使用 Laravel 在 MySQL 中插入表情符号?
- reactjs - 如何在 reactjs 中处理刷新令牌
- python - 使用 fastText 进行文本分类的文本预处理
- node.js - mongoose:无法为模型名称“SchemaName”在 `_id` 上指定自定义索引,MongoDB 不允许覆盖默认的 `_id` 索引
- python - 带有元组和frozensets的“is”关键字
- django - 借助表单将图像插入数据
- javascript - 元素要么被选中,要么被聚焦,要么被选中。它可以防止背景颜色可见