使用BeautifulSoup在单个循环周期中解析多个段落

时间:2014-08-03 11:52:05

标签: python beautifulsoup

我正在解析博客的评论部分。不幸的是,这种结构非常不规则。

我面临两种情况:

第一条评论将分为多段

 <p>My first paragraph.<br />But this a second line</p>
 <p>And this is a third line</p>

而第二段仅在一段中。

我想解析字符串变量中的每个注释。但是执行以下代码

from bs4 import BeautifulSoup

html_doc = """
<!DOCTYPE html>
<html>
<body>

<div id="firstDiv">
     <br></br>
     <p>First comment and first line</p>
     <p>First comment and second line</p>
     <div id="secondDiv">
          <b>Date1</b>
     </div> 
     <br></br>  
     <p>Second comment</p>
     <div id="secondDiv">
          <b>Date2</b>
     </div> 
     <br></br>
     </div>
     <br></br>
 </div>

</body>
</html>
"""

soup = BeautifulSoup(html_doc)

for p in soup.find(id="firstDiv").find_all("p"):
    print "Print comment: " + p.get_text()
    print "End of loop"

程序将在循环的不同实例中捕获前两个段落,打印

Print comment: First comment and first line
End of loop
Print comment: First comment and second line
End of loop
Print comment: Second comment
End of loop

我怎样才能在同一循环中打印前两段?

2 个答案:

答案 0 :(得分:0)

soup = BeautifulSoup(html_doc)
text = [''.join(s.findAll(text=True))for s in soup.findAll('p')]

text = [''.join(s.findAll(text=True))for s in soup.findAll('p')]
print ", ".join(text[:2])
print " ".join(text[2:])

First comment and first line, First comment and second line
Second comment

当调用soup.find(id="firstDiv").find_all("p")时,它会创建一个如下所示的列表,因此在列表中迭代三个元素就可以获得三个循环:

[<p>First comment and first line</p>, <p>First comment and second line</p>, <p>Second comment</p>]

答案 1 :(得分:0)

你在这里尝试做的事情不是汤的工作,因为你处理的是平面数据,其结构没有反映在HTML中。所以,你想让汤尽可能地带你,然后切换到迭代。

获取父p的{​​{1}}和div子女的最简单方法就是让所有孩子都来。我们只想要HTML节点,而不是它们之间的字符串,所以我们可以找到没有参数的。像这样:

div

输出将是:

def chunkify(parent):
    """yields groups of <p> nodes separated by <div> siblings"""
    chunk = []
    for element in parent.find_all():
        if element.name == 'p':
            chunk.append(element)
        elif element.name == 'div':
            yield chunk
            chunk = []
    if chunk:
        yield chunk

for paras in chunkify(soup.find(id="firstDiv")):
    print "Print comment: " + '\n'.join(p.get_text() for p in paras)
    print "End of loop"

这就是你想要的,对吧?


你可以更紧凑地编写这个函数,如果你理解Print comment: First comment and first line First comment and second line End of loop Print comment: Second comment End of loop 我觉得更可读...但是我想以一种对新手更有意义的方式来编写它,即使它&#39;先是笨重的这是一个较短的版本:

itertools

您还可以使用包含def chunkify(parent): """yields groups of <p> nodes separated by <div> siblings""" grouped = groupby(parent.find_all(), lambda element: element.name != 'div') groups = (g for k, g in grouped if k) return ([node for node in g if node.name == 'p'] for g in groups) 的更高级别函数替换前两行;我groupby有这个,或至少有一些接近它的东西:

more-itertools