【问题标题】:How to ignore empty lines while using .next_sibling in BeautifulSoup4 in pythonpython - 在BeautifulSoup4中使用.next_sibling时如何忽略空行
【发布时间】:2014-04-23 10:30:42
【问题描述】:

由于我想删除 html 网站中重复的占位符,我使用 BeautifulSoup 的 .next_sibling 运算符。只要重复项在同一行中,就可以正常工作(请参阅数据)。但有时它们之间有一条空线 - 所以我希望 .next_sibling 忽略它们(看看 data2)

那是代码:

from bs4 import BeautifulSoup, Tag
data = "<p>method-removed-here</p><p>method-removed-here</p><p>method-removed-here</p>"
data2 = """<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>
"""
soup = BeautifulSoup(data)
string = 'method-removed-here'
for p in soup.find_all("p"):
    while isinstance(p.next_sibling, Tag) and p.next_sibling.name== 'p' and p.text==string:
        p.next_sibling.decompose()
print(soup)

数据的输出符合预期:

<html><head></head><body><p>method-removed-here</p></body></html>

data2 的输出(这需要修复):

<html><head></head><body><p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>
</body></html>

我在 BeautifulSoup4 文档中找不到有用的信息,而且 .next_element 也不是我想要的。

【问题讨论】:

  • 运行它时我没有得到相同的行为——我的输出不包括空行(这是我所期望的行为)。这正是你正在运行的吗?
  • 绝对。我正在运行 python3.4 removeplaceholder.py 并得到 exactly 输出,包括换行符。

标签: python html-parsing beautifulsoup


【解决方案1】:

使用find_next_sibling() 而不是next_sibling。还有find_previous_sibling() 而不是previous_sibling

原因:next_sibling 不仅返回下一个 html 标记,还返回下一个“汤元素”。通常这是标签之间的空白,但可以更多。另一方面,find_next_sibling() 返回下一个 html 标签,忽略标签之间的空格和其他杂物。

我稍微重组了您的代码以进行此演示。我希望它在语义上是相同的。

带有next_sibling 的代码展示了您描述的相同行为(适用于data,但不适用于data2

from bs4 import BeautifulSoup, Tag
data = "<p>method-removed-here</p><p>method-removed-here</p><p>method-removed-here</p>"
data2 = """<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>

<p>method-removed-here</p>
"""
soup = BeautifulSoup(data, 'html.parser')
string = 'method-removed-here'
for p in soup.find_all("p"):
    while True:
        ns = p.next_sibling
        if isinstance(ns, Tag) and ns.name== 'p' and p.text==string:
            ns.decompose()
        else:
            break
print(soup)

带有find_next_sibling() 的代码适用于datadata2

soup = BeautifulSoup(data, 'html.parser')
string = 'method-removed-here'
for p in soup.find_all("p"):
    while True:
        ns = p.find_next_sibling()
        if isinstance(ns, Tag) and ns.name== 'p' and p.text==string:
            ns.decompose()
        else:
            break
print(soup)

beautifulsoup 其他部分的行为相同(返回所有汤元素,包括不需要的空格):BeautifulSoup .children or .content without whitespace between tags

【讨论】:

    【解决方案2】:

    也不是一个很好的解决方案,但这对我有用

    def get_sibling(element):
        sibling = element.next_sibling
        if sibling == "\n":
            return get_sibling(sibling)
        else:
            return sibling
    

    【讨论】:

      【解决方案3】:

      通过使neurosnap 回答通用化来改进一点:

      def next_elem(element, func):
          new_elem = getattr(element, func)
          if new_elem == "\n":
              return next_elem(new_elem, func)
          else:
              return new_elem
      

      现在你可以用它调用任何函数,例如:

      next_elem(element, 'previous_sibling')
      

      【讨论】:

        【解决方案4】:

        我可以通过变通方法解决此问题。 google-group for BeautifulSoup 中描述了该问题,他们建议对 html 文件使用预处理器:

         def bs_preprocess(html):
             """remove distracting whitespaces and newline characters"""
             pat = re.compile('(^[\s]+)|([\s]+$)', re.MULTILINE)
             html = re.sub(pat, '', html)       # remove leading and trailing whitespaces
             html = re.sub('\n', ' ', html)     # convert newlines to spaces
                                                # this preserves newline delimiters
             html = re.sub('[\s]+<', '<', html) # remove whitespaces before opening tags
             html = re.sub('>[\s]+', '>', html) # remove whitespaces after closing tags
             return html 
        

        这不是最好的解决方案,而是一个。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-12-23
          • 2022-01-14
          • 2022-11-28
          • 1970-01-01
          • 2019-05-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多