网络爬虫简介(5)— 链接爬虫

优采云 发布时间: 2020-05-31 08:01

  1.5.5 链接爬虫

  到目前为止,我们早已借助示例网站的结构特性实现了两个简单爬虫,用于下载所有已发布的国家(或地区)页面。只要这两种技术可用,就应该使用它们进行爬取,因为这两种方式将须要下载的网页数目降至最低。不过,对于另一些网站爬虫社区,我们须要使爬虫表现得更象普通用户,跟踪链接,访问感兴趣的内容。

  通过跟踪每位链接的方法,我们可以很容易地下载整个网站的页面。但是,这种方式可能会下载好多并不需要的网页。例如,我们想要从一个在线峰会中抓取用户帐号详情页,那么此时我们只须要下载帐号页,而不需要下载讨论贴的页面。本章使用的链接爬虫将使用正则表达式来确定应该下载什么页面。下面是这段代码的初始版本。

  import re

def link_crawler(start_url, link_regex):

""" Crawl from the given start URL following links matched by

link_regex

"""

crawl_queue = [start_url]

while crawl_queue:

url = crawl_queue.pop()

html = download(url)

if html is not None:

continue

# filter for links matching our regular expression

for link in get_links(html):

if re.match(link_regex, link):

crawl_queue.append(link)

def get_links(html):

""" Return a list of links from html

"""

# a regular expression to extract all links from the webpage

webpage_regex = re.compile("""<a[^>]+href=["'](.*?)["']""",

re.IGNORECASE)

# list of all links from the webpage

return webpage_regex.findall(html)

  要运行这段代码,只须要调用

  link_crawler

  函数,并传入两个参数:

  要爬取的网站

  URL

  以及用于匹配你想跟踪的链

  接的正则表达式。对于示例网

  站来说,我们想要爬取的是国家(或地区

  )列表索引页和国家(或地区)页面。

  我们查看站点可以获知索引页链接遵守如下格式:

  国家(或地区)页遵守如下格式:

  因此爬虫社区,我们可以用/(index|view)/这个简单的正则表达式来匹配这两类网页。当爬虫使用这种输入参数运行时会发生哪些呢?你会得到如下所示的下载错误。

  >>> link_crawler('http://example.python-scraping.com', '/(index|view)/')

Downloading: http://example.python-scraping.com

Downloading: /index/1

Traceback (most recent call last):

...

ValueError: unknown url type: /index/1

  正则表达式是从字符串中抽取信息的非常好的工具,因此我推荐每名程序员都应该“学会怎样阅读和编撰一些正则表达式”。即便这么,它们常常会特别脆弱,容易失效。我们将在本书后续部份介绍更先进的抽取链接和辨识页面的形式。可以看出,问题出在下载/index/1时,该链接只有网页的路径部份,而没有合同和服务器部份,也就是说这是一个相对链接。由于浏览器晓得你正在浏览那个网页,并且还能采取必要步骤处理那些链接,因此在浏览器浏览时,相对链接是才能正常工作的。但是,urllib并没有上下文。为了使urllib才能定位网页,我们须要将链接转换为绝对链接的方式,以便包含定位网页的所有细节。如你所愿,Python的urllib中有一个模块可以拿来实现该功能,该模块名为parse。下面是link_crawler的改进版本,使用了urljoin方式来创建绝对路径。

  from urllib.parse import urljoin

def link_crawler(start_url, link_regex):

""" Crawl from the given start URL following links matched by

link_regex

"""

crawl_queue = [start_url]

while crawl_queue:

url = crawl_queue.pop()

html = download(url)

if not html:

continue

for link in get_links(html):

if re.match(link_regex, link):

abs_link = urljoin(start_url, link)

crawl_queue.append(abs_link)

  当你运行这段代码时,会听到似乎下载了匹配的网页,但是同样的地点总是会被不断下载到。产生该行为的诱因是那些地点互相之间存在链接。比如,澳大利亚链接到了南极洲,而南极洲又链接回了德国,此时爬虫都会继续将这种URL装入队列,永远不会抵达队列尾部

  。要想避开重复爬取相同的链接,我们须要记录什么链接早已被爬取过。下面是更改后的link_crawler函数,具备了储存已发觉URL的功能,可以避免重复下载。

  def link_crawler(start_url, link_regex):

crawl_queue = [start_url]

# keep track which URL's have seen before

seen = set(crawl_queue)

while crawl_queue:

url = crawl_queue.pop()

html = download(url)

if not html:

continue

for link in get_links(html):

# check if link matches expected regex

if re.match(link_regex, link):

abs_link = urljoin(start_url, link)

# check if have already seen this link

if abs_link not in seen:

seen.add(abs_link)

crawl_queue.append(abs_link)

  当运行该脚本时,它会爬取所有地点,并且还能如期停止。最终,我们得到了一个可用的链接爬虫!

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线