【问题标题】:How to understand "recursive" with BeautifulSoup in Python如何在 Python 中用 BeautifulSoup 理解“递归”
【发布时间】:2021-12-21 17:05:05
【问题描述】:

我正在使用 Python 中的 BeautifulSoup 进行“递归”项目。我已经阅读了官方文档和很多问题,但我仍然不明白。

from bs4 import BeautifulSoup
s = "<div>C<p><strong>A</strong>B</p></div>"
soup = BeautifulSoup(s, 'html.parser')
  1. print(soup.find("p", recursive=False))None

是不是因为我们在&lt;div&gt;&lt;/div&gt;之外找不到任何东西了?

  1. print(soup.find("p").find(recursive=False))&lt;strong&gt;A&lt;/strong&gt;

如果我在第一个问题中的想法是正确的, 我猜这会给&lt;p&gt;B&lt;/p&gt;,因为我们无法深入。但是为什么这要从&lt;strong&gt;开始呢?为什么不&lt;p&gt;

另外,如何提取&lt;p&gt;B&lt;/p&gt;

【问题讨论】:

    标签: python html beautifulsoup web-crawler


    【解决方案1】:

    HTML 文档是嵌套的,标签里面有标签。 在您提供的文档('s')中,结构如下:

    Div
       p
         strong
            `text node A`
         `text node B`         
    

    Recursive 指示 beautifulsoup 检查特定节点的子节点是否匹配(如果设置为 false,则不检查)。

    1. 只有一个根节点(div)。因为你告诉 beautifulsoup 不要递归检查,它不会查看 div 的子元素,所以它返回 None,因为没有根 'p' 元素。

    2. 这实际上是两个“find”链接在一起的实例。第一个“查找”查找“p”(并且递归查找,因为递归的默认设置为 True)。它会按照我们的预期找到“div>p”。在此之后,您在第一次查找的结果上再次调用了“查找”,然后它正在搜索任何内容,因为您没有指定您要查找的节点类型。 'p' 的第一个孩子是 'strong' 标记,所以这就是返回的内容。

    【讨论】:

    • 谢谢,我完全明白了。但我现在有麻烦了,我可以再问一件事吗?
    • 我明白为什么 print(soup.find("p").find(recursive=False)) 会给出 A。但是当我像 -> print(soup.find("p").find(text=True, recursive=False)) 一样添加“text=True”时,它给出了 B。我不明白为什么它没有给出A 在强标签内。
    • @Jihyun 这是因为 'A' 嵌套在 标记内,所以要找到它,您需要启用递归搜索。否则,搜索将只找到作为

      的直接后代的“text”,在这种情况下是“B”文本节点是

    • @Jihyun 不用担心。如果回答了您的问题,请接受答案:)
    • 哦,我不知道有这样的功能。谢谢!
    【解决方案2】:

    Recursive = False仅返回您要查找的标记元素的子元素。例如:

    <li>
        <p>1</p>
        <p>2</p>
        <div>
          <p>3</p>
        </div>
    </li>
    
    li = soup.find('li')
    

    现在,

    print(li.findChildren("p"))
    

    打印[&lt;p&gt;1&lt;/p&gt;, &lt;p&gt;2&lt;/p&gt;, &lt;p&gt;3&lt;/p&gt;]

    print(li.findChildren("p", recursive=False))
    

    打印[&lt;p&gt;1&lt;/p&gt;, &lt;p&gt;2&lt;/p&gt;]


    为了从&lt;div&gt;C&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt;B&lt;/p&gt;&lt;/div&gt;得到&lt;p&gt;B&lt;/p&gt;

    s = "<div>C<p><strong>A</strong>B</p></div>"
    soup = BeautifulSoup(s, 'html.parser')
    soup.strong.decompose()
    print(soup.p)
    

    打印&lt;p&gt;B&lt;/p&gt;


    说明:

    print(soup.strong)
    

    打印&lt;strong&gt;A&lt;/strong&gt;

    soup.strong.decompose()
    

    删除&lt;strong&gt;A&lt;/strong&gt; (Beautiful Soup decompose())

    print(soup.p)
    

    打印&lt;p&gt;B&lt;/p&gt;

    【讨论】:

      【解决方案3】:

      当您使用recursive=False 时,这意味着只搜索您正在调用.find().find_all() 的元素的直接子元素。顶级soup 对象的唯一直接子元素是&lt;div&gt; 元素。由于它不是&lt;p&gt; 元素,因此它与给定的名称不匹配,因此找不到任何内容。

      在您的第二个示例中,您首先使用递归搜索来查找&lt;p&gt; 元素。然后你打电话给.find() 没有名字,所以它会匹配任何元素的名字。由于您指定了recursive=false,它只考虑&lt;p&gt; 的直系子级。第一个子元素是&lt;strong&gt;A&lt;/strong&gt;,它被返回了。

      【讨论】:

      • 哇我真的明白了!!!谢谢! ?
      猜你喜欢
      • 1970-01-01
      • 2019-07-28
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 2017-05-08
      • 2014-05-07
      • 2018-03-28
      • 1970-01-01
      相关资源
      最近更新 更多