本节是 《Python爬虫从入门到进阶》课程中的一节,课程购买链接(PC访问需要微信扫码) ,目前已更新80% 课程
购买课程请扫码:
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。只需要编写很少的代码就能实现抓取功能,另外由于它底层用了twisted,性能也非常优越。使用Scrapy框架编写的抓取代码,可读性很强,非常利于维护,是现在最流行的抓取框架。
安装
pip install scrapy SQLAlchemy
SQLAlchemy之后我们会用到
一个简单爬虫
我们写一个简单地例子,抓取开发者头条最近5天feed页面的文章地址和标题。先抓包分析下怎么抓比较好。
(略过抓包过程, 课程视频中有..)
接着我们就可以写爬虫代码了:
from
好的习惯是先定义Item,这里每项包含标题和链接。start_urls就是要抓取的里面列表。重载了parse方法,里面做页面解析:我还是用xpath的方法。另外在parse里面我没有延伸,就是没有翻页或者解析出新的链接再抓取,一共就抓了这5个页面
接下来就是抓取,使用 runspider 就能运行了,不过头条要求使用一个正确的UA。所以在命令行用-s指定了USER_AGENT变量。另外-o表示把结果导出到toutiao.json文件中
USER_AGENT
在运行中通过DEBUG信息其实大家就可以看到抓到了什么,当然json文件里面就是最终结果。假如你的程序写的有问题,在运行过程中会抛错,看着堆栈改bug就好了。
上面就是Scrapy的一个基本用法了。可以感受到,我们写的代码非常少,就实现了一个异步的抓取和处理。说的再明确一点,你不需要等待一个任务完成,他们是一起抓取的,充分利用CPU时间,另外即使一些请求失败了,或者处理过程中出错了,其他请求还可以继续完成。
而且我这里使用ITEM定义结构,让这个项目更清晰好理解
爬虫工程
上面我们演示的是一个简单地小例子。事实上Scrapy更倾向于Django那样的的企业级用法。可以在命令行下非常容易的创建一个复杂的爬虫项目
我们看一下项目下的目录结构
# 创建一个叫做toutiao_project的项目
❯ tree toutiao_project
toutiao_project
├── scrapy.cfg
└── toutiao_project├── __init__.py├── items.py├── middlewares.py├── pipelines.py├── settings.py└── spiders├── __init__.py
scrapy.cfg是Scrapy的配置文件。item.py存放了一些抓取对象的schema,或者说Item是保存爬取到的数据的容器。 middlewares.py是Spider中间件,使用中间件可以在抓取过程中的对应事件钩子上加上额外的行为, 比如添加代理,自动登录等等。pipelines.py是项目管道,当Item在Spider中被收集之后,它将会被传递到Item Pipeline,会按照一定的顺序执行对Item的处理。常见的如去重,验证item值,将爬取结果保存到数据库中等等。上面说的scrapy.cfg是针对Scrapy框架的配置,settings.py是针对于项目本身的设置,比如用什么中间件、并发数量、UA、Pipelines等等。全部选项可以看官方文档,如果你要深入了解和使用这个框架,这些设置项都是应该了解的。spiders目录下就是具体的抓取代码
定义Item
接着我们把开发者头条的抓取的逻辑迁移到这种项目用法中。定义Item这个结构之前我们已经做过,我觉得无论你使用Scrapy的哪种方式:是一个小脚本去抓,还是一个很复杂的大项目去爬,都建议要有一个良好的schema结构,现在我们只是需要把ToutiaoItem放到items.py文件中
❯
这种Item很像ORM的用法,对吧。每个字段是一个Field。每种获取的数据都可以写成一个这样的Item类,它要继承scrapy.Item。
添加抓取逻辑
可以在spiders子目录下创建一个文件,从items.py里面import ToutiaoItem。这里要注意,我写全了import模块路径。
❯
代码文件的名字没有要求,关键是类中name的名字。
通过 Item Pipeline 把数据存到数据库
在之前的小例子中,我们只是把数据存在json文件中。这次我们把数据存到数据库,反正本地测试我就存进SQLite,而且由于用到SQLAlchemy,上线时直接改成MySQL或者PostgreSQL的DB_URL就好了。
顺便提一下去重,去重是一个基本的抓取优化,但是对于我们这个需求,feed里面肯定不会有重复的内容,所以就不考虑了
首先我们用SQLAlchemy写一个头条的模型
❯
除了toutiao这个模型还写了2个功能函数,一个是连接数据库的,一个是创建表的。DB_URL在配置文件中:
here
接着我们看pipelines.py:
❯
里面使用session的形式,需要在process_item方法内加上添加记录的逻辑。在__init__里面获得了engine,然后通过engine创建数据库。当然这个创建数据库的步骤可以只做一次,虽然重复执行也不会有什么影响.
接着需要在settings里面指定这个pipeline:
ITEM_PIPELINES
后面那个300表示执行的顺序, 值越小越靠前,下面说的中间件也是:同类中间件中,这个顺序值越小越先执行
项目配置
当然到这里还是不能抓取,是因为开发者头条要求我们使用一个正确的UA。所以要修改settings.py. 改一下USER_AGENT。这个ua是我个人电脑的UA。
USER_AGENT
设置中间件
接着我们看看中间件怎么用,在Scrapy中有 2 种中间件,
- 下载器中间件(Downloader Middleware)
- Spider中间件(Middleware)
一个是下载器中间件,在request/response之间。另外一个是Spider中间件,发生在spider处理过程中。我们先看一个下载器中间件的例子。之前我们在配置文件中指定了USER_AGENT, 但是ua只有一个。这里实现随机换一个正确UA的例子。
# pip install fake_useragent
其中用到的fake-useragent这个库会下载一个数据文件,可能需要想办法去国外下载下。每次调用会随机拿一个ua,避免了重复用一个。当然大家还可以扩展思路,有代理池的话,每次代理也随机换。
看settings.py里面对应中间件的配置:
DOWNLOADER_MIDDLEWARES
这里注意,其实scrapy里面其实已经实现了一个UserAgent的中间件,这样在settings里面指定USER_AGENT就能让抓取使用对应的ua了。不过既然我们实现了随机ua中间件,自带的那个就可以让他的执行顺序为None,让它不起作用了
Spider Middleware这种我们日常开发基本用不到,不过呢,为了演示我们这里就实现一个用logging模块记录日志的中间件,要不然scarpy默认的抓取过程debug日志很多,抓不到重点,使用这个日志中间件,可以很有针对性的了解抓取情况
import
这样就可以把抓取的内容写入日志,同时由于我们定制了logging模块的日志格式,日志中会记录时间。基于时间和结果可以有助于未来排查问题。接着我们要改一下settings.py设置
FILE_LOGGING_ENABLED
PS:如果不指定FILE_LOGGING_ENABLED这个中间件是不生效的。
中间件自带的其他方法其实在 startproject 时候创建的 middlewares.py 里面都有了,不了解的可以具体看看API,注意按需使用。
运行抓取
最后呢,我们就可以执行抓取了,在命令行运行:
❯ scrapy crawl toutiao
运行正常。接着来确认下程序正确性。首先看看SQLite中的数据:
".help"
这样就完成抓取和存入数据库啦。
接着看一下日志scrapy.log,里面已经可以看到对应的记录:
{
通过LoggingSpiderMiddleware,抓取结果都被写进了日志。
好啦,这个爬虫项目就完成了,我们相对完整的体验了Scrapy的用法。
什么情况下应该用Scrapy这类框架?
大部分优秀项目能出现的原因,都是作者或者团队在对过去已有的工作模式和轮子深入之后发现问题之后提出更先进的思想,并实现出来。框架非常好,比如作为web开发者,我不能不用flask django这类web框架,而爬虫框架嘛,利用成熟的框架基本能避免常见的坑。可以写非常少的代码就能实现抓取,其中的一些细节都被框架封装了,开发者不再需要关注,专心实现业务逻辑就好了。
不过我是不推荐用框架的,我不做运维的一个重要原因是不想做一个天天翻阅软件文档的运维,运维嘛,日常一个工作是搭建环境,用人家写好的东西,按文档运行起来,最多google一些最佳实践或者解决一些报错。但是我们是不知道它怎么实现的、运行原理是什么的。你用这种框架也是,比如flask, 就是按照人家规定你的玩法填东西就好了,填多了不过是个熟练工而已。
我在12-13年底写了很多的爬虫,每个通常都会尝试一些新的技术,后来我突然意识到,当你掌握了爬虫技能,爬一个还是爬一百个区别已经不大,量已经没有意义,关键是质了。
所以,我的建议是:
- 如果你是新学者,没有工作安排的话,我建议从零开始不要用框架。
- 如果已经写过可用的爬虫,但是还不能灵活运用,更多的是多了解我上面提到的那些技术,多造轮子。
- 如果你已经踩过该踩的坑,灵活运用,用什么都无所谓,造轮子意义不大。这个时候用scrapy是很好的选择。
再强调一次基础。千万别把自己在某些领域的能力限制在某个框架上,会影响你未来的发展。
延伸阅读
Scrapy是一个功能很齐全的抓取框架,支持的特性、配置项等非常多,需要花很多时间学习和熟悉。这里有几个延伸阅读的链接。第一个是Scrapy创始人自己搞的scrapinghub服务中的视频学习教程。应该是市面上最好的教程之一了,大家可以看看。
- https://learn.scrapinghub.com/scrapy/
- https://doc.scrapy.org/en/latest/intro/tutorial.html
欢迎关注「爱湃森Python」服务号(微信号ipaisen)获取更多内容哟