网络爬虫(web crawler)又称为网络蜘蛛(web spider)是一段计算机程序,它从互联网上按照必定的逻辑和算法抓取和下载互联网的网页,是搜索引擎的一个重要组成部分。通常的爬虫从一部分start url开始,按照必定的策略开始爬取,爬取到的新的url在放入到爬取队列之中,而后进行新一轮的爬取,直到抓取完毕为止。 php
咱们看一下crawler通常会遇到什么样的问题吧: html
海量网页的存在就意味着在必定时间以内,抓取只能的抓取其中的一部分,所以须要定义清楚抓取的优先级;网页更新的频繁,也就意味着须要抓取最新的网页和保证连接的有效性,所以一个更有可能带来新网页的列表页显得尤其重要;对于新闻网站,新的网站通常出如今首页,或者在指定的分类网页,可是对于淘宝来讲,商品的更新就很难估计了;动态网页怎么办呢?如今的网页大都有JS和AJAX,抓取已经不是简单的执行wget下载,现代的网页结构须要咱们的爬虫更加智能,须要更灵活的应对网页的各类状况。 java
所以,对一个通用的爬虫个,咱们要定义 python
抓取策略 web
使用URL的正则特征是一个简单但却很高效的模式;对于定向抓取,通常的网站的URL有必定的特征,好比可能仅仅关心 .html, .htm, .asp, .aspx, .php, .jsp, .jspx类型的网页;或者是若是能够获得目标网站的正则,则能够大大的下降抓取的数量;又或者咱们无需关心某一类网页,好比咱们不抓取bbs.taobao.com下面的内容;仅仅须要抓取淘宝的商品页面(http://item.taobao.com/item.htm?id=\d+ )。经过URL的正则能极大的下降抓取数量; 算法
也能够经过网页的文本特征来肯定;不过要复杂得多了,通常须要必定数量已知页面的训练集合,而后提取页面的文本特征,而后经过向量空间模型或者其其余基于主题词提取的模型计算目标网页和训练集网页的距离,决定是不是目标网页。 浏览器
更新策略 网络
Freshness:表示抓取到的网页是否已经被修改 多线程
Age:表示抓取的网页过时的时间 架构
对于更新来讲,目标是让平均age时间越小,freshness越高;通常的更新策略有两种:按期批量更新和按更新周期更新;按期批量更新指对一批URL,按照失效时间按期去刷新,按周期更新指的是按照页面更新变化频率而修正是更新频率,通常来讲,更新越频繁的网页更新也就越快。
抽取策略:
XPATH是一个简单直观,可是颇有效的一个方案,XPATH能精准的定位网页的任意一个位置,意味着咱们能够很精准的抽取页面上的任意位置,当面临不少网站的时候,固然配置XPATH就是一个很艰巨的任务,也许存在一个自适应的XPATH识别的方法。
JS和AJAX
在java下面,HtmlUnit是一个不错的解决方案,HtmlUnit是Junit 的扩展测试框架之一,该框架模拟浏览器的行为,开发者可使用其提供的API对页面的元素进行操做,套用官方网站的话HtmlUnit“是Java程序的浏览器”。HtmlUnit支持HTTP,HTTPS,COOKIE,表单的POST和GET方法,可以对HTML文档进行包装,页面的各类元素均可以被看成对象进行调用,另外对JavaScript的支持也比较好。通常来讲,HtmlUnit是在java环境下解决JS的很好的选择
WebKit包含一个网页引擎WebCore和一个脚本引擎JavaScriptCore,它们分别对应的是KDE的KHTML和KJS;目前比较主流的浏览器Google Chrome和Apple的safari,都是基于WebKit的内核写的。使用浏览器做为抓取能更好的模拟用户浏览的行为,可以自然的解决JS和AJAX等问题,问题可能就是性能是一个瓶颈,
抓取频率
同时开启N个线程抓取一个网站,相信很快就会被对方网站封掉;所以抓取的频率也很重要;抓取网站同时不对对方网站形成压力;在robot.txt协议里面定义Crawl-delay来肯定抓取的频率也是一种网站的通用的作法,对于通常的抓取而言,10到20秒抓取一次是一个比较保险的频率,也有提出10*t的抓取间隔(t是download时间)比较合理
定向抓取的框架
通用抓取架构,以下图
多线程下载模块(Multi-threaded downloader)
该模块通常包含:
调度模块(schedule)
调度模块是抓取系统的核心,调度模块从url队列里面选择一批url喂到下载模块下载;其中会涉及到
实例:使用开源的scrapy爬虫抓取B2C站点的商品
Scrapy(http://scrapy.org/)是基于Twisted的异步处理框架,纯python实现的爬虫框架,用户只须要定制开发几个模块就能够轻松的实现一个爬虫,用来抓取网页内容以及各类图片,很是之方便,如今咱们以scrapy为例子,简单配置一个抓取商品的例子。
Scrapy的安装请参考 http://doc.scrapy.org/intro/install.html#intro-install
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
fromscrapy.selectorimportHtmlXPathSelector
fromscrapy.spiderimportBaseSpider
fromscrapy.contrib.linkextractors.sgmlimportSgmlLinkExtractor
fromscrapy.utils.urlimporturljoin_rfc
fromscrapy.httpimportRequest
classMySpider(BaseSpider):
name='test'
allowed_domains=['xxxx.com']
start_urls=[
]
download_delay=10
defparse(self, response):
forlinkinSgmlLinkExtractor(allow=" product.htm\?id=\d+").extract_links(response):
yieldRequest(link.url,callback=self.parse_detail)
hxs=HtmlXPathSelector(response)
forurlinhxs.select('//a/
@href ').extract():
url= self._urljoin(response,url)
#print url
yieldRequest(url, callback=self.parse)
defparse_detail(self, response):
hxs=HtmlXPathSelector(response)
what_u_want=hxs.select("/xpath/text()").extract()[0]
print'url=',response.url, what_u_want.strip()
return
def_urljoin(self, response, url):
"""Helper to convert relative urls to absolute"""
returnurljoin_rfc(response.url, url, response.encoding)
|
最后,在工程目录里面执行 scrapy crawl mycrawler
简单几步,咱们就能够抓取获得一个站点想要的页面了,而且能够抽取指定xpath的内容。
一个简单的定向爬虫就搭建起来了,关键是一个可以大规模的分布式的爬虫多是一个挑战,后续再进一步介绍如何在分布式环境进行大规模的抓取,以及抓取遇到的一些更为棘手的问题