您的位置:首页 > 理论基础 > 计算机网络

开源python网络爬虫框架Scrapy

2013-12-12 16:57 771 查看


Twisted:Twisted Matrix 是一种用来进行网络服务和应用程序编程的纯 Python 框架,虽然 Twisted Matrix 中有大量松散耦合的模块化组件,但该框架的中心概念还是非阻塞异步服务器这一思想。Twisted的安装也非常简单,在这里直接下载windows平台下的相应版本即可:http://pypi.python.org/packages/2.7/T/Twisted/

zope.interface:在这里下载http://pypi.python.org/pypi/zope.interface/3.8.0#downloads。zope.interface没有提供windows平台下的exe版,只提供了windows平台下的egg包。

ez_setup:下载http://pypi.python.org/pypi/ez_setup,安装。将egg文件放置在{python安装目录}\Scripts目录下。

打开CMD并切换至scripts目录,easy_install zope.interface-3.8.0-py2.6-win32.egg安装。

w3lib:zope.interface问题解决之后还会提示缺少w3lib,下载http://pypi.python.org/pypi/w3lib后安装即可

libxml2:使用scrapy的html解析功能时,会提示你缺少libxml2,所以我们先把这个也装上,地址http://xmlsoft.org/sources/win32/python/,下载相应的版本即可。

至此就可以使用Scrapy玩spider了,大家可以根据文档写一个简单的爬虫试试,实际上使用scrapy做一个简易的爬虫甚至只需要几行代码就可以了,以后有空再详细说说使用方法,本文不做更多描述。

入门:

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

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

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

1.创建一个新的Scrapy Project

2.定义你需要从网页中提取的元素Item

3.实现一个Spider类,通过接口完成爬取URL和提取Item的功能

4.实现一个Item PipeLine类,完成Item的存储功能

新建工程

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

[python]view plaincopyprint?

scrapy startproject Domz

scrapy startproject Domz


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

[python]view plaincopyprint?

dmoz/

scrapy.cfg

dmoz/

__init__.py

items.py

pipelines.py

settings.py

spiders/

__init__.py

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


scrapy.cfg: 项目配置文件

items.py: 需要提取的数据结构定义文件

pipelines.py: 管道定义,用来对items里面提取的数据做进一步处理,如保存等

settings.py: 爬虫配置文件

spiders: 放置spider的目录

定义Item

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

[python]view plaincopyprint?

from scrapy.item import Item, Field

class DmozItem(Item):

title = Field()

link = Field()

desc = Field()

from scrapy.item import Item, Field class DmozItem(Item):   title = Field()   link = Field()   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 plaincopyprint?

class DmozSpider(BaseSpider):

name = "dmoz.org"

start_urls = [

"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",

"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"

]

def parse(self, response):

filename = response.url.split("/")[-2]

open(filename, 'wb').write(response.body)

class DmozSpider(BaseSpider):   name = "dmoz.org"   start_urls = [       "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",       "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"   ]    def parse(self, response):       filename = response.url.split("/")[-2]       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 plaincopyprint?

scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/[/code] 
现在修改parse()方法看看如何提取数据到items里面去:

[python]view plaincopyprint?

def parse(self, response):

hxs = HtmlXPathSelector(response)

sites = hxs.select('//ul/li')

items = []

for site in sites:

item = DmozItem()

item['title'] = site.select('a/text()').extract()

item['link'] = site.select('a/@href').extract()

item['desc'] = site.select('text()').extract()

items.append(item)

return items

def parse(self, response):      hxs = HtmlXPathSelector(response)      sites = hxs.select('//ul/li')      items = []      for site in sites:          item = DmozItem()          item['title'] = site.select('a/text()').extract()          item['link'] = site.select('a/@href').extract()          item['desc'] = site.select('text()').extract()          items.append(item)      return items


实现PipeLine

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

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

[python]view plaincopyprint?

def __init__(self):

self.file = open('jingdong.txt', 'wb')

def process_item(self, item, spider):

self.file.write(item['title'] + '\t'+ item['link'] + '\t' + item['desc']+'\n')

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


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

[python]view plaincopyprint?

scrapy crawl dmoz.org

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 plaincopyprint?

from scrapy.selector import HtmlXPathSelector

def parse(self, response):

hxs = HtmlXPathSelector(response)

items = []

newurls = hxs.select('//a/@href').extract()

validurls = []

for url in newurls:

#判断URL是否合法

if true:

validurls.append(url)

items.extend([self.make_requests_from_url(url).replace(callback=self.parse) for url in validurls])

sites = hxs.select('//ul/li')

items = []

for site in sites:

item = DmozItem()

item['title'] = site.select('a/text()').extract()

item['link'] = site.select('a/@href').extract()

item['desc'] = site.select('text()').extract()

items.append(item)

return items

from scrapy.selector import HtmlXPathSelector def parse(self, response):    hxs = HtmlXPathSelector(response)    items = []     newurls = hxs.select('//a/@href').extract()    validurls = []        for url in newurls:                #判断URL是否合法                if true:                        validurls.append(url)         items.extend([self.make_requests_from_url(url).replace(callback=self.parse) for url in validurls])         sites = hxs.select('//ul/li')        items = []        for site in sites:                item = DmozItem()                item['title'] = site.select('a/text()').extract()                item['link'] = site.select('a/@href').extract()                item['desc'] = site.select('text()').extract()                items.append(item)         return items
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: