为什么bs4会返回标签,然后将空列表返回给此find_all()方法?

时间:2014-10-14 20:05:39

标签: python html5 web-scraping beautifulsoup

US Census QFD我试图抓住比赛的百分比。我构建的循环超出了我的问题的范围,这涉及到此代码:

url = 'http://quickfacts.census.gov/qfd/states/48/48507.html'
#last county in TX; for some reason the qfd #'s counties w/ only odd numbers
page = urllib2.urlopen(url)
soup = BeautifulSoup(page)

c_black_alone = soup.find_all("td", attrs={'headers':'rp9'})[0] #c = county %
s_black_alone = soup.find_all("td", attrs={'headers':'rp9'})[1] #s = state %

它抓取html元素包括其标签,而不仅仅是其中的文本:

c_black_alone, s_black_alone

(<td align="right" headers="rp9 p1" valign="bottom">96.9%<sup></sup></td>,
 <td align="right" headers="rp9 p2" valign="bottom">80.3%<sup></sup></td>)

在上面^,我只想要元素中的%&... ...

此外,为什么

test_black = soup.find_all("td", text = "Black")

不返回与上面相同的元素(或其文本),而是返回一个空的bs4 ResultSet对象? (编辑:我一直关注文档,所以我希望这个问题看起来不太模糊......)

1 个答案:

答案 0 :(得分:1)

要从这些匹配中获取文字,请使用.text获取所有包含的文字:

>>> soup.find_all("td", attrs={'headers':'rp9'})[0].text
u'96.9%'
>>> soup.find_all("td", attrs={'headers':'rp9'})[1].text
u'80.3%'

由于两个原因,您的text搜索无法匹配任何内容:

  1. 文字字符串仅匹配整个包含的文本,而不是部分匹配。它仅适用于<td>Black</td>作为唯一内容的元素。
  2. 它将使用.string property,但仅当文本是给定元素的 only 子元素时才设置该属性。如果存在其他元素,则搜索将完全失败。
  3. 解决这个问题的方法是使用lambda代替;它将传递整个元素,您可以验证每个元素:

    soup.find_all(lambda e: e.name == 'td' and 'Black' in e.text)
    

    演示:

    >>> soup.find_all(lambda e: e.name == 'td' and 'Black' in e.text)
    [<td id="rp10" valign="top">Black or African American alone, percent, 2013 (a)  <!-- RHI225213 --> </td>, <td id="re6" valign="top">Black-owned firms, percent, 2007  <!-- SBO315207 --> </td>]
    

    这两个匹配都在<td>元素中有评论,使text匹配的匹配无效。