使用Scrapy构建自己的定制网络爬虫

爬虫(Web Spider or ),顾名思义:一个在网站之间互相游走的虫子,专好觅食各类页面数据。随着Spider技术门槛降低,爬虫也开始泛滥起来,很多时候爬虫变成了扒虫。然,技术本无善恶,全在用者之念。此处不做过多计较,我们当下要讨论也仅仅是定制一款自己的网络爬虫,仅此。

爬虫就Mitchell个人经验来说分为两大类:

  • 通用型网络爬虫:该类爬虫并无明确采集目标,每个能够爬及的页面都是其采集对象,除非满足系统指定条件,否则此类爬虫基本全年无休的辛勤劳作。最常见的就是搜索引擎的爬虫,如:Google,Baidu,Yahoo,Bing等
  • 专用型网络爬虫:这种爬虫仅针对自身偏好的网站或者主题作为采集目标,采集到的内容或涉及到的URL为此爬虫不感兴趣的,将被爬虫直接忽略,此类爬虫根据需要采集的目标多寡采集时间有所不同。如:各类垂直搜索站,金融爬虫,站点采集等

如果你是要构建一个通用型的网络爬虫,当前的并不太适合,而要做个专用型的网络爬虫,或者简单的收集某个站点信息,Scrapy还是能够胜任的,本文作为入门,为简单起见,只针对单个站点进行爬取。

 

基本技能要求

  • Python ,能读写Python代码是基础,不然定制无从谈起;
  • xpath,对于xpath也需要了解,数据的提取需要使用xpath来进行(也可以使用css来提取);
  • Python操作存储设备,Python操作文件,数据库中的某一类方式,可用来存储采集的数据(本文不涉及)

 

安装Scrapy

Scrapy是Python开发的爬虫系统,因此:

  • 必须要有Python 2.7+ 的运行环境
  • 同时请准备好pipsetuptools这两个包,将使你后继安装更加简单
  • lxml虽然在大部分Linux中已经有lxml,但安全起见,请检查,没有的话,请移步到lxml官网
  • OpenSSL这个除了Windows之外,其他系统应该都预装了的,不过在你装Python的时候,能免费赠送。
  • Windows下需要加菜,pywin32别忘记了,到sourceforge上找个适合自己版本吧(可能要*(此处[翻]字被屏蔽)墙)。

有了pip,我们就能使用pip来安装Scrapy,命令行下输入:

pip install Scrapy

针对国内这种和谐的网络环境,你很有可能无法顺利执行完上面这个命令。

此时,一个镜像站点也许能给你带来很大帮助 —— Python已经不再官方授权镜像,如果你信不过其他站点,*(此处[翻]字被屏蔽)墙(VPN或其他*(此处[翻]字被屏蔽)墙工具)将是你唯一的选择。

# 此处使用中科大 mirrors pip install -i https://pypi.mirrors.ustc.edu.cn/simple Scrapy

 如果是Windows,记得将Python和Python下面Scripts的路径加到PATH中。再装个pywin32。

安装好了Scrapy,我们就离成功定制进一步。

 

创建Scrapy爬虫

如果安装好了Scrapy,你应该是能够在命令行下直接访问scrapy命令的:

> scrapy  Scrapy 1.0.1 - no active project  Usage:   scrapy <command> [options] [args]  Available commands:   bench         Run quick benchmark test   commands   fetch         Fetch a URL using the Scrapy downloader   runspider     Run a self-contained spider (without creating a project)   settings      Get settings values   shell         Interactive scraping console   startproject  Create new project   version       Print Scrapy version   view          Open URL in browser, as seen by Scrapy    [ more ]      More commands available when run from project directory  Use "scrapy <command> -h" to see more info about a command

 首先切换到需要创建爬虫项目的目录下,使用startproject来创建爬虫项目:

## path/to/....是要切换到的目录路径 ## 创建myfirstspiderproject项目 ## Mitchell Chu ## Blog:http://blog.usepas.net/  >pushd path/to/create/spider/project >scrapy startproject myfirstspiderproject

