如何使用Beautiful Soup提取树结构下的链接

时间:2012-08-28 08:33:10

标签: python beautifulsoup web-crawler

假设html网页是这样的:

<html>
    <div id="a">
        <div class="aa">
            <p>
                <a id="ff" href="#">ff</a>
                <a id="gg" href="#">gg</a>
            </p>
        </div>
        <div class="bb">
            <p>
                <a id="ff" href="#">ff</a>
            </p>
        </div>
    </div>
    <div id="b">
    </div>
</html>

使用后

soup = BeautifulSoup(webpage.read())

我有html网页,我想获得树结构下的链接:<html> - &gt; <div id="a"> - &gt; <div class="aa">

如何使用Beautiful Soup编写以下Python代码?

3 个答案:

答案 0 :(得分:2)

如果没有关于您的数据的更多信息,很难为您提供涵盖所有可能输入的简明解决方案。为了帮助您顺利进行,这是一个演练,希望能够为您提供适合您需求的解决方案。

以下内容将为我们<div id="a">(应该只有一个具有特定ID的元素):

top_div = soup.find('div', {'id':'a'})

然后我们可以继续使用class='aa'检索所有内部div(可能有多个):

aa_div = top_div.findAll('div', {'class':'aa'})

从那里,我们可以返回找到的每个div的所有链接:

links = [div.findAll('a') for div in aa_div]

请注意,links包含嵌套列表,因为div.findAll('a')将返回找到的a个节点的列表。有various ways to flatten such a list

这是一个遍历列表并打印出单个链接的示例:

>>> from itertools import chain
>>> for a in chain.from_iterable(links):
...   print a
... 
<a id="ff" href="#">ff</a>
<a id="gg" href="#">gg</a>

上面介绍的解决方案相当漫长。但是,通过更好地理解输入数据,可以实现更紧凑的解决方案。例如,如果数据与您显示的完全一致,并且总会有一个divclass='aa',那么解决方案可能只是:

>>> soup.find('div', {'class':'aa'}).findAll('a')
[<a id="ff" href="#">ff</a>, <a id="gg" href="#">gg</a>]

使用带有BeautifulSoup4

的CSS选择器

如果您使用的是较新版本的BeatifulSoup(版本4),您还可以使用提供.select() method支持的CSS selector。我在本回答开头提供的精细解决方案可以重写为:

soup.select("div#a div.aa a")

对于BeautifulSoup v3,您可以使用soupselect添加此功能。

但是,请注意文档中的以下声明(强调我的):

  

这对于了解CSS选择器语法的用户来说非常方便。你可以使用Beautiful Soup API完成所有这些工作。并且如果你只需要CSS选择器,你也可以直接使用lxml,因为它更快。但是这可以让你将简单的CSS选择器与Beautiful Soup API结合起来。

答案 1 :(得分:2)

我会这样做:

from BeautifulSoup import BeautifulSoup
import urllib

url = 'http://www.website.com'
file_pointer = urllib.urlopen(url)
html_object = BeautifulSoup(file_pointer)

link_list = []
links = html_object('div',{'class':'aa'})[0]('a')
for href in links:
    link_list.append(href['href'])

这将返回一个可以通过offset调用的“链接”列表:

link_1 = link_list[0]
link_2 = link_list[1]

或者,如果您想要与链接相关联的文本(即“Click Here”vs“/ Product/Store/Whatever.html”),您可以稍微更改相同的代码并生成所需的结果:

link_list = []
links = html_object('div',{'class':'aa'})[0]('a')
for text in links:
    link_list.append(text.contents[0])

同样,这将返回一个列表,因此您必须调用偏移量:

link_1_text = link_list[0]
link_2_text = link_list[1]

答案 2 :(得分:2)

我在官方美丽的汤文档中找到了这个信息:

for link in soup.find_all('a'):
    print(link.get('href'))
# http://example.com/elsie

您可以在此处查看有关美味汤的更多信息:http://www.crummy.com/software/BeautifulSoup/bs4/doc/

此致