Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
scrapy 框架
- 高性能的网络请求
- 高性能的数据解析
- 高性能的持久化存储
- 深度爬取
- 全站爬取
- 分布式
- 中间件
- 请求传参
环境的安装
- mac/linux:pip install scrapy
- windows:
- pip install wheel
- twisted(异步相关,scrapy 的异步由twisted实现)
- 一定要在twisted安装成功的情况下执行后面的安装
环境测试: cmd中 输入scrapy 就安装成功
基本使用
新建一个工程:
终端下
scrapy startproject ProName
- 如果环境变量中没有,前面加
python -m scrapy startproject ProName
- 如果环境变量中没有,前面加
目录结构
- spiders(包):空包
修改配置文件(settings.py)
不遵从robots
ROBOTSTXT_OBEY = False
UA伪装
USER_AGENT = 'xxx'
日志等级的指定
LOG_LEVEL = 'ERROR'
LOG_FILE = './file.txt'
scrapy crawl spiderName --nolog
不推荐
CONCURRENT_REQUESTS = 16 默认开启的线程数量
AUTOTHROTTLE_START_DELAY = 3 开始下载时限速并延迟时间
AUTOTHROTTLE_MAX_DELAY = 60 高并发请求时最大延迟时间
cd ProName
: 进入到工程目录在spiders(爬虫文件夹)中创建一个爬虫文件
scrapy genspider spiderName www.xxx.com
- url 随意,后面再改
编写代码:主要代码会编写在爬虫文件中
- 爬虫类:父类(spider),后面还有4中爬虫类
- 爬虫文件的名称:当前爬虫源文件的唯一标识
- 通常注释掉 allowed_domains , 因为有些资源是存在别的域名的
- 起始的url列表:
- 列表中存放的url都可以被scrapy进行异步的网络请求
执行工程:
scrapy crawl spiderName
scrapy的数据解析
parse用作数据解析
参数:response 就是响应对象
extract、extract_first() 作用
scrapy的持久化存储
基于终端指令进行持久化存储
- 只可以将parse方法的返回值存储到本地的磁盘文件(指定形式后缀)中。
sracpy crawl spiderName -o filePath
- 局限性:
- 只能是parse的返回值
- 不能存到数据库中
基于管道进行持久化存储(推荐)
编码流程:
- 在爬虫文件中进行数据解析
- 在item类中定义相关的属性/字段
- 将解析到的数据存储到一个item类型的对象中
- Field类型视为一个万能的数据类型
- 将item类型的对象提交给管道
- 采用这样的规则是比手动存效率高的。
- 管道负责持久化存储
- yield item 将item提交给管道
- 管道类的process_item方法负责接收item,接收到后可以对item实现任意形式的持久化存储操作。
- return item 会将item传递给下一个即将执行的管道类。
- 重写父类方法 open_spider 该方法只会被执行一次,并且在爬虫之前执行
- 重写父类方法 close_spider 该方法只会被执行一次,并且在爬虫结束执行
- 在配置文件中开启管道。
- 300 表示的是优先级,数值越小优先级越高,可以定义多个管道类,这样优先级就会起作用。
note:一个管道类对应一种平台的持久化存储
例子:爬取抽屉网热榜
需求:爬取抽屉网热榜的作者和内容并做持久化存储
地址为:https://dig.chouti.com/
①修改spider
生成 spider 文件: scrapy genspider first www.xxx.com
补充数据解析的逻辑:
1 | # first.py |
②定义Item
定义Item,来将数据从 spider 传入管道并进行处理。
1 | # items.py |
③定义pipeline
定义 pipeline 来做持久化存储。
1 | # pipelines.py |
请求传参(深度爬取)
深度爬取:
- 爬取的数据没有存在同一张页面中。
如何实现请求传参:
例如:yield scrapy.Request(detail_url, callback=self.parse_detail, meta={'item': item})
meta= {}
: 可以将meta字典传递给 callback- 在 callback 接收
item = response.meta['item']
scrapy的五大核心组件
- 引擎依据接接受到的数据流的类型调用相关事务!
Scrapy运行流程
①:spider中的url被封装成请求对象交给引擎(每一个对应一个请求对象)
②:引擎拿到请求对象之后,将全部交给调度器
③:调度器过滤掉重复的请求对象(request)(重复的url),然后使用队列来存储非重复的请求对象,并将去重的消息队列回发给引擎
④:引擎将调度器调度出的请求对象交给下载器
⑤:下载器拿到该请求对象去互联网中下载数据
⑥:数据下载成功后会被封装到response中,随后response会被交给下载器
⑦:下载器将response交给引擎
⑧:引擎将response对象交给spiders(爬虫文件)
⑨:spiders拿到response后调用回调方法进行数据解析,解析成功后生成item,随后spiders将item交给引擎
⑩:引擎将解析好的item对象交给管道,管道拿到item后进行数据的持久化存储
引擎
所有组件的交互都要经过引擎,它控制着整个流程。
引擎定义了很多方法(parse,process_item),那它什么时候该执行这是如何做到的呢?
- 通过数据流来判断
作用:
- 接收所有事务流
- 对事务流进行判断来执行下一步
spider
封装成请求对象
调度器
- 调度请求对象
过滤器
- 过滤掉重复的请求对象
队列
- 存储非重复的请求的对象
实体管道
- 做持久化存储
下载器
- 将下载好的数据封装成response对象
- 异步体现在下载器这里
scrapy的异步也体现在下载器的异步,是建立在twisted这个高效的异步模型上的(其实整个框架都在建立在这个模型上的)。
scrapy的中间件
中间件有哪些?
下载中间件
引擎和下载器之间
爬虫中间件
引擎和spider之间
下载中间件的作用
- 批量拦截所有的请求和响应
为什么需要拦截请求?
- 篡改请求的头信息(headers)(UA)
- 建一个UA池
- request.headers[‘User-Agent’] = ‘xxx’
- 代理
- request.meta[‘proxy’] = ‘http://ip:port'
为什么拦截响应?
- 篡改响应数据
- 篡改响应对象(推荐)
1 | # middlewares.py |
爬取网易新闻
- 基于Scrapy框架中的Spider的递归爬取进行实现(Request模块递归回调parse方法)
(国内、国际、军事、航空、无人机) 新闻数据的标题和内容
分析:
每一个板块下对应的新闻数据都是动态加载出来的
会对5个板块的响应数据进行数据解析,但是板块对应的响应对象中是不包含动态加载的新闻数据的,意味着目前获取的每一个板块对应的响应对象是不满足需求的响应对象!!!
将不满足需求的5个响应对象篡改(工程中一共有1 + 5 + n),修改成满足需求的
- 找到指定的5个不满足需求的响应对象(中间件中完成)
- 使用selenium加载动态数据,获取标题和新闻详情的url
持久化存储:
mysql
redis
完整代码如下:
- wangyi.py
1 | # wangyi.py |
- items.py
1 | # items.py |
- middlewares.py
1 | # middlewares.py |
- pipelines.py
1 | # pipelines.py |
redis
- 启动server 启动cle
- 查看数据 keys *
- lpush key value
- lpush names 123
redis如果不可以写入字典:
- pip install - U redis == 2.10.6