【问题标题】:extracting nested items with beautifulsoup用 beautifulsoup 提取嵌套项
【发布时间】:2013-12-18 14:56:19
【问题描述】:

这很可能是重复的。我已经阅读了很多与表格相关的问题——like this one——试图了解如何提取嵌套更深的网页内容。

这里是源代码:

<div class='event-details'>
    <div class='event-content'>
    <p style="text-align:center;">
        <span style="font-size:14px;">
            <span style="color:#800000;">TICKETS: ...<br></span>
        </span>
        <span style="font-size:14px;">
            <span style="color:#800000;">Front-of-House $35 ...<br></span>
        </span>
    </p>
    <p><span style="font-size:14px;">From My Generation ...</span></p>
    <p><span style="font-size:14px;">With note for note ...</span></p>
    <p><span style="font-size:14px;">The Who Show was cast ...</span></p>
    <p><span style="font-size:14px;">With excellent musicianship ...</span></p>
    <p><span style="font-size:14px;">http://www.thewhoshow.com</span></p>
    </div>
</div>

这就是困难所在:我不想要票证信息,它在我想要的段落文本之前,并且所有文本在某一点或另一个点前面都有一个相同的 style 标记。即:&lt;span style="font-size:14px;"&gt;

我希望在 BS 中有一种方法可以获取段落提供的独特功能——即p 标签紧跟上面的 span 标签。见:&lt;p&gt;&lt;span style="font-size:14px;"&gt;

这是我所做的:

desc_block = newsoup.find('div', {'class','event-details'}).find_all('p')
description = []
for desc in desc_block:
    desc_check = desc.get_text()
description.append(desc_check)
print description[2:]

问题有两个:第一,我添加了我不想要的字符(例如\n)和信息(票务信息);第二,我要附加,因为我真正想做的是提取文本并将其作为 utf-8 字符串添加到空字符串中。谁能帮我解决第一个问题——即获取无关的p标签和我不想要的信息?任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 您可能正在寻找 XPath 表达式。有关如何使用它的示例,请参阅answer I gave here。您可以将 XPath 表达式与 lxml 一起使用,它还提供了 Beautiful Soup 解析器(以及其他)。
  • @LukasGraf 你的回复很棒;谢谢你,卢卡斯。您能否提供任何建议或指向另一个教程以使 lxml(我与 xpath 一起使用的唯一工具)与 BS 很好地配合?我似乎永远无法使这两项工作,但我相信它可以完成,正如 lxml 文档所说的那样。可能是一个愚蠢的问题,但你肯定比我更清楚,我会尽职尽责地遵循你提出的任何建议:)。谢谢你,先生。
  • 正在寻找答案 ;-)
  • 你也想放弃"Front-of-House $35...",对吧?那么前两个 14px 跨度,分别来自 #800000 跨度的所有文本?
  • @LukasGraf 是的,没错;我只想要&lt;p&gt;&lt;span style="font-size:14px;"&gt; 段落。 ps:谢谢编辑。以后我会尝试像这样格式化html块。

标签: python python-2.7 beautifulsoup


【解决方案1】:

如果您使用lxml 解析文档,则可以使用XPath expressions 根据它们在树中的位置及其属性仅选择您关心的元素。

要安装lxml,请执行以下任一操作

  • easy_install lxml
  • pip install lxml
  • setup.py 中将其声明为您的包的依赖项
  • 或使用任何其他方式安装包

(假设您已经安装了BeautifulSoup

示例

from BeautifulSoup import UnicodeDammit
from lxml import html


def decode_html(html_string):
    converted = UnicodeDammit(html_string, isHTML=True)
    if not converted.unicode:
        raise UnicodeDecodeError(
            "Failed to detect encoding, tried [%s]",
            ', '.join(converted.triedEncodings))
    # print converted.originalEncoding
    return converted.unicode


tag_soup = open('mess.html').read()

# Use BeautifulSoup's UnicodeDammit to detect and fix the encoding
decoded = decode_html(tag_soup)

# Use lxml's HTML parser (faster) to parse the document
root = html.fromstring(decoded)

spans = root.xpath("//span[@style='font-size:14px;']")
wanted_spans = spans[2:]

blocks = []
for span in wanted_spans:
    line = span.text.strip().replace('\n', '')
    blocks.append(line)

description = '\n'.join(blocks)
print description

此代码使用lxml 的快速 HTML 解析器来解析文档(对于您提供的 sn-p 工作得很好),但 BeautifulSoup 的编码检测首先猜测适当的字符集并解码文档。有关如何将 lxml 与 BeautifulSoup 解析器一起使用的更多信息,请参阅 lxml docs on BeautifulSoup

跨度由 XPath 表达式 //span[@style='font-size:14px;'] 选择,这基本上意味着:“文档中具有属性 style 且精确值为 font-size:14px; 的任何&lt;span /&gt;

如果您想更具体地选择元素,可以使用类似的表达式

//div[@class='event-details']//span[@style='font-size:14px;']

仅选择类event-detailsdiv 下方的跨度(某处)。现在,这确实是要匹配的 exact 值 - 如果样式值后面甚至有 ;missig,它就不会匹配。 XPath 对 CSS 一无所知,它是一种通用查询语言,用于遍历 XML 文档中的元素或属性。如果您的文档那么凌乱,并且您需要考虑这一点,则需要在 XPath 表达式中使用 contains() 之类的内容。

spans[2:] 然后选择除前两个跨度之外的所有跨度,strip().replace('\n', '') 确保我们在文本中没有空格。最后,我将所有行加入以形成换行符分隔的描述 - 如果您甚至不想要单个换行符,只需使用 ' '.join(lines) 加入行。

有关 XPath 语法的更多信息,请参见 W3Schools Xpath Tutorial 中的 XPath Syntax 页面。

要开始使用 XPath,在众多 XPath testers 之一中摆弄您的文档也很有帮助。此外,Firefox 的 Firebug 插件或 Google Chrome 检查器允许您显示所选元素的(或者更确切地说,其中之一)XPath。

【讨论】:

  • 这太棒了,卢卡斯。我非常感谢您的详尽解释,尤其是,我可以在这些资源中了解更多信息以进行未来改进。非常棒!
猜你喜欢
  • 2021-10-11
  • 2019-04-10
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多