
14. 收集链接
今天我们要准备完成我们的网络爬虫了!
首先我们需要从找到种子页上的所有链接开始,但不是像第二单元那样直接打印出来,而是需要将它们存储在一个列表中,这样你就可以利用它们继续前进。通过该列表中的所有链接来继续我们的抓取,只要有更多的页面可以抓取,就可以继续前进。
第一步定义一个过程get_all_links,它将一个代表网页上文字的字符串作为输入,并产生一个包含该网页上所有链接标签目标的URL的列表作为输出。
15. 获取所有链接
下面是第二单元的代码回顾:
def print_all_links(page):
while True:
url, endpos = get_next_target(page)
if url:
print url
page = page[endpos:]
else:
break
我们定义了一个过程,get_next_target,它将接收一个页面,搜索该页面上的第一个链接,并将其作为url的值返回,同时还返回引用末尾的位置,这样我们就知道在哪里继续。
然后,我们定义了一个过程,print_all_links,只要页面上有更多的链接,它就会一直进行下去。它将反复找到下一个目标,打印出来,并将页面推进到结束位置以上。
我们要做的是改变这种情况,不是每次找到一个URL就打印出来,而是要收集这些URL,这样我们就可以用它们来继续抓取并找到新的页面。要做到这一点,我们将创建一个我们找到的所有链接的列表。我们将print_all_links过程改为get_all_links,这样我们就可以使用输出,这将是一个链接列表,它将对应于我们最初打印出来的链接。
16. 链接
包含了三个链接标签,分别指向关于爬取、行走和飞行的页面(你可以通过点击浏览器中测试页面上的链接来检查它们)。
下面是get_all_links的操作方法。
links = get_all_links(get_page(‘http://www.link1.com/cs101x/index.html’)
print links [‘http://www.link1.com/cs101x/crawling.html’,
‘http://www.link1.com/cs101x/walking.html’, ‘http://www.link1.com/cs101x/flying.html’]
因为结果是一个列表,我们可以用它来继续抓取页面。你可以自己思考如何定义get_all_links,但如果你被卡住了,可以使用下面的测验来逐步完成我们需要做的改变。
== 测验:开始get_all_links
链接的初始值应该是多少?请记住,get_all_links 的目标是返回一个页面上所有链接的列表。你将使用 link 变量来引用一个包含所有我们找到的链接的列表。
def get_all_links(page):
links = []
while True:
url, endpos = get_next_target(page)
if url:
print url (strikthrough)
page = page[endpos:]
else:
break
17. 完成网络爬虫
此时,我们已经准备好完成网络爬虫的工作了。网络爬虫的目的是能够在种子页上找到链接,将它们做成一个列表,然后按照这些链接到新的页面,那里可能会有更多的链接,你希望你的网络爬虫能够跟踪这些链接。
为了做到这一点,网络爬虫需要跟踪所有的页面。使用变量tocrawl作为剩下要抓取的页面列表。使用变量crawled来存储抓取的页面列表。
- 抓取网页 Crawl Web
要启动crawl_web过程,需要提供tocrawl和crawl的初始值:
def crawl_web(seed):
tocrawl = [seed] - initialize this variable
crawl = [] - initialize this variable
- 抓取网络循环the Web Loop
下一步是写一个循环来进行抓取,只要有页面可以抓取,你就会继续前进。要做到这一点,你将使用一个 while 循环,以 tocrawl 作为测试条件。你可以使用 len(tocraw) == 0 来测试列表是否为空。还有一种更简单的方法,就是只用tocrawl来写。一个空列表(一个没有元素的列表)被解释为false,而每一个非空列表被解释为true。
在循环里面,我们需要选择一个页面来抓取。对于这个测验,你的目标是找出一个好的方法来完成这个任务。有很多方法可以做到这一点,但利用我们在本单元学到的东西,你可以用一行代码来实现,它既可以将页面初始化为我们要抓取的下一个页面,也可以将该页面从tocrawl列表中删除。
最好的方法是使用pop。pop是我们见过的唯一一个真正从列表中删除元素,并且还具有返回该元素的属性的东西。如果我们使用tocrawl.pop(),就会得到tocrawl列表中的最后一个元素,将该元素从列表tocrawl中删除,并将其赋值给变量page。
def crawl_web(seed):
tocrawl = [seed]
crawled = []
while tocrawl:
page = tocrawl.pop()
因为我们首先得到的是最后一个元素,所以我们实现的是所谓的深度优先搜索depth-first-search。这意味着当我们抓取网页时,我们将查看网页链中每个页面的第一个链接,直到我们到达终点。只有这样,我们才会开始查看第一页的第二个链接以及后续的每一页。如果我们的目标是快速获得一个好的网络语料库,那么做深度优先搜索可能不是最好的方式。如果我们完成搜索,无论按照什么顺序,我们都会找到同一组网页。如果我们不能够完成搜索,而对于真正的网络爬虫来说,有太多的网页要等到我们把它们全部抓取后才能返回结果,那么我们查看网页的顺序就很重要了。
- 抓取 If
下一步是管理链接中的循环问题。我们不想抓取已经抓取过的页面,所以我们需要的是测试页面是否被抓取的方法。
为了做出这样的决定,我们使用if。我们需要一个if的测试条件,只有在页面没有被抓取过的情况下,才会做我们抓取页面的事情。
我们应该只抓取还没有抓取的页面。crawled变量会跟踪我们已经抓取的页面。所以,我们要测试这个页面是否没有在抓取中。如果它的页面不在crawled中,那么我们就抓取。如果是,那么我们继续前进。在这个迭代中,我们在while循环中不做其他事情,继续检查下一个页面。
def crawl_web(seed):
tocrawl = [seed]
crawled = []
while tocrawl:
page = tocrawl.pop()
if page not in crawled:
...
- 完成抓取网页
现在你已经准备好完成我们的爬虫的编写了。写两行代码来更新tocrawl的值,以反映页面上发现的所有新链接,并更新crawled的值,以跟踪已被抓取的页面。
首先,我们需要将我们在一个页面上找到的所有链接添加到页面上,我们可以使用本单元前面一个测验中的联合过程来完成。使用append,我们可以跟踪我们已经抓取的页面。
def crawl_web(seed):
tocrawl = [seed]
crawled = []
while tocrawl:
page = tocrawl.pop()
if page not in crawled:
union (tocrawl, get_all_links(get_page(page)))
crawled.append(page)
return crawled
转载请注明:XAMPP中文组官网 » Python编程之数据爬虫抓取 下篇