Python 使用BeautifulSoup以查找所有;ul";及;李",;元素
我目前正在用Python编写一个爬行脚本,我想将下面的HTML响应映射到一个多列表或字典中(这无关紧要) 我目前的代码是:Python 使用BeautifulSoup以查找所有;ul";及;李",;元素,python,beautifulsoup,html-lists,Python,Beautifulsoup,Html Lists,我目前正在用Python编写一个爬行脚本,我想将下面的HTML响应映射到一个多列表或字典中(这无关紧要) 我目前的代码是: from bs4 import BeautifulSoup from urllib.request import Request, urlopen req = Request("https://my.site.com/crawl", headers={'User-Agent': 'Mozilla/5.0'}) webpage = urlopen(req) soup
from bs4 import BeautifulSoup
from urllib.request import Request, urlopen
req = Request("https://my.site.com/crawl", headers={'User-Agent': 'Mozilla/5.0'})
webpage = urlopen(req)
soup = BeautifulSoup(webpage, 'html.parser')
ul = soup.find('ul', {'class': ''})
运行此命令后,我得到存储在ul中的以下结果:
<ul>
<li><a class="reference" href="#ref1">Data1</a></li>
<li><a class="reference" href="#ref2">Data2</a>
<ul>
<li><a class="reference" href="#ref3">Data3</a></li>
<li><a class="reference" href="#ref4">Data4</a>
<ul>
<li><a class="reference" href="#ref5"><span class="pre">Data5</span></a></li>
<li><a class="reference" href="#ref6"><span class="pre">Data6</span></a></li>
.
.
.
</ul>
</li>
</ul>
</li>
<li><a class="reference" href="#ref7">Data7</a>
<ul>
<li><a class="reference" href="#ref8"><span class="pre">Data8</span></a></li>
<li><a class="reference" href="#ref9"><span class="pre">Data9</span></a></li>
.
.
.
</ul>
</li>
<li><a class="reference" href="#ref10">Data10</a>
<ul>
<li><a class="reference" href="#ref11"><span class="pre">Data11</span></a></li>
<li><a class="reference" href="#ref12">Data12</a></li>
</ul>
</li>
</ul>
我确实觉得这是一个麻烦的过程,但是我看不到任何其他的方法
非常感谢任何能让我走上正确方向的帮助
干杯 只需递归
ul
元素,拉出所有包含文本的li
元素的文本,如果存在
元素,则递归更深:
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
这需要所有直接li
元素;如果存在
元素,则该锚元素的文本将转换为键,我们将标记属性的副本存储为值(忽略任何类
属性)。如果
标记旁边还有元素,则递归解析该元素,并将其作为
标记的属性字典的子项添加
对于示例输入,这将生成:
>>> from pprint import pprint
>>> pprint(parse_ul(soup.ul))
{'Data1': {'href': '#ref1'},
'Data10': {'children': {'Data11': {'href': '#ref11'},
'Data12': {'href': '#ref12'}},
'href': '#ref10'},
'Data2': {'children': {'Data3': {'href': '#ref3'},
'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}},
'href': '#ref4'}},
'href': '#ref2'},
'Data7': {'children': {'Data8': {'href': '#ref8'}, 'Data9': {'href': '#ref9'}},
'href': '#ref7'}}
没有简单的方法可以做到这一点,但也没有那么麻烦
例如,您可以递归地执行此操作,如下所示:
def make_data(ul):
d = {}
for a in ul.find_all('a'):
d[a.text] = {'href': a.attrs['href']}
lis = ul.find_all('li', recursive=False)
children = {}
for li in lis:
child = li.ul
if child:
children[li.a.attrs['href']] = make_data(child)
if children:
d['children'] = children
return d
(我必须给每个孩子口述一个键,因为你真正想要的结构不是有效的口述。)
当然,你会想,例如,添加一些错误处理,但这应该足够让你开始了。我非常喜欢Martijn Pieters parse_ul(),但我有一些代码没有遵循这个解析器的规则,在一个- 中有一个双
其中最后一节的前缀为文本。
例如
见下文
<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
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)
将生成以下输出,该输出缺少
中包含的第二部分:
{'Data1': {'href': '#ref1'},
'Data2': {'children': {'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}}},
'href': '#ref4'},
'href': '#ref2'}
}
HTML结构不一致,至少缺少一个开头(或结尾过多)。一定要确保它是干净的。在字典中,您确实需要一个用于测试字典值的键。可能是'children'
?它们是我想在Future中查找的真实值,例如表单电子邮件模型
。这不是有效的数据结构。在每组大括号中,您的href
dict都有键,但您的孩子dict没有键。这不是口述,也不是一套,只是一个语法错误。也许你想要像'href':'ref2',children:{…
?@MartijnPieters是的,你对HTML结构的看法是对的。我收到的数据要多得多,我试图将其缩短。我想可能是错误地添加了两个额外的
-元素,这在帖子中得到了修复。感谢你一直以来的帮助,不幸的是,它最终添加了子元素艾姆斯
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)
{'Data1': {'href': '#ref1'},
'Data2': {'children': {'Data4': {'children': {'Data5': {'href': '#ref5'},
'Data6': {'href': '#ref6'}}},
'href': '#ref4'},
'href': '#ref2'}
}