所谓网络爬虫,就是一个在网上到处或定向抓取数据的程序,当然,这种说法不够专业,更专业的描述就是,抓取特定网站网页的HTML数据。不过由于一个网站的网页很多,而我们又不可能事先知道所有网页的URL地址,所以,如何保证我们抓取到了网站的所有HTML页面就是一个有待考究的问题了。一般的方法是,定义一个入口页面,然后一般一个页面会有其他页面的URL,于是从当前页面获取到这些URL加入到爬虫的抓取队列中,然后进入到新页面后再递归的进行上述的操作,其实说来就跟深度遍历或广度遍历一样。
Scrapy是一个基于Twisted,纯Python实现的爬虫框架,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便~
Scrapy 使用 Twisted这个异步网络库来处理网络通讯,架构清晰,并且包含了各种中间件接口,可以灵活的完成各种需求。整体架构如下图所示:
绿线是数据流向,首先从初始URL 开始,Scheduler 会将其交给 Downloader 进行下载,下载之后会交给 Spider 进行分析,Spider分析出来的结果有两种:一种是需要进一步抓取的链接,例如之前分析的“下一页”的链接,这些东西会被传回 Scheduler ;另一种是需要保存的数据,它们则被送到Item Pipeline 那里,那是对数据进行后期处理(详细分析、过滤、存储等)的地方。另外,在数据流动的通道里还可以安装各种中间件,进行必要的处理。
1.创建一个Scrapy项目:scrapy startproject 项目名
Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. T:>scrapy startproject tutorial T:>
这个命令会在当前目录下创建一个新目录tutorial,它的结构如下:
T: utorial>tree /f Folder PATH listing Volume serial number is 0006EFCF C86A:7C52 T:. │ scrapy.cfg │ └─tutorial │ items.py │ pipelines.py │ settings.py │ __init__.py │ └─spiders __init__.py
这些文件主要是:
- scrapy.cfg: 项目配置文件
- tutorial/: 项目python模块, 呆会代码将从这里导入
- tutorial/items.py: 项目items文件
- tutorial/pipelines.py: 项目管道文件
- tutorial/settings.py: 项目配置文件
- tutorial/spiders: 放置spider的目录
定义Item
Items是将要装载抓取的数据的容器,它工作方式像python里面的字典,但它提供更多的保护,比如对未定义的字段填充以防止拼写错误。
它通过创建一个scrapy.item.Item类来声明,定义它的属性为scrpy.item.Field对象,就像是一个对象关系映射(ORM).
在items.py文件中,定义一个scrapy.item.Item类,在其中定义我们想要从抓取到的网页数据中解析获取的数据的Field(scrpy.item.Field类型)
from scrapy.item import Item, Field class DmozItem(Item): title = Field() link = Field() desc = Field()
定义Spider
他们定义了用于下载的URL的初步列表,如何跟踪链接,以及如何来解析这些网页的内容用于提取items。
要建立一个Spider,你必须为scrapy.spider.BaseSpider创建一个子类,并确定三个主要的、强制的属性:
- name:爬虫的识别名,它必须是唯一的,在不同的爬虫中你必须定义不同的名字.
- start_urls:爬虫开始爬的一个URL列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些URLS开始。其他子URL将会从这些起始URL中继承性生成。
- parse():爬虫的方法,调用时候传入从每一个URL传回的Response对象作为参数,response将会是parse方法的唯一的一个参数,这个方法负责解析返回的数据、匹配抓取的数据(解析为item)并跟踪更多的URL。
为了让我们的爬虫工作,我们返回项目主目录执行以下命令
T: utorial>scrapy crawl dmoz
crawl dmoz 命令从dmoz.org域启动爬虫。 你将会获得如下类似输出
T: utorial>scrapy crawl dmoz 2012-07-13 19:14:45+0800 [scrapy] INFO: Scrapy 0.14.4 started (bot: tutorial) 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled extensions: LogStats, TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, RedirectMiddleware, CookiesMiddleware, HttpCompressionMiddleware, ChunkedTransferMiddleware, DownloaderStats 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled item pipelines: 2012-07-13 19:14:45+0800 [dmoz] INFO: Spider opened 2012-07-13 19:14:45+0800 [dmoz] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080 2012-07-13 19:14:46+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> (referer: None) 2012-07-13 19:14:46+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (referer: None) 2012-07-13 19:14:46+0800 [dmoz] INFO: Closing spider (finished) 2012-07-13 19:14:46+0800 [dmoz] INFO: Dumping spider stats: {'downloader/request_bytes': 486, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 13063, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2012, 7, 13, 11, 14, 46, 703000), 'scheduler/memory_enqueued': 2, 'start_time': datetime.datetime(2012, 7, 13, 11, 14, 45, 500000)} 2012-07-13 19:14:46+0800 [dmoz] INFO: Spider closed (finished) 2012-07-13 19:14:46+0800 [scrapy] INFO: Dumping global stats: {}
注意包含 [dmoz]的行 ,那对应着我们的爬虫。你可以看到start_urls中定义的每个URL都有日志行。因为这些URL是起始页面,所以他们没有引用(referrers),所以在每行的末尾你会看到 (referer: <None>).
有趣的是,在我们的 parse 方法的作用下,两个文件被创建:分别是 Books 和 Resources,这两个文件中有URL的页面内容。
发生了什么事情?
Scrapy为爬虫的 start_urls属性中的每个URL创建了一个 scrapy.http.Request 对象 ,并将爬虫的parse 方法指定为回调函数。
这些 Request首先被调度,然后被执行,之后通过parse()方法,scrapy.http.Response 对象被返回,结果也被反馈给爬虫。