Python,BeautifulSoup - <div>文本和<img/>属性的顺序正确</div>

时间:2013-12-15 02:36:46

标签: python html beautifulsoup

我想要使用BeautifulSoup运行一小段HTML。我已经有了基本的导航功能,但是这个让我很难过。

这是HTML的一个示例(完全成功):

<div class="textbox">
    Buying this item will cost you 
    <img align="adsbottom" alt="1" src="/1.jpg;type=symbol"/>
    silver credits and
    <img align="adsbottom" alt="1" src="/1.jpg;type=symbol"/>
    golden credits
</div>

使用img标签的'alt'属性我希望看到以下结果: 购买此商品将花费您1银奖和1金奖

我不知道如何顺序遍历div-tag。我可以执行以下操作来提取div-tag

中包含的所有文本
html = BeautifulSoup(string)
print html.get_text()

获取div-tag中包含的所有文本,但这会给我这样的结果: 购买此商品将花费您银奖和黄金信用

同样,我可以通过这样做从img-tags获取alt-attributes的值:

html = BeautifulSoup(string).img
print html['alt']

但当然这只给了我属性值。

如何以正确的顺序迭代所有这些元素?是否可以按连续顺序读取div元素中的文本和img-element的属性?

2 个答案:

答案 0 :(得分:7)

您可以遍历标记的所有子元素,包括文本;测试他们的类型,看看他们是Tag还是NavigableString个对象:

from bs4 import Tag

result = []
for child in html.find('div', class_='textbox').children:
    if isinstance(child, Tag):
        result.append(child.get('alt', ''))
    else:
        result.append(child.strip())

print ' '.join(result)

演示:

>>> from bs4 import BeautifulSoup, Tag
>>> sample = '''\
... <div class="textbox">
...     Buying this item will cost you 
...     <img align="adsbottom" alt="1" src="/1.jpg;type=symbol"/>
...     silver credits and
...     <img align="adsbottom" alt="1" src="/1.jpg;type=symbol"/>
...     golden credits
... </div>
... '''
>>> html = BeautifulSoup(sample)
>>> result = []
>>> for child in html.find('div', class_='textbox').children:
...     if isinstance(child, Tag):
...         result.append(child.get('alt', ''))
...     else:
...         result.append(child.strip())
... 
>>> print ' '.join(result)
Buying this item will cost you 1 silver credits and 1 golden credits

答案 1 :(得分:1)

这也可以通过单个XPath查询来完成:

//div[@class="textbox"]/text() | //div[@class="textbox"]/img/@alt

不幸的是,BeautifulSoup不支持XPath,但lxml不支持:

import lxml.html

root = lxml.html.fromstring("""
    <div class="textbox">
        Buying this item will cost you 
        <img align="adsbottom" alt="1" src="/1.jpg;type=symbol"/>
        silver credits and
        <img align="adsbottom" alt="1" src="/1.jpg;type=symbol"/>
        golden credits
    </div>
""")

pieces = root.xpath('//div[@class="textbox"]/text() | //div[@class="textbox"]/img/@alt')
print ' '.join(map(str.strip, pieces))