现在的位置: 首页 > 综合 > 正文

Scrapy开发

2014年02月11日 ⁄ 综合 ⁄ 共 4697字 ⁄ 字号 评论关闭

最近要开发一个软件需要爬取网站信息,于是选择了python 和scrapy下面做一下简单介绍:Scrapy安装连接,scrapy官网连接

所谓网络爬虫,就是一个在网上到处或定向抓取数据的程序,当然,这种说法不够专业,更专业的描述就是,抓取特定网站网页的HTML数据。不过由于一个网站的网页很多,而我们又不可能事先知道所有网页的URL地址,所以,如何保证我们抓取到了网站的所有HTML页面就是一个有待考究的问题了。

一般的方法是,定义一个入口页面,然后一般一个页面会有其他页面的URL,于是从当前页面获取到这些URL加入到爬虫的抓取队列中,然后进入到新新页面后再递归的进行上述的操作,其实说来就跟深度遍历或广度遍历一样。

上面介绍的只是爬虫的一些概念而非搜索引擎,实际上搜索引擎的话其系统是相当复杂的,爬虫只是搜索引擎的一个子系统而已。下面介绍一个开源的爬虫框架Scrapy。

一、概述

Scrapy是一个用 Python 写的 Crawler Framework ,简单轻巧,并且非常方便,并且官网上说已经在实际生产中在使用了,不过现在还没有 Release 版本,可以直接使用他们的 Mercurial 仓库里抓取源码进行安装。

Scrapy 使用 Twisted 这个异步网络库来处理网络通讯,架构清晰,并且包含了各种中间件接口,可以灵活的完成各种需求。整体架构如下图所示:

绿线是数据流向,首先从初始 URL 开始,Scheduler 会将其交给 Downloader 进行下载,下载之后会交给 Spider 进行分析,Spider 分析出来的结果有两种:一种是需要进一步抓取的链接,例如之前分析的“下一页”的链接,这些东西会被传回 Scheduler ;另一种是需要保存的数据,它们则被送到 Item Pipeline 那里,那是对数据进行后期处理(详细分析、过滤、存储等)的地方。另外,在数据流动的通道里还可以安装各种中间件,进行必要的处理。

入门:

本文参考Scrapy Tutorial里面的文档,翻译出来加上自己的理解,供大家学习。

在本文中,我们将学会如何使用Scrapy建立一个爬虫程序,并爬取指定网站上的内容,这一切在Scrapy框架内实现将是很简单轻松的事情。

本教程主要内容包括一下四步:

1. 创建一个新的Scrapy Project
2. 定义你需要从网页中提取的元素Item
3. 实现一个Spider类,通过接口完成爬取URL和提取Item的功能
4. 实现一个Item PipeLine类,完成Item的存储功能

新建工程

首先,为我们的爬虫新建一个工程,首先进入一个目录(任意一个我们用来保存代码的目录),执行:

[python] view
plain
copy

  1. scrapy startproject Domz  

最后的Domz就是项目名称。这个命令会在当前目录下创建一个新目录Domz,结构如下:

[python] view
plain
copy

  1. dmoz/  
  2.    scrapy.cfg     
  3.    dmoz/  
  4.        __init__.py  
  5.        items.py  
  6.        pipelines.py  
  7.        settings.py  
  8.        spiders/  
  9.            __init__.py  

scrapy.cfg: 项目配置文件

items.py: 需要提取的数据结构定义文件
pipelines.py: 管道定义,用来对items里面提取的数据做进一步处理,如保存等
settings.py: 爬虫配置文件
spiders: 放置spider的目录

定义Item

在items.py里面定义我们要抓取的数据:

[python] view
plain
copy

  1. from scrapy.item import Item, Field  
  2.    
  3. class DmozItem(Item):  
  4.    title = Field()  
  5.    link = Field()  
  6.    desc = Field()  

这里我们需要获取dmoz页面上的标题,链接,描述,所以定义一个对应的items结构,不像Django里面models的定义有那么多种类的Field,这里只有一种就叫Field(),再复杂就是Field可以接受一个default值。

实现Spider

spider只是一个继承字scrapy.spider.BaseSpider的Python类,有三个必需的定义的成员

name: 名字,这个spider的标识
start_urls: 一个url列表,spider从这些网页开始抓取
parse(): 一个方法,当start_urls里面的网页抓取下来之后需要调用这个方法解析网页内容,同时需要返回下一个需要抓取的网页,或者返回items列表

