scrapy简介:
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
演示:
为了让您了解Scrapy提供了什么功能,我们将提供一个Scrapy Spider的示例,并且以最简单的方式启动该spider。
以下的代码将跟进StackOverflow上具有投票数最多的链接,并且爬取其中的一些数据:
import scrapy class StackOverflowSpider(scrapy.Spider): name = 'stackoverflow' start_urls = ['http://stackoverflow.com/questions?sort=votes'] def parse(self, response): for href in response.css('.question-summary h3 a::attr(href)'): full_url = response.urljoin(href.extract()) yield scrapy.Request(full_url, callback=self.parse_question) def parse_question(self, response): yield { 'title': response.css('h1 a::text').extract()[0], 'votes': response.css('.question .vote-count-post::text').extract()[0], 'body': response.css('.question .post-text').extract()[0], 'tags': response.css('.question .post-tag::text').extract(), 'link': response.url, }
将上述代码存入到某个文件中,以类似于
stackoverflow_spider.py
命名, 并且使用 runspider
命令运行:
scrapy runspider stackoverflow_spider.py -o top-stackoverflow-questions.json
当命令执行完后,您将会得到 top-stackoverflow-questions.json
文件。 该文件以JSON格式保存了StackOverflow上获得upvote最多的问题, 包含了标题、链接、upvote的数目、相关的tags以及以HTML格式保存的问题内容, 看起来类似于这样(为了更容易阅读,对内容进行重新排版):
[{ "body": "... LONG HTML HERE ...", "link": "http://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array", "tags": ["java", "c++", "performance", "optimization"], "title": "Why is processing a sorted array faster than an unsorted array?", "votes": "9924" }, { "body": "... LONG HTML HERE ...", "link": "http://stackoverflow.com/questions/1260748/how-do-i-remove-a-git-submodule", "tags": ["git", "git-submodules"], "title": "How do I remove a Git submodule?", "votes": "1764" }, ...]
原理:
当您运行 scrapy runspider somefile.py
命令时,Scrapy尝试从该文件中查找Spider的定义,并且在爬取引擎中运行它。
Scrapy首先读取定义在 start_urls
属性中的URL(在本示例中,就是StackOverflow的top question页面的URL), 创建请求,并且将接收到的response作为参数调用默认的回调函数 parse
,来启动爬取。 在回调函数 parse
中,我们使用CSS Selector来提取链接。接着,我们产生(yield)更多的请求, 注册 parse_question
作为这些请求完成时的回调函数。
这里,您可以注意到Scrapy的一个最主要的优势: 请求(request)是 被异步调度和处理的 。 这意味着,Scrapy并不需要等待一个请求(request)完成及处理,在此同时, 也发送其他请求或者做些其他事情。 这也意味着,当有些请求失败或者处理过程中出现错误时,其他的请求也能继续处理。
在允许您可以以非常快的速度进行爬取时(以容忍错误的方式同时发送多个request), Scrapy也通过 一些设置 来允许您控制其爬取的方式。 例如,您可以为两个request之间设置下载延迟, 限制单域名(domain)或单个IP的并发请求量,甚至可以 使用自动限制插件 来自动处理这些问题。
最终, parse_question
回调函数从每个页面中爬取到问题(question)的数据并产生了一个dict, Scrapy收集并按照终端(command line)的要求将这些结果写入到了JSON文件中。