【问题标题】:How do I use beautiful soup to find tables under p tag with a certain text如何使用漂亮的汤在p标签下找到带有特定文本的表格
【发布时间】:2015-04-21 02:23:34
【问题描述】:

我是 Beautifulsoup 的新手,我正在尝试在某个 p 标签下找到一些表格,其中包含文本“子类”

这是 HTML 示例

<p><b>subclass</b></p>
<table>...<table>
<p><b>frnekr</b></p>
<table>...<table>

我只想用文本->子类抓取p标签下的表格。不幸的是,那些 p 标签没有类。

【问题讨论】:

  • 我希望应该是&lt;table&gt;...&lt;/table&gt;,而不是一张永远不会关闭的巨型桌子,三张桌子相互嵌套?
  • 顺便说一句,与 BS4 的 find 语法不同,XPath 可以一次性完成所有这些,例如 //p[descendant-or-self::text()='subclass']/following::table。我很确定lxml 可以处理。当然,如果这对您来说看起来像是难以理解的魔法,请忽略这一点,并首先学习如何使用 BS4 强制执行它;这要简单得多。

标签: python beautifulsoup


【解决方案1】:

做到这一点的一种方法是在一个过滤器中。

请参阅文档中搜索下的Kinds of filters 部分。

如果你可以写一个函数来检查一个标签是否是一个p标签,文本中有subclass,你可以用它来找到p标签。例如:

>>> soup.find_all(lambda tag: tag.name=='p' and tag.text=='subclass')
[<p><b>subclass</b></p>]

当然你不需要那个功能。 (与soup.find_all('p', text='subclass') 相同。)但它说明了这个想法。

所以现在,您要查找此类 p 标记之后的 table 标记。这会变得有点复杂,所以让我们把它写出来。

首先,一个快速而肮脏的解决方案:

def is_table_after_subclass(tag):
    return (tag.name == 'table' and 
            tag.find_previous_sibling('p').text == 'subclass')

但这不是很健壮。您不想扫描所有以前的兄弟姐妹,只需检查直接的兄弟姐妹。此外,如果没有找到 p 标签,您将得到一个异常而不是 false。所以:

# This is necessary because the table's previous_sibling is the
# '\n' string between the `p` and the `table`, not the `p`.
def previous_tag(tag):
    tag = tag.previous_sibling
    while not isinstance(tag, bs4.Tag):
        tag = tag.previous_sibling
    return tag

def is_table_after_subclass(tag):
    if tag.name != 'table': return False
    prev = previous_tag(tag)
    return prev.name == 'p' and prev.text == 'subclass'

现在,你可以这样做了:

soup.find_all(is_table_after_subclass)

另一种方法是首先迭代所有表,然后跳过具有错误前一个同级的表。或者首先迭代所有子类段落,然后跳过具有错误下一个兄弟的段落。例如:

def next_tag(tag):
    tag = tag.next_sibling
    while not isinstance(tag, bs4.Tag):
        tag = tag.next_sibling
    return tag

for subclass in soup.find_all('p', text='subclass'):
    tag = next_tag(subclass)
    if tag.name == 'table':
        do_stuff(tag)

【讨论】:

    【解决方案2】:

    Soupy 是我尝试让这样的查询更自然(Soupy 包装了 BeautifulSoup,使查询链接更容易)。这是一个解决方案:

    from soupy import Soupy, Q
    
    text = """
    <p><b>subclass</b></p>
    <table>...</table>
    <p><b>frnekr</b></p>
    <table>...</table>
    <p><b>subclass</b></p>
    <p> No table here </p>
    """
    from soupy import Soupy, Q
    
    (dom.find_all('p', text="subclass")     # find relevant p tags
        .each(Q.find_next_sibling('table')) # look for sibling tables
        .filter(Q)                          # drop failed searches
        .val())                             # dump out of Soupy
    

    哪个产生

    [<table>...</table>]
    

    这大致相当于@abarnert 的最后一个代码示例

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-21
      • 1970-01-01
      相关资源
      最近更新 更多