在Python中使用Mechanize打开多个页面

时间:2011-12-04 21:01:32

标签: python web-scraping mechanize

我正在尝试使用mechanize以特定格式打开多个页面。我想从某个页面开始,并让机械化跟踪链接中具有某个类或文本的所有链接。例如,根网址类似于

http://hansard.millbanksystems.com/offices/prime-minister

我希望关注页面上具有

等格式的每个链接
<li class='office-holder'><a href="http://hansard.millbanksystems.com/people/mr-tony-blair">Mr Tony Blair</a> May  2, 1997 - June 27, 2007</li>

换句话说,我希望关注每个具有“office-holder”类或URL中包含/ people /的链接。我已经尝试了以下代码,但它没有用。

import mechanize

br = mechanize.Browser()
response = br.open("http://hansard.millbanksystems.com/offices/prime-minister")
links = br.links(url_regex="/people/")

print links

我正在尝试打印链接,这样我就可以确保在编写更多代码之前获得正确的链接/信息。我得到的错误(?)是:

<generator object _filter_links at 0x10121e6e0>

任何指针或提示都表示赞赏。

1 个答案:

答案 0 :(得分:2)

这不是错误 - 这意味着Browser.links()返回生成器对象而不是列表。

iterator是一个“像列表一样”的对象,这意味着你可以做像

这样的事情
for link in links:
    print link

等等。但是你只能以它定义的顺序访问事物;你不一定能做link[5],一旦你经历了迭代器,就会用完它。

对于大多数用途,生成器只是一个迭代器,它不一定事先知道所有结果。这在generator expressions中非常有用,你实际上可以编写非常简单的函数来返回带有yield关键字的生成器:

def odds():
    x = 1
    while True:
        yield x
        x += 2

 os = odds()
 os.next() # returns 1
 os.next() # returns 3

这是一件好事,因为这意味着您不必一次将所有数据存储在内存中(odds()不可能......),如果您只需要第一个结果的一些元素,你不必费心计算其余的。 itertools module有一堆方便的函数来处理迭代器。


无论如何,如果您只想打印出links的内容,可以将其转换为带有list()函数的列表(它采用可迭代并返回其元素列表):

 print list(links)

或列出具有列表推导的字符串列表:

 print [l.url for l in list(links)]

或遍历其元素并将其打印出来:

 for l in links:
      print l.url

但请注意,执行此操作后,links将“耗尽” - 因此,如果您想要对其执行任何操作,则需要再次使用它。

也许最简单的选择就是立即把它变成一个列表而不用担心它根本就是迭代器:

links = list(br.links(url_regex="/people/"))

此外,您显然还没有获得具有所需课程的链接。可能有一些mechanize技巧在这里做“或”,但使用集合和生成器表达式这样做的一种很好的方法是这样的:

 links = set(l.url for l in br.links(url_regex='/people/'))
 links.update(l.url for l in br.get_links_with_class('office-holder'))

显然用真实的方式替换get_links_with_class来获取这些链接。然后,您最终会得到一组所有链接网址,其网址中包含/people/和/或具有类office-holder,并且没有重复项。 (请注意,您不能直接将Link对象放在集合中,因为它们不可清除。)