
本文介绍了如何使用scrapy搭建一个简单的新闻爬虫。
使用scrapy搭建一个简单的新闻爬虫
前段时间面了几家公司的爬虫工程师岗位。所有的公司都会问的一个问题就是: 你使用过哪种爬虫框架?熟练度如何?是否能根据需求修改框架源码?有过分布式爬取的经验吗?
每次我遇到这种问题都感到很尴尬 —— 现在主流的爬虫框架大概有Scrapy, PySpider(Python); Nutch, Heritrix(Java) —— 这些我一个都没用过, 目前在线上运行的爬虫全是 requests + json/html/xml 解析。
至于分布式爬虫, 由于我目前接触的项目爬取量比较小(200+新闻app,300+新闻媒体微信公众号,300+微博的每日增量爬取), 每天的爬取量一台1核/1G/1M的阿里云足够胜任了, 暂时还用不到分布式爬取……
另外分布式爬取大多依赖上面提到的框架。
所以我做了一个很艰难的决定!把之前写过的爬虫!用scrapy重新实现一遍!
……
……
……
好吧,的确有点艰难……
所以先从其中一个开始吧。
下面会讲到如何使用scrapy 编写一个网易新闻app的爬虫。
* 我选择了一本参考书籍 《learning scrapy》, 但是这本书爬取的示例网站需要翻墙,所以我只看了框架相关的部分,实际网页解析之类的事情,在修改之前的爬虫的过程中解决。
1. 环境配置
我开发使用电脑的是Mac OSX, 但其实在实际的Python开发中, OSX使用的命令和ubuntu/debian大同小异。
- 安装scrapy
1 | sudo pip install scrapy |
- 创建工程文件夹
1 | scrapy startproject crawler |
scrapy startproject crawler 这行命令创建了一个新的工程文件夹,文件夹的结构使用tree命令展示出来了。
这些文件的主要作用:
(1) scrapy.cfg 项目的配置文件
(2) crawler/ :Python代码存放的位置
(3) crawler/items.py: items文件,定义一个(或多个)item的属性
(4) crawler/pipelines: 项目的管道文件。
在scrapy的官方文档中,pipeline的作用是:
- 清洗html数据;
- 验证已经爬取的数据(检查item是否有特定属性);
- 去重;
- 将爬取的item存进数据库。
(5) crawler/settings.py 配置文件
(6) crawler/spiders/ :爬虫文件的目录
2. 爬虫的编写
2.1 定义Item
简单来说,item的作用是装载抓取到的数据,是一种类似字典的容器。它的属性都会定义为scrapy.item.Field对象。
由于我们要写的是一个爬取新闻的app, 首先要明确的是我们需要的数据是什么,对于一个爬虫来说, 重要的是能否取我所需, 而不是尽我所能爬取对应网站的所有数据。
那么对于一个新闻爬虫,我们爬到的每一条新闻都需要一些什么样的数据呢?
- category 新闻类型(按照包含的媒体 分为图片/视频)
- source_type 新闻来源的类型(app, 微博, 微信, 网站, 电子报 etc.)
- source_name 新闻来源的名称
- news_sign 一条新闻的唯一标识(可以用于去重)
- views 浏览量
- title 标题
- url 新闻链接
- publish_time 发布时间
- text 新闻文本
- images 新闻图片的列表
以上就是我们需要的一些数据,我们按照上面的列表定义一个item
1 | from scrapy.item import Item, Field |
2.2 编写爬虫
Spider是爬虫的核心部分,用于从一个(或一系列)网站爬取数据。
要建立一个Spider,你必须为scrapy.spider.BaseSpider创建一个子类,并确定三个主要的、强制的属性:
- name 爬虫名称,必须是唯一的
- start_urls 起始页面
- parse() 解析爬取到的数据所用的方法, 接受的唯一参数是scrapy.Request方法请求得到的Response对象
2.2.1 关于二维爬取
一个典型的爬虫在两个方向移动:
- 水平方向:从一个索引页到另一个索引页
- 垂直方向:从索引页面到下一级页面(可能是下一级的索引,或者内容页面)
这个例子中水平方向是网易新闻的一页新闻到另一页,它返回的是一个个的新闻列表;
垂直方向是从新闻列表逐个进入新闻的内容界面
2.2.2 关于从网页(或者HTTP请求的Response Body)中提取数据
- html 网页的数据可以用 beautifusoup/xpath/正则 提取
- json 直接解析成Python的字典即可
- xml python也有对应的库用于解析
本文的爬虫会用到json和html解析,这里html使用xpath解析。
2.2.3 一个网易新闻app的Spider
1 | #coding:utf-8 |
2.2.4 爬虫代码代码的解析
上面提到过parse接受response作为参数。
这里重点说一下parse()方法中的两个生成器yeild,分别代表了垂直爬取和水平爬取。
首先说一下Request对象:
1 | class Request(object_ref): |
这里我们使用到了3个参数,url,callback,dont_filter。
我们第一次使用yeild是请求新闻的内容页面,这里的回调函数是parse_item(),用来提取单个新闻的信息;
第二次使用yeild是请求“下一页”的数据,这里的回调函数是parse(),当然从scrapy的官方文档来看,这里不传callback的话,默认的回调函数也是parse(),这样下一页的数据也会再一次通过parse()解析,实现水平方向上的爬取。
dont_filter是告诉Request不要对url进行过滤(去重)
下面的parse_item()就是html的解析了,这里不赘述。
3 爬取到的数据存储
这里我们用mongoDb对爬取到的数据进行存储。
3.1 配置MongoDB信息
在settings.py中设置MongoDB的信息
1 | # MongoDB settings |
这里server的ip隐去了
3.2 编写MongoDBPipeline
1 | from pymongo import MongoClient |
这个pipeline的作用包括上面提到的验证已经爬取的数据和将爬取的item存进数据库。去重暂时还没有做处理。
3.3 配置pipeline
在settings.py中添加下面的配置
1 | ITEM_PIPELINES = { |
可以看到这是一个字典,键为pipeline的路径,值为优先级(值越小越优先)。
4.总结
按照上面的步骤走下来,大概就能编写出一个网易新闻的爬虫。这个爬虫写出来,大概就迈出了重构以前爬虫代码的第一步了
后面碰到什么问题也会更新上来的,敬请期待