python - 在完全平坦的 HTML 层次结构上使用 BeautifulSoup

标签 python html beautifulsoup

所以我是一个网络抓取新手,遇到了一些我以前从未见过的 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 中 emp 的 sibling .

<p><em></em></p>

在此 HTML 中 emp 的 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/

相关文章:

python - python中有什么方法可以找出调用其他方法的方法吗?

javascript : window. location.href/window.open 在 iframe 上不起作用

python - 使用 BeautifulSoup 读取 &lt;script&gt; 的内容

python - 如何使用 python 将表单发布到 aspx 网站

html - Selenium - XPath - 通过 innerHTML 搜索元素

python - 为什么我的 8kHz wav 文件的 mel 特征在 sr = 16kHz 和 44.1kHz 中提取不同

python - 如何组织一个python项目

python - Wagtail:动态图像生成和缓存

html - 强制边距使用所有宽度

javascript - 在 jquery 文档准备好之前加载 Modernizr