如何使用BeautifulSoup从HTML段落中提取内容?

1 投票
2 回答
2643 浏览
提问于 2025-04-16 00:45

我正在使用BeautifulSoup进行网页数据抓取。我的问题是:

<p><b><a href="/name/abe">ABE</a></b> &nbsp; <font class="masc">m</font> &nbsp; <font class="info"><a href="/nmc/eng.php" class="usg">English</a>, <a href="/nmc/jew.php" class="usg">Hebrew</a></font><br />Short form of <a href="/name/abraham" class="nl">ABRAHAM</a>

从这个段落中,我可以提取出名字ABE,方法如下:

for pFound in soup.findAll('p'):

    print pFound


#will get the names
    x = pFound.find('a').renderContents()
    print x

现在我的问题是,如何在同一个段落中提取另一个名字。

Short form of <a href="/name/abraham" class="nl">ABRAHAM</a>

我只想提取当标签a前面有“Short form of”这个文本时的内容。

有没有什么好主意呢?在这个HTML页面中有很多这样的段落,并不是所有的段落都有“Short form of”这个文本,可能会有其他的文本在那个位置。

我觉得结合正则表达式和findNext()可能会有用,但我对BeautifulSoup不太熟悉,浪费了不少时间。

希望能得到一些帮助。谢谢。

2 个回答

0

你可以使用pyparsing这个工具来处理HTML,就像一个“超级正则表达式”。你可以通过组合各种开始和结束的标签来创建一个简单的匹配模式,这样就不会遇到用普通正则表达式抓取HTML时常见的问题,比如标签和属性的字母大小写不一致、属性不确定、属性顺序混乱、空格不规律等。然后,使用pattern.scanString这个方法,它会扫描HTML源代码,并返回匹配到的内容和它们的起始和结束位置。再加上结果命名的功能(类似于正则表达式中的命名字段),这样访问你感兴趣的具体字段就变得很简单了。

html = """<some leading html>
<p><b><a href="/name/abe">ABE</a></b> &nbsp; <font class="masc">m</font> &nbsp; 
<font class="info"><a href="/nmc/eng.php" class="usg">English</a>, <a href="/nmc/jew.php" class="usg">
Hebrew</a></font><br />Short form of <a href="/name/abraham" class="nl">ABRAHAM</a>
<some trailing html>"""

from pyparsing import makeHTMLTags, SkipTo, Optional

pTag,pEnd = makeHTMLTags("P")
bTag,bEnd = makeHTMLTags("B")
aTag,aEnd = makeHTMLTags("A")
fontTag,fontEnd = makeHTMLTags("FONT")
brTag = makeHTMLTags("BR")[0]
nbsp = "&nbsp;"

nickEntry = (pTag + bTag + aTag + SkipTo(aEnd)("nickname") + aEnd + bEnd + Optional(nbsp) + 
            fontTag + SkipTo(fontEnd) + fontEnd + Optional(nbsp) +
            fontTag + aTag + SkipTo(aEnd) + aEnd + "," +
            aTag + SkipTo(aEnd) + aEnd + fontEnd + 
            brTag + "Short form of" +
            aTag + SkipTo(aEnd)("fullname") + aEnd)

for match,_,_ in nickEntry.scanString(html):
    print match.nickname, "->", match.fullname

打印结果:

ABE -> ABRAHAM
1

下面的代码应该可以正常运行...:

htm = '''<p><b><a href="/name/abe">ABE</a></b> &nbsp; <font class="masc">m
</font>&nbsp; <font class="info"><a href="/nmc/eng.php" class="usg">English
</a>, <a href="/nmc/jew.php" class="usg">Hebrew</a></font><br />
Short form of <a href="/name/abraham" class="nl">ABRAHAM</a>'''

import BeautifulSoup

soup = BeautifulSoup.BeautifulSoup(htm)

for p in soup.findAll('p'):
  firsta = True
  shortf = False
  for c in p.recursiveChildGenerator():
    if isinstance(c, BeautifulSoup.NavigableString):
      if 'Short form of' in str(c):
        shortf = True
    elif c.name == 'a':
      if firsta or shortf:
        print c.renderContents()
        firsta = shortf = False

撰写回答