这个时候将会在指定的目录下创建myfirstspiderproject的项目目录,该目录下的内容大致如下:

scrapy.cfg myfirstspiderproject/     __init__.py     items.py     pipelines.py     settings.py     spiders/         __init__.py

这仅是创建好了爬虫项目,还没有爬虫,因此还需要使用命令行创建一个爬虫:

## 切到项目目录内 ## 创建一个叫spider007的爬虫 ## Mitchell Chu ## Blog: http://blog.useasp.net/  >cd myfirstspiderproject >scrapy genspider spider007 crawlerdomain.com

此时目录变成了:

scrapy.cfg myfirstspiderproject/     __init__.py     items.py     pipelines.py     settings.py     spiders/         __init__.py         spider007.py 

会发现,多了一个spider007的文件,这就是我们的爬虫了。接下来我们的定制之旅也就围绕这个文件进行。

 

我们创建的spider007文件内容如下:

# -*- coding: utf-8 -*- import scrapy   class Spider007Spider(scrapy.Spider):     name = "spider007"     allowed_domains = ["crawlerdomain.com"]     start_urls = (         'http://www.crawlerdomain.com/',     )      def parse(self, response):         pass 

恩,等等,,,要定制之前,我们至少得知道我们的定制目标,来让我们来想想:

我们要采集那个网站? 恩,就用本站吧,域名:http://blog.useasp.net/

我们要采集什么内容?我们只需要文章标题!

恩,OK,大概的目标既定,开始定制吧。

首先,我们需要将allowed_domains改成我们要采集的网站了,至少也得让他出现在这个列表,不然会被scrapy过滤掉——没错,我们是专用型网络爬虫,不感兴趣的统统不要。

其次,start_urls也换成http://blog.useasp.net/吧,我们都要采集文章标题了,像Mitchell的这个博客小站,没有入口,是很难到的了的。

恩,先这么些,改好之后想下面这样:

# -*- coding: utf-8 -*- import scrapy   class Spider007Spider(scrapy.Spider):     name = "spider007"     allowed_domains = ["blog.useasp.net"]     start_urls = (         'http://blog.useasp.net/',     )      def parse(self, response):         pass 

现在,我们就有了一个采集Mitchell Chu‘s Blog的专用网络爬虫了! —— 不过只是爬,啥都没干。

我们还得取个数据不是?要标题,我们得到哪里找最快?

经过分析,应该是右侧的数据归档下面最快了,全部都有,进去的第一个页面就能获取到,应该属于最短有效路径了。

数据采集时,选取最快的方式获取数据能很大程度提升程序的性能,并有效降低对目标网站的压力。

恩,既然已经出来,我们理下思路:

  • 数据归档获取页面文章归档地址(非归档地址忽略)
  • 归档页面提取文章标题

 有了这个思路,我们就将思路放到parse里面:

# -*- coding: utf-8 -*- import scrapy   class Spider007Spider(scrapy.Spider):     name = "spider007"     allowed_domains = ["blog.useasp.net"]     start_urls = (         'http://blog.useasp.net/',     )      def parse(self, response):         """             提取页面URI,只要归档地址         """         for url in response.xpath(                 '//div[@class="links box-wrap"]' +                 '//a[starts-with(@href, "/archive/")]/@href').extract():             yield scrapy.Request(                                 response.urljoin(url),                                 self.parse_useasp_net_blog_title)      def parse_useasp_net_blog_title(self, response):         """             解析归档页面的文章标题             注意:             进入这的URL是归档页面             http://blog.useasp.net/archive/*         """         blog_title = response.xpath('//h4/a/text()').extract()         # extract出来的是数组.         print blog_title[0].encode('gb2312') 

说明:

为了清晰起见,我们将解析URI的功能放在了parse,而解析标题的单独放在了parse_useasp_net_blog_title里面。

在解析URI之后,我们生成了scrapy的Request对象,并返回给scrapy进行调度采集,response.urljoin()是用来生成绝对地址的方法,并告知Request,请求的页面使用parse_useasp_net_blog_title这个方法来解析。

