本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关。

1. 简介

  Scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架,是目前 Python 中最受欢迎的爬虫框架之一,简单、方便、易上手。 它的应用领域很多,比如网络爬虫开发、数据挖掘、数据监测、自动化测试等。
  Scrapy 吸引人的地方在于它是一个框架,将 request (异步调度和处理)、下载器(多线程的 Downloader)、解析器(selector)和 twisted(异步处理)等封装在一起,任何人都可以根据需求方便的修改项目。它也提供了多种类型爬虫的基类,如 BaseSpider、sitemap 爬虫等,最新版本又提供了 Web2.0 爬虫的支持。
  官方网址是 https://scrapy.org/

2. Scrapy的安装

  使用 pip 直接安装:

1
pip install scrapy

  Scrapy 依赖的库比较多,比如 lxml、Twisted、pyOpenSSL 等等,我这边的建议是,先执行pip install scrapy命令,查看安装提示是否报错,如报错就根据报错信息将缺少的依赖用 pip 安装即可,这些对于开发人员是属于最基本的东西,所以我就不放详细过程了。

3. Scrapy的架构


  架构组件:

  • Engine(引擎): 处理整个系统的数据流处理、触发事务,是整个框架的核心、调度中心,相当于爬虫的 “大脑”。
  • Item(项目): 它定义了爬取结果的数据结构,爬取的数据会被赋值成该 Item 对象,也就是我们对数据进行后期过滤或存储的地方。
  • Scheduler(调度器): 简单来说就是一个队列,接受引擎发过来的请求并将其加入队列中,在引擎再次请求的时候将请求提供给引擎。
  • Downloader(下载器): 负责下载引擎发送过来的所有 request 请求,并将获得的 response 内容返回给引擎,再由引擎将 response 交管给 Spiders 来进行解析。
  • Spiders(爬虫): 负责处理所有的 response,从中解析数据,其内定义了爬取的逻辑和网页的解析规则 ,并将需要跟进的 URL 提交给引擎,再次进入 Scheduler。
  • Item Pipeline(项目管道): 就是我们封装去重类、存储类的地方,负责处理 Spiders 中获取到的数据并且进行后期的处理,过滤或者存储等等,当页面被爬虫解析所需的数据存入 Item 后,将被发送到 Pipeline,并经过几个特定的次序处理数据,最后存入本地文件或存入数据库。
  • Downloader Middlewares(下载器中间件): 可以当做是一个可自定义扩展下载功能的组件,是在引擎及下载器之间的特定钩子(specific hook),主要处理引擎与下载器之间的请求及响应。通过设置下载器中间件可以实现爬虫自动更换 user-agent、IP 等功能。
  • Spider Middlewares(爬虫中间件): 在引擎及 Spider 之间的特定钩子(specific hook),主要处理 Spider 的输入(response)和输出(items 及 requests)。自定义扩展、引擎和 Spider 之间通信功能的组件,通过插入自定义代码来扩展 Scrapy 功能。

  注意:所有模块(除引擎外)之间是相互独立的,只跟引擎进行交互,并不能直接互相交互。即各大组件(除引擎)之间一定是不能够直接进行交流的。

4. Scrapy的数据流程

  1. Engine 首先打开一个网站,找到处理该网站的 Spider ,并向该 Spider 获取第一个要爬取的 URL。
  2. Engine 从 Spider 处获取到第一个要爬取的 URL ,并通过 Scheduler 以 Request 的形式调度。
  3. Engine 向 Scheduler 请求下一个要爬取的 URL。
  4. Scheduler 返回下一个要爬取的 URL 给 Engine,Engine 将 URL 通过 Downloader Middlewares 转发给 Downloader下载。
  5. 一旦页面下载完毕, Downloader 生成该页面的 Response,并将其通过 Downloader Middlewares 发送给 Engine。
  6. Engine 从下载器中接收到 Response,并将其通过 Spider Middlewares 发送给 Spider 处理。
  7. Spider 处理 Response ,并返回爬取到的 Item 及新的 Request 给 Engine。
  8. Engine 将 Spider 返回的 Item 给 Item Pipeline,将新的 Request 给 Scheduler。
  9. 重复第2步到第8步,直到 Scheduler 中没有更多的 Request,Engine 关闭该网站,爬取结束。

  用户只需要将自己的爬取请求输入到对应的 Spider 中,同时将自己对文件的加工请求写入到对应的 Item Pipeline 中,所以一般使用 Scrapy 框架都只修改 Spider 和 Item Pipeline。

