第1章 Scrapy简介
欢迎来到你的Scrapy之旅。通过本书,我们旨在将你从一个只有很少经验甚至没有经验的Scrapy初学者,打造成拥有信心使用这个强大的框架从网络或者其他源爬取大数据集的Scrapy专家。本章将介绍Scrapy,并且告诉你一些可以用它实现的很棒的事情。
1.1 初识Scrapy
Scrapy是一个健壮的网络框架,它可以从各种数据源中抓取数据。作为一个普通的网络用户,你会发现自己经常需要从网站上获取数据,使用类似Excel的电子表格程序进行浏览(参见第3章),以便离线访问数据或者执行计算。而作为一个开发者,你需要经常整合多个数据源的数据,但又十分清楚获得和抽取数据的复杂性。无论难易,Scrapy都可以帮助你完成数据抽取的行动。
以健壮而又有效的方式抽取大量数据,Scrapy已经拥有了多年经验。使用Scrapy,你只需一个简单的设置,就能完成其他爬虫框架中需要很多类、插件和配置项才能完成的工作。快速浏览第7章,你就能体会到通过简单的几行配置,Scrapy可以实现多少功能。
从开发者的角度来说,你也会十分欣赏Scrapy的基于事件的架构(我们将在第8章和第9章中对其进行深入探讨)。它允许我们将数据清洗、格式化、装饰以及将这些数据存储到数据库中等操作级联起来,只要我们操作得当,性能降低就会很小。在本书中,你将学会怎样可以达到这一目的。从技术上讲,由于Scrapy是基于事件的,这就能够让我们在拥有上千个打开的连接时,可以通过平稳的操作拆分吞吐量的延迟。来看这样一个极端的例子,假设你需要从一个拥有汇总页的网站中抽取房源,其中每个汇总页包含100个房源。Scrapy可以非常轻松地在该网站中并行执行16个请求,假设完成一个请求平均需要花费1秒钟的时间,你可以每秒爬取16个页面。如果将其与每页的房源数相乘,可以得出每秒将产生1600个房源。想象一下,如果每个房源都必须在大规模并行云存储当中执行一次写入,每次写入平均需要耗费3秒钟的时间(非常差的主意)。为了支持每秒16个请求的吞吐量,就需要我们并行运行1600 × 3 = 4800次写入请求(你将在第9章中看到很多这样有趣的计算)。对于一个传统的多线程应用而言,则需要转变为4800个线程,无论是对你,还是对操作系统来说,这都会是一个非常糟糕的体验。而在Scrapy的世界中,只要操作系统没有问题,4800个并发请求就能够处理。此外,Scrapy的内存需求和你需要的房源数据量很接近,而对于多线程应用而言,则需要为每个线程增加与房源大小相比十分明显的开销。
简而言之,缓慢或不可预测的网站、数据库或远程API都不会对Scrapy的性能产生毁灭性的结果,因为你可以并行运行多个请求,并通过单一线程来管理它们。这意味着更低的主机托管费用,与其他应用的协作机会,以及相比于传统多线程应用而言更简单的代码(无同步需求)。
1.2 喜欢Scrapy的更多理由
Scrapy已经拥有超过5年的历史了,成熟而又稳定。除了上一节中提到的性能优势外,还有下面这些能够让你爱上Scrapy的理由。
- Scrapy能够识别残缺的HTML
你可以在Scrapy中直接使用Beautiful Soup或lxml,不过Scrapy还提供了一种在lxml之上更高级的XPath(主要)接口——selectors。它能够更高效地处理残缺的HTML代码和混乱的编码。
- 社区
Scrapy拥有一个充满活力的社区。只需要看看https://groups. google.com/ forum/#!forum/scrapy-users 上的邮件列表,以及Stack Overflow网站(http:// stackoverflow.com/questions/tagged/ scrapy)中的上千个问题就可以知道了。大部分问题都能够在几分钟内得到回应。更多社区资源可以从http://scrapy.org/ community/中获取到。
- 社区维护的组织良好的代码
Scrapy要求以一种标准方式组织你的代码。你只需编写被称为爬虫和管道的少量Python模块,并且还会自动从引擎自身获取到未来的任何改进。如果你在网上搜索,可以发现有相当多专业人士拥有Scrapy经验。也就是说,你可以很容易地找到人来维护或扩展你的代码。无论是谁加入你的团队,都不需要漫长的学习曲线,来理解你的自定义爬虫中的特别之处。
- 越来越多的高质量功能
如果你快速浏览发布日志(http://doc.scrapy.org/en/latest/ news.html),就会注意到无论是在功能上,还是在稳定性/bug修复上,Scrapy都在不断地成长。
1.3 关于本书:目标和用途
在本书中,我们的目标是通过重点示例和真实数据集教你使用Scrapy。大部分章节将专注于爬取一个示例的房屋租赁网站。我们选择这个例子,是因为它能够代表大多数的网站爬取项目,既能让我们介绍感兴趣的变动,又不失简单。以该示例为主题,可以帮助我们聚焦于Scrapy,而不会分心。
我们将从只运行几百个页面的小爬虫开始,最终在第11章中使用几分钟的时间,将其扩展为能够处理5万个页面的分布式爬虫。在这个过程中,我们将向你介绍如何将Scrapy与MySQL、Redis和Elasticsearch等服务相连接,使用Google的地理编码API找到我们示例属性中的位置坐标,以及向Apache Spark提供数据用于预测最影响房价的关键词。
你需要做好阅读本书多次的准备。你可能需要从略读开始,先理解其架构。然后阅读一到两章,仔细学习、实验一段时间,再进入后面的章节。如果你觉得自己已经熟悉了某一章的内容,那么跳过这一章也无需担心。尤其是如果你已经了解HTML和XPath,那么就没有必要花费太多时间在第2章上面了。不用担心,对你来说本书还有很多需要学习的内容。一些章节,比如第8章,将参考书和教程的元素结合起来,深入编程概念。这就是一个例子,我们可能会阅读某一章几次,在这中间允许我们有几个星期的时间实践Scrapy。你在继续阅读后续的章节,比如以应用为主的第9章之前,不需要完美掌握第8章中的内容。阅读后续的内容,有助于你理解如何使用编程概念,如果你愿意的话,可以回过头来反复阅读几次。
为使本书既有趣,又对初学者友好,我们已经试图做了平衡。不过我们不会做的一件事情是,在本书中教授Python。对于这一主题,目前已经有了很多优秀的书籍,不过我更加建议的是以一种轻松的心态来学习。Python如此流行的一个理由是因为它比较简单、整洁,并且阅读起来更近似于英文。Scrapy是一个高级框架,无论是初学者还是专家,都需要学习。你可以将其称之为“Scrapy语言”。因此,我会推荐你通过材料来学习Python,如果你发觉自己对于Python的语法比较迷惑,那么可以通过一些Python的在线教程或Coursera等为Python初学者开设的免费在线课程予以补充。请放心,即使你不是Python专家,也能够成为一名优秀的Scrapy开发者。
1.4 掌握自动化数据爬取的重要性
对于大多数人来说,掌握一门像Scrapy这样很酷的技术所带来的好奇心和精神上的满足,足以激励我们。令人惊喜的是,在学习这个优秀框架的同时,我们还能享受到开发过程始于数据和社区,而不是代码所带来的好处。
1.4.1 开发健壮且高质量的应用,并提供合理规划
为了开发现代化的高质量应用,我们需要真实的大数据集,如果可能的话,在开始动手写代码之前就应该进行这一步。现代化软件开发就是实时处理大量不完善数据,并从中提取出知识和有价值的情报。当我们开发软件并应用于大数据集时,一些小的错误和疏忽难以被检测出来,就有可能导致昂贵的错误决策。比如,在做人口统计学研究时,很容易发生仅仅是由于州名过长导致数据被默认丢弃,造成整个州的数据被忽视的错误。在开发阶段,甚至更早的设计探索阶段,通过细心抓取,并使用具有生产质量的真实世界大数据集,可以帮助我们发现和修复错误,做出明智的工程决策。
另外一个例子是,假设你想要设计Amazon风格的“如果你喜欢这个商品,也可能喜欢那个商品”的推荐系统。如果你能够在开始之前,先爬取并收集真实世界的数据集,就会很快意识到有关无效条目、停产商品、重复、无效字符以及偏态分布引起的性能瓶颈等问题。这些数据将会强迫你设计足够健壮的算法,无论是数千人购买过的商品,还是零销售量的新条目,都能够很好地处理。而孤立的软件开发,可能会在几个星期的开发之后,也要面对这些丑陋的真实世界数据。虽然这两种方法最终可能会收敛,但是为你提供进度预估承诺的能力以及软件的质量,都将随着项目进展而产生显著差别。从数据开始,能够带给我们更加愉悦并且可预测的软件开发体验。
1.4.2 快速开发高质量最小可行产品
对于初创公司而言,大规模真实数据的集甚至更加必要。你可能听说过“精益创业”,这是由Eric Ries创造的一个术语,用于描述类似技术初创公司这样极端不确定条件下的业务发展过程。该框架的一个关键概念是最小可行产品(Minimum Viable Product,MVP),这种产品只有有限的功能,可以被快速开发并向有限的客户发布,用于测试反响及验证业务假设。基于获得的反馈,初创公司可能会选择继续更进一步的投资,也可能是转向其他更有前景的方向。
在该过程中的某些方面,很容易忽视与数据紧密连接的问题,这正是Scrapy所能为我们做的部分。比如,当邀请潜在的客户尝试使用我们的手机应用时,作为开发者或企业主,会要求他们评判这些功能,想象应用在完成时看起来应该如何。对于这些并非专家的人而言,这里需要的想象有可能太多了。这个差距相当于一个应用只展示了“产品1”、“产品2”、“用户433”,而另一个应用提供了“三星 UN55J6200 55英寸电视机”、用户“Richard S”给出了五星好评以及能够让你直达产品详情页面(尽管事实上我们还没有写这个页面)的有效链接等诸多信息。人们很难客观判断一个MVP产品的功能性,除非使用了真实且令人兴奋的数据。
一些初创企业将数据作为事后考虑的原因之一是认为收集这些数据需要昂贵的代价。的确,我们通常需要开发表单及管理界面,并花费时间录入数据,但我们也可以在编写代码之前使用Scrapy爬取一些网站。在第4章中,你可以看到一旦拥有了数据,开发一个简单的手机应用会有多么容易。
1.4.3 Google不会使用表单,爬取才能扩大规模
当谈及表单时,让我们来看下它是如何影响产品增长的。想象一下,如果Google的创始人在创建其引擎的第一个版本时,包含了一个每名网站管理员都需要填写的表单,要求他们把网站中每一页的文字都复制粘贴过来。然后,他们需要接受许可协议,允许Google处理、存储和展示他们的内容,并剔除大部分广告利润。你能想象解释该想法并说服人们参与这一过程所需花费的时间和精力会有多大吗?即使市场非常渴望一个优秀的搜索引擎(事实正是如此),这个引擎也不会是Google,因为它的增长过于缓慢。即使是最复杂的算法,也不能弥补数据的缺失。Google使用网络爬虫技术,在页面间跳转链接,填充其庞大的数据库。网站管理员则不需要做任何事情。实际上,反而还需要一些努力才能阻止Google索引你的页面。
虽然Google使用表单的想法听起来有些荒谬,但是一个典型的网站需要用户填写多少表单呢?登录表单、新房源表单、结账表单,等等。这些表单中有多少会阻碍应用增长呢?如果你充分了解你的受众/客户,很可能已经拥有关于他们通常使用并且很可能已经有账号的其他网站的线索了。比如,一个开发者很可能拥有Stack Overflow和GitHub的账号。那么,在获得他们允许的情况下,你是否能够抓取这些站点,只需他们提供给你用户名,就能自动填充照片、简介和一小部分近期文章呢?你能否对他们最感兴趣的一些文章进行快速文本分析,并根据其调整网站的导航结构,以及建议的产品和服务呢?我希望你能够看到如何使用自动化数据抓取替代表单,从而更好地服务你的受众,增长网站规模。
1.4.4 发现并融入你的生态系统
抓取数据自然会让你发现并考虑与你付出相关的社区的关系。当你抓取一个数据源时,很自然地就会产生一些问题:我是否相信他们的数据?我是否相信获取数据的公司?我是否需要和他们沟通以获得更正式的合作?我和他们是竞争关系还是合作关系?从其他源获得这些数据会花费我多少钱?无论如何,这些商业风险都是存在的,不过抓取过程可以帮助我们尽早意识到这些风险,并制定出缓解策略。
你还会发现自己想知道能够为这些网站和社区带来的回馈是什么。如果你能够给他们带来免费的流量,他们应该会很高兴。另一方面,如果你的应用不能给你的数据源带来一些价值,那么你们的关系可能会很短暂,除非你与他们沟通,并找到合作的方式。通过从不同源获取数据,你需要准备好开发对现有生态系统更友好的产品,充分尊重已有的市场参与者,只有在值得努力时才可以去破坏当前的市场秩序。现有的参与者也可能会帮助你成长得更快,比如你有一个应用,使用两到三个不同生态系统的数据,每个生态系统有10万个用户,你的服务可能最终将这30万个用户以一种创造性的方式连接起来,从而使每个生态系统都获益。例如,你成立了一个初创公司,将摇滚乐与T恤印花社区关联起来,你的公司最终将成为两种生态系统的融合,你和相应的社区都将从中获益并得以成长。
1.5 在充满爬虫的世界里做一个好公民
当开发爬虫时,还有一些事情需要清楚。不负责任的网络爬虫会令人不悦,甚至在某些情况下是违法的。有两个非常重要的事情是避免类似拒绝服务(DoS)攻击的行为以及侵犯版权。
对于第一种情况,一个典型的访问者可能每几秒访问一个新的页面。而一个典型的网络爬虫则可能每秒下载数十个页面。这样就比典型用户产生的流量多出了10倍以上。这可能会使网站所有者非常不高兴。请使用流量限速将你产生的流量减少到可以接受的普通用户的水平。此外,还应该监控响应时间,如果发现响应时间增加了,就需要降低爬虫的强度。好消息是Scrapy对于这些功能都提供了开箱即用的实现(参见第7章)。
对于版权问题,显然你需要看一下你抓取的每个网站的版权声明,并确保你理解其允许做什么,不允许做什么。大多数网站都允许你处理其站点的信息,只要不以自己的名义重新发布即可。在你的请求中,有一个很好的User-Agent
字段,它可以让网站管理员知道你是谁,你用他们的数据做什么。Scrapy在制造请求时,默认使用BOT_NAME
参数作为User-Agent
。如果User-Agent
是一个URL或者能够指明你的应用名称,那么网站管理员可以通过访问你的站点,更多地了解你是如何使用他们的数据的。另一个非常重要的方面是,请允许任何网站管理员阻止你访问其网站的指定区域。对于基于Web标准的robots.txt
文件(参见http://www.google.com/robots.txt的文件示例),Scrapy提供了用于尊重网站管理员设置的功能(RobotsTxtMiddleware
)。最后,最好向网站管理员提供一些方法,让他们能说明不希望在你的爬虫中出现的东西。至少网站管理员必须能够很容易地找到和你交流及表达顾虑的方式。
1.6 Scrapy不是什么
最后,很容易误解Scrapy可以为你做什么,主要是因为数据抓取这个术语与其相关术语有些模糊,很多术语是交替使用的。我将尝试使这些方面更加清楚,以防止混淆,为你节省一些时间。
Scrapy不是Apache Nutch,也就是说,它不是一个通用的网络爬虫。如果Scrapy访问一个一无所知的网站,它将无法做出任何有意义的事情。Scrapy是用于提取结构化信息的,需要人工介入,设置合适的XPath或CSS表达式。而Apache Nutch则是获取通用页面并从中提取信息,比如关键字。它可能更适合于一些应用,但对另一些应用则又更不适合。
Scrapy不是Apache Solr、Elasticsearch或Lucene,换句话说,就是它与搜索引擎无关。Scrapy并不打算为你提供包含“Einstein”或其他单词的文档的参考。你可以使用Scrapy抽取数据,然后将其插入到Solr或Elasticsearch当中,我们会在第9章的开始部分讲解这一做法,不过这仅仅是使用Scrapy的一个方法,而不是嵌入在Scrapy内的功能。
最后,Scrapy不是类似MySQL、MongoDB或Redis的数据库。它既不存储数据,也不索引数据。它只用于抽取数据。即便如此,你可能会将Scrapy抽取得到的数据插入到数据库当中,而且它对很多数据库也都有所支持,能够让你的生活更加轻松。然而Scrapy终究不是一个数据库,其输出也可以很容易地更改为只是磁盘中的文件,甚至什么都不输出——虽然我不确定这有什么用。
1.7 本章小结
本章介绍了Scrapy,给出了它能够帮你做什么的概述,并描述了我们认为的使用本书的正确方式。本章还提供了几种自动化数据抓取的方式,通过帮你快速开发能够与现有生态系统更好融合的高质量应用而获益。下一章将介绍HTML和XPath,这是两个非常重要的Web语言,我们在每个Scrapy项目中都将用到它们。