使用BeautifulSoup解析HTML页面

4

我开始学习使用BeautifulSoup解析HTML。
例如对于网站"http://en.wikipedia.org/wiki/PLCB1"。

import sys
sys.setrecursionlimit(10000)

import urllib2, sys
from BeautifulSoup import BeautifulSoup

site= "http://en.wikipedia.org/wiki/PLCB1"
hdr = {'User-Agent': 'Mozilla/5.0'}
req = urllib2.Request(site,headers=hdr)
page = urllib2.urlopen(req)
soup = BeautifulSoup(page)

table = soup.find('table', {'class':'infobox'})
#print table
rows = table.findAll("th")
for x in rows:
    print "x - ", x.string

在一些包含URL的情况下,我的输出会变成“None”。为什么会这样呢?

输出:

x -  Phospholipase C, beta 1 (phosphoinositide-specific)
x -  Identifiers
x -  None
x -  External IDs
x -  None
x -  None
x -  Molecular function
x -  Cellular component
x -  Biological process
x -  RNA expression pattern
x -  Orthologs
x -  Species
x -  None
x -  None
x -  None
x -  RefSeq (mRNA)
x -  RefSeq (protein)
x -  Location (UCSC)
x -  None

例如,在Location之后,还有一个包含“pubmed search”的th,但显示为None。我想知道为什么会出现这种情况。
其次,是否有办法将th和相应的td获取为字典,以便更容易解析?
2个回答

5

Element.string 只包含元素中直接文本内容,不包括嵌套元素。

如果你正在使用 BeautifulSoup 4,请使用 Element.stripped_strings 替代:

print ''.join(x.stripped_strings)

对于BeautifulSoup 3,您需要搜索所有文本元素:
print ''.join([unicode(t).strip() for t in x.findAll(text=True)])

如果想要将<th><td>元素组合成一个字典,您需要循环遍历所有的<th>元素,然后使用.findNextSibling()来定位相应的<td>元素,并结合上面的.findAll(text=True)技巧构建一个字典。
info = {}
rows = table.findAll("th")
for headercell in rows:
    valuecell = headercell.findNextSibling('td')
    if valuecell is None:
        continue
    header = ''.join([unicode(t).strip() for t in headercell.findAll(text=True)])
    value = ''.join([unicode(t).strip() for t in valuecell.findAll(text=True)])
    info[header] = value

这仅适用于bs4。@sam可能正在使用早期版本的BeautifulSoup。(顺便说一句,这不是我的-1) - unutbu
@unutbu:该死..已更新,包括BS3选项。 - Martijn Pieters
您更新的答案非常有帮助,非常感谢。您能告诉我第二个问题的答案吗? - sam
@sam:我为你添加了一个信息表到字典的片段。 - Martijn Pieters
@MartijnPieters:你是一个非常优秀的程序员,非常感谢你的帮助。我也从你身上学到了很多东西。愿上帝保佑你!!! - sam

2
如果您检查HTML代码,
<th colspan="4" style="text-align:center; background-color: #ddd">Identifiers</th>
</tr>
<tr class="">
<th style="background-color: #c3fdb8"><a href="/wiki/Human_Genome_Organisation" title="Human Genome Organisation">Symbols</a></th>
<td colspan="3" class="" style="background-color: #eee"><span class="plainlinks"><a rel="nofollow" class="external text" href="http://www.genenames.org/data/hgnc_data.php?hgnc_id=15917">PLCB1</a>; EIEE12; PI-PLC; PLC-154; PLC-I; PLC154; PLCB1A; PLCB1B</span></td>
</tr>
<tr class="">
<th style="background-color: #c3fdb8">External IDs</th>

您会发现在标识符外部ID之间有一个没有文本,只有一个<a>标签的<th>标签:

<th style="background-color: #c3fdb8"><a href="/wiki/Human_Genome_Organisation" title="Human Genome Organisation">Symbols</a></th>

这个<th>没有文本内容,所以x.stringNone


当然,x.string 是空的,但是你如何解决这个问题呢?:-P - Martijn Pieters
1
@MartijnPieters:我正要回答,但你回答得太快了 :) - unutbu
最后一种情况呢,如果同时存在<th>和<a>标签呢? - sam
@sam:中间的<th>有一个<a>标签,但没有文本。这是标签x,其x.stringNone。使用x.findAll(text=True)(如MartijnPieters的答案中所示)来获取<a>标签内的文本。 - unutbu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接