5. Scrapy开发流程

  下面以爬取慕课网免费课程(https://www.imooc.com/course/list)第一页信息为例概述开发 Scrapy 项目的流程。

5.1 创建项目

  进入待创建项目所在的文件夹下,执行scrapy startproject MyReptile命令创建项目,MyReptile是项目名称。


  在 PyCharm 中点击File,选择Open,找到刚刚创建的项目并打开:


  打开项目之后可以看到,我们创建的项目目录结构如下:

5.2 创建Spider

  Spider 是自定义的类,Scrapy 用它从网页中抓取数据,并解析抓取的结果。这个类必须继承 Scrapy 提供的 Spider 类scrapy.Spider,并定义 Spider 的名称和起始请求,以及怎样处理爬取结果的方法,
  进入刚刚创建的文件夹,执行命令scrapy genspider myspider www.imooc.com创建一个 Spider,myspider是 Spider 名称,www.imooc.com是网站域名。


  执行完毕之后,spiders文件夹下就生成了一个myspider.py文件:


  文件代码中有三个属性和一个方法:

  • name: 每个 spider 的名字,用来区分不同的 spider;
  • allowed_domains: 允许爬取的域名,如果初始或后续的请求链接不是这个域名下的就会被过滤掉;
  • start_urls: Spider 在启动时进行爬取的 URL 列表,也就是爬虫的起始地址,可以是多个 URL,一般是一个,后续的 URL 则从初始的 URL 获取到的 response 中提取;
  • parse(): 被调用时,每个初始 URL 完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。该方法负责解析返回的数据,提取数据(生成 item)以及生成需要进一步处理的 URL 的 Request 对象。

5.3 创建Item

  创建完 Spider 文件之后,接着定义一个容器来保存要爬取的数据,我们对items.py文件进行更改或者创建一个新的文件来定义 item 都行。
  创建 Item 需要继承 scrapy.Item 类,并且定义类型为 scrapy.Field 的字段。例如我们要爬取慕课网站课程的信息,包括课程名称,课程 URL,课程图片 URL,课程描述,学习人数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import scrapy

class MyreptileItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 课程名称
title = scrapy.Field()
# 课程url
url = scrapy.Field()
# 课程标题图片url
image_url = scrapy.Field()
# 课程描述
introduction = scrapy.Field()
# 学习人数
student = scrapy.Field()

5.4 编写Spider

  之后编写 Spider 中parse()的内容,parse()方法的参数 response 是 start_urls里 URL 爬取后的结果,所以在parse()中,我们可以直接对 response 的内容进行解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import scrapy

# 引入容器
from MyReptile.items import MyreptileItem

class MyspiderSpider(scrapy.Spider):
name = 'myspider'
allowed_domains = ['www.imooc.com']
start_urls = ['https://www.imooc.com/course/list']

# 填写爬写方法
def parse(self, response):
# 实例化一个容器保存爬取信息
item = MyreptileItem()
# 这部分是爬取部分,使用xpath的方式选择信息,具体方法根据网页结构而定
# 先获取每个课程的div
for box in response.xpath('//div[@class="course-card-container"]/a[@target="_blank"]'):
# 获取div中的课程标题
# strip() 方法用于移除字符串头尾指定的字符(默认为空格)
# extract()返回的所有数据,存在一个list里。extract_first()返回的是一个string,是extract()结果中第一个值。
item['title'] = box.xpath('.//h3/text()').extract()[0].strip()
# 获取每个div中的课程路径
item['url'] = 'http://www.imooc.com' + box.xpath('.//@href').extract()[0]
# 获取div中的标题图片地址
item['image_url'] = 'http:'+box.xpath('.//img[@data-original]').extract()[0]
# 获取div中的课程简介
#item['introduction'] = box.xpath('.//p[@class="course-card-desc"]/text()').extract()[0].strip()
item['introduction'] = box.xpath('.//p/text()').extract()[0].strip()
# 获取div中的学生人数
item['student'] = box.xpath('.//div[@class="course-card-info"]/span[2]/text()').extract()[0].strip()

# 返回信息
yield item

5.5 运行Spider

  执行完以上步骤后,我们可以执行命令scrapy crawl myspider运行爬虫,控制台就会给出爬取的数据。
  运行完 Scrapy 后,我们只在控制台看到了输出结果,我们可以利用 Scrapy 提供的 Feed Exports 轻松抓取输出的结果。 例如,我们想将结果保存成 csv 文件,可以在 Pycharm 的 Terminal 窗口中执行如下命令:crawl myspider -o myspider.csv
  输出格式还支持很多种,例如 json、 xml 、 pickle 、 marshal 等。 下面命令对应的输出分别为 json 、 xml 、 pickle 、 marshal 格式以及远程输出。

1
2
3
4
5
scrapy crawl myspider -o myspider.json
scrapy crawl myspider -o myspider.xml
scrapy crawl myspider -o myspider.pickle
scrapy crawl myspider -o myspider.marshal
scrapy crawl myspider -o ftp://user:pass@ftp.example.com/myspider.csv

  其中, ftp 输出需要正确配置用户名、密码、地址、输出路径,否则会报错。

参考文献

  【1】https://zhuanlan.zhihu.com/p/598764670
  【2】https://zhuanlan.zhihu.com/p/431078183?utm_id=0
  【3】https://blog.csdn.net/weixin_52245535/article/details/128695051
  【4】https://www.cnblogs.com/hsiang/p/15139627.html
  【5】https://m.biancheng.net/view/2027.html
  【6】https://www.zhihu.com/question/439914883/answer/2607880092
  【7】https://www.jianshu.com/p/063026368b3c
  【8】https://www.coonote.com/python-note/python-scrapy-intro.html
  【9】https://www.bilibili.com/video/BV1Db4y1m7Ho?p=90