所以我是一个网络抓取新手,遇到了一些我以前从未见过的 HTML 格式。我需要的所有信息都在一个完全扁平的层次结构中。我需要获取日期/电影名称/位置/便利设施。
它的布局是这样的(就像这样):
<div class="caption">
<strong>July 1</strong>
<br>
<em>Top Gun</em>
<br>
"Location: Millennium Park"
<br>
"Amenities: Please be a volleyball tournament..."
<br>
<em>Captain Phillips</em>
<br>
"Location: Montgomery Ward Park"
<br>
<br>
<strong>July 2</strong>
<br>
<em>The Fantastic Mr. Fox </em>
我希望最终在字典或列表中具有格式,以便能够使用 csvwriter 或 Dictwriter 将其写为 CSV 文件;所以输出像
[7 月 1 日,壮志凌云,千禧公园,“请参加 Volley 锦标赛……”], [7 月 1 日,飞利浦船长,蒙哥马利沃德公园,]等
如您所见,烦人的是,当两部电影在同一日期放映时,日期仅显示在第一部电影之前;然后列出所有电影直到下一个<strong>somedate<strong>
属于该初始日期。
有什么建议吗?我怎样才能让多部电影都在上面的标签中指定的日期之内呢?可能认为 find_next_siblings 包括检查标签是否为 <strong>
标签?
最佳答案
这是一个非常丑陋的解决方案,在您使用它之前应该变得更加健壮,但是像这样的东西应该可以工作:
from bs4 import BeautifulSoup
import re
import csv
doc = """<div class="caption">
<strong>July 1</strong>
<br>
<em>Top Gun</em>
<br>
"Location: Millennium Park"
<br>
"Amenities: Please be a volleyball tournament..."
<br>
<em>Captain Phillips</em>
<br>
"Location: Montgomery Ward Park"
<br>
<br>
<strong>July 2</strong>
<br>
<em>The Fantastic Mr. Fox </em>
<br>
"Location: Somewhere"
<br>
"Amenities: Something something"
<br>"""
soup = BeautifulSoup(doc.replace("<br>", "<br/>"))
data = []
for date in soup.find_all("strong"):
sibling = date.next_sibling
while sibling and sibling.name != "strong":
if sibling.name == "em":
title = sibling
location = title.find_next("br").next
extra = location.find_next("br").next
row = []
row.append(date.text)
row.append(title.text)
row.append(re.findall('(?<=:)[^"]*', location)[0])
extra_val = re.findall('(?<=:)[^"]*', extra)
if len(extra_val):
row.append(extra_val[0])
data.append(row)
sibling = sibling.next_sibling
with open('foo.csv', 'wb') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(data)
注意 doc.replace("<br>", "<br/>")
因为 BeautifulSoup 否则解释 <br>
标签来包裹文档的所有其余部分。
解释<br>
对比<br/>
进一步部分:
<p></p><em></em>
在上面的 HTML 中 em
是 p
的 sibling .
<p><em></em></p>
在此 HTML 中 em
是 p
的 child .现在让我们看看 BeautifulSoup 如何解析一些 HTML:
>>> from bs4 import BeautifulSoup
>>> BeautifulSoup('<br><p>Hello<br></p>', 'html.parser')
<br><p>Hello<br/></p></br>
>>> BeautifulSoup('<br><p>Hello<br></p>', 'html5lib')
<html><head></head><body><br/><p>Hello<br/></p></body></html>
html.parser
是 Python 内置的 HTML 解析器,这是您默认获得的解析器。如您所见,它添加了一个关闭 </br>
标记并转换一个 <br>
到 </br>
.简而言之,如果不关闭标签,它就不能很好地完成工作。这搞乱了哪些元素应该是 sibling 。
html5lib
另一方面尝试匹配浏览器的行为,并使用它代替 doc.replace("<br>", "<br/>")
也会工作。然而,它要慢得多,而且它没有 Python 或 BeautifulSoup,所以它需要另一个 pip install html5lib
。去工作。
关于python - 在完全平坦的 HTML 层次结构上使用 BeautifulSoup,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30367396/