所以在spiders目录下新建一个spider,dmoz_spider.py:

[python] view
plain
copy

  1. class DmozSpider(BaseSpider):  
  2.    name = "dmoz.org"  
  3.    start_urls = [  
  4.        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",  
  5.        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"  
  6.    ]  
  7.    
  8.    def parse(self, response):  
  9.        filename = response.url.split("/")[-2]  
  10.        open(filename, 'wb').write(response.body)  

提取Item

提取数据到Items里面,主要用到XPath提取网页数据:

scrapy有提供两个XPath选择器,HtmlXPathSelector和XmlXPathSelector,一个用于HTML,一个用于XML,XPath选择器有三个方法

select(xpath): 返回一个相对于当前选中节点的选择器列表(一个XPath可能选到多个节点)
extract(): 返回选择器(列表)对应的节点的字符串(列表)
re(regex): 返回正则表达式匹配的字符串(分组匹配)列表
一种很好的方法是在Shell里面对XPath进行测试:

[python] view
plain
copy

  1. scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/  

现在修改parse()方法看看如何提取数据到items里面去:

[python] view
plain
copy

  1. def parse(self, response):  
  2.       hxs = HtmlXPathSelector(response)  
  3.       sites = hxs.select('//ul/li')  
  4.       items = []  
  5.       for site in sites:  
  6.           item = DmozItem()  
  7.           item['title'] = site.select('a/text()').extract()  
  8.           item['link'] = site.select('a/@href').extract()  
  9.           item['desc'] = site.select('text()').extract()  
  10.           items.append(item)  
  11.       return items  

实现PipeLine

PipeLine用来对Spider返回的Item列表进行保存操作,可以写入到文件、或者数据库等。

PipeLine只有一个需要实现的方法:process_item,例如我们将Item保存到一个文件中:

[python] view
plain
copy

  1. def __init__(self):  
  2.     self.file = open('jingdong.txt''wb')  
  3.    
  4. def process_item(self, item, spider):  
  5.     self.file.write(item['title'] + '\t'+ item['link'] + '\t' + item['desc']+'\n')  

到现在,我们就完成了一个基本的爬虫的实现,可以输入下面的命令来启动这个Spider:

[python] view
plain
copy

  1. scrapy crawl dmoz.org  


Scrapy之URL解析与递归爬取:

前面介绍了Scrapy如何实现一个最简单的爬虫,但是这个Demo里只是对一个页面进行了抓取。在实际应用中,爬虫一个重要功能是”发现新页面”,然后递归的让爬取操作进行下去。

发现新页面的方法很简单,我们首先定义一个爬虫的入口URL地址,比如Scrapy入门教程中的start_urls,爬虫首先将这个页面的内容抓取之后,解析其内容,将所有的链接地址提取出来。这个提取的过程是很简单的,通过一个html解析库,将这样的节点内容提取出来,href参数的值就是一个新页面的URL。获取这个URL值之后,将其加入到任务队列中,爬虫不断的从队列中取URL即可。这样,只需要为爬虫定义一个入口的URL,那么爬虫就能够自动的爬取到指定网站的绝大多数页面。

当然,在具体的实现中,我们还需要对提取的URL做进一步处理:

1. 判断URL指向网站的域名,如果指向的是外部网站,那么可以将其丢弃
2. URL去重,可以将所有爬取过的URL存入数据库中,然后查询新提取的URL在数据库中是否存在,如果存在的话,当然就无需再去爬取了。

下面介绍一下如何在Scrapy中完成上述这样的功能。

我们只需要改写spider的那个py文件即可,修改parse()方法代码如下:

[python] view
plain
copy

  1. from scrapy.selector import HtmlXPathSelector  
  2.    
  3. def parse(self, response):  
  4.     hxs = HtmlXPathSelector(response)  
  5.     items = []  
  6.    
  7.     newurls = hxs.select('//a/@href').extract()  
  8.     validurls = []  
  9.         for url in newurls:  
  10.                 #判断URL是否合法  
  11.                 if true:  
  12.                         validurls.append(url)  
  13.    
  14.         items.extend([self.make_requests_from_url(url).replace(callback=self.parse) for url in validurls])  
  15.    
  16.         sites = hxs.select('//ul/li')  
  17.         items = []  
  18.         for site in sites:  

抱歉!评论已关闭.