这样,我们就获得了一个完整功能的爬虫了,它爬取blog.useasp.net网站的所有博文标题,并显示到命令行下。

让我们试试效果,在命令行下输入:

scrapy crawl spider007

等待片刻,我们将能够看到输出了:

Chrome卡死无响应的问题解决方法 Python函数的各种参数(含星号参数) Linux普通用户无法使用sudo处理及sudoers设置 MySql用户权限配置管理--查看,赋予,回收(GRANT,REVOKE)Linux下如何批量建立文件软连接(极简版) 2016-03-12 22:47:38 [scrapy] DEBUG: Crawled (200) <GET http://blog.useasp.net/archive/2014/05.aspx> (referer: http://blog.useasp.net/) 

 恩,这正是我们所要的,目标达成,完成了一次定制Scrapy的过程。

 

Scrapy调试

scrapy开发中,肯定不会像我们上面如此顺利,很多时候需要进行调试,我们可以在scrapy使用下面的命令进入shell模式,进行必要测试:

scrapy shell http://blog.useasp.net/

scrapy会选择spider007作为默认的spider,并请求提供的url,成功后,进入shell的环境:

2016-03-12 11:43:04 [scrapy] DEBUG: Crawled (200) <GET http://blog.useasp.net> (referer: None) [s] Available Scrapy objects: [s]   crawler    <scrapy.crawler.Crawler object at 0x00000000049BCC50> [s]   item       {} [s]   request    <GET http://blog.useasp.net> [s]   response   <200 http://blog.useasp.net> [s]   settings   <scrapy.settings.Settings object at 0x00000000049BCB70> [s]   spider     <Spider007Spider 'spider007' at 0x72bbf98> [s] Useful shortcuts: [s]   shelp()           Shell help (print this help) [s]   fetch(req_or_url) Fetch request (or URL) and update local objects [s]   view(response)    View response in a browser 2016-03-12 11:43:07 [root] DEBUG: Using default logger 2016-03-12 11:43:07 [root] DEBUG: Using default logger  In [1]:

进入shell后,我们就可以使用语法进行操作了:

In [2]: response.xpath('//h3/a/text()') Out[2]: [<Selector xpath='//h3/a/text()' data=u'C# HttpWebResponse\u4e0b\u8f7d\u9650\u901f'>,  <Selector xpath='//h3/a/text()' data=u'BitConverter.IsLittleEndian\u5728x86\u7684\u673a\u5668\u4e0a\u8fd4\u56defal'> ]  In [3]: response.xpath('//h3/a/text()').extract() Out[3]: [u'C# HttpWebResponse\u4e0b\u8f7d\u9650\u901f',  u'BitConverter.IsLittleEndian\u5728x86\u7684\u673a\u5668\u4e0a\u8fd4\u56defalse',  u'FLV\u97f3\u9891\u89c6\u9891\u6587\u4ef6\u7684\u52a0\u5bc6\u89e3\u5bc6\u65b9\u5f0f']

 是不是很方便?

使用完毕后,可以直接使用exit()退出shell即可。

 

现在开始,你也可以开始定制属于自己的了,试试吧。

Mitchell偷偷告诉你:要获取blog.useasp.net的blog其实不用再这么复杂的,本站有RSS的。仅用来作为scrapy试手的示例而已。

 

后记

本文只是对scrapy的使用的一个概况,仅涉及scrapy的基本功能,大部分时候需要对scrapy进行配置,启用DNS cache,Http Cache,job等来提升scrapy的性能,同时涉及定制pipeline,item,middleware等,留待Mitchell后继为你介绍吧。

 

参考

  1. scrapy帮助文档
  2. scrapy官方网站
Saturday, March 12, 2016 | 其他技术 编程语言

文章评论

  • # RE:使用Scrapy构建自己的定制网络爬虫
    怎么好文章没有人评论

发表评论

Please add 8 and 5 and type the answer here:

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。