Spider-five

一、Scrapy框架

1. Scrapy框架主要组成

a. Scrapy三个对象: request请求对象、response响应对象、item数据对象(字典)

b. Scrapy五个核心组件:
Spider爬虫组件、构建爬虫的起始请求并交给调度器, 解析响应提取数据,交给管道保存。
Engine引擎组件、调用各个组件执行功能,并接收返回值和传递参数
Scheduler调度器、调度器请求去重并临时存储请求,交给下载器发送请求
Downloader下载器、下载发送请求,返回响应交给爬虫解析
Pipeline管道、保存数据

c. Scrapy两个可选中间件:
DownloaderMiddlewaresSpider下载中间件、处理反爬相关操作
SpiderMiddlewaresSpider中间件、请求交给调度器之前的特殊处理。

d. Scrapy框架流程: 爬虫组件 -> 引擎组件 -> 调度器 -> 引擎组件 -> 下载器 -> 引擎组件 -> 爬虫组件
若下载器返回的是请求时: -> 引擎组件 -> 调度器 -> 引擎组件 -> 下载器 -> 引擎组件 -> 爬虫组件
若下载器返回的是item对象: -> 引擎组件 -> 管道


补充:
Spider爬虫组件构建起始请求的url、xpath解析提取响应对象的数据
Scheduler调度器所有请求完毕Spider就会终止
组件之间存在数据交互,可使用中间件进行外部扩展

 

 

2. 拟人化流程

1> 引擎 :Hi! Spider , 老大要处理哪⼀个⽹站?把第⼀批需要处理的URL请求给我吧。
2> Spider :给你,第⼀批URL "http://www.baidu.com/"

3> 引擎 :Hi! 调度器 ,我这有request请求你帮我去重⼊队⼀下。
4> 调度器 :正在处理你等⼀下...好的,处理好了。
5> 引擎 :Hi! 调度器 ,把你去重好的request请求给我。
6> 调度器 :给你,这是我去重好的request

7> 引擎 :Hi!下载器,你按照⽼⼤的 下载中间件 的设置帮我下载⼀下这个request请求,
8> 下载器 :稍等... 行了给你,这是下载好的响应。
(如果失败:sorry,这个请求下载失败了。然后 引擎 告诉 调度器 : 这个request下载失败了,你放到请求队列里,我待会⼉再找你要重新下载。)

9> 引擎 :Hi! Spider ,这是下载好的响应,并且已经按照⽼⼤的 下载中间件 处理过了,你⾃⼰处理⼀下。
10> Spider :引擎 ,我这⾥有两个处理结果,这个是我需要跟进的URL请求,还有这个是我获取到的Item数据。

11> 引擎 :Hi ! 管道 我这⼉有个item数据你帮我保存⼀下。 调度器,这是需要跟进URL请求你帮我处理下,然后从我们第五步开始循环,直到获取完⽼⼤需要全部信息。

12> 管道+调度器 :好的,现在就做!

注意:只有当 调度器 没有request需要处理时,整个程序才会停⽌。(对于下载失败的请求,Scrapy也会重新下载。总共3次。)
框架默认的请求重试的时间是180s,可改变setting文件的 DOWNLOAD_TIMEOUT 变量的值

 

 

3. requests模块&Scrapy框架对比

requests模块的response
import reqeusts
response = reqeusts.get()
response.text # 返回 Unicode字符串
response.content # 网页原始编码字符串,也可以处理图片音视频

Scrapy框架的response
response.text # Unicode字符串
response.body # 网页原始编码字符串,也可以处理图片音视频


requests模块的xpath方法,返回的是已匹配到的 Unicode字符串
# 返回所有xpath匹配对象的列表
rsponse.xpath("//title/text()")

Scrapy框架的xpath方法,返回的是已匹配到对象的列表,Unicode字符串
# 取多值: 返回所有匹配结果的 字符串 列表(如果匹配成功,通过下标获取数据;如果匹配失败,返回空列表,下标获取数据抛异常)
rsponse.xpath("//title/text()").extract()
["", "", ""]

# 取单值:返回第一条符合匹配的字符串(如果匹配成功,返回字符串,如果匹配失败,返回 None)
rsponse.xpath("//title/text()").extract_first()


Scrapy框架支持大量的请求和高并发
Scrapy框架 : 发送请求、解析响应、并发处理、数据存储、请求去重(指纹-url、method、body=sha1字符串)、scrapy_redis支持分布式采集。

 


4. Scrapy使用的标准流程:

1> 新建项目
scrapy startproject Baidu

2> 进入项目代码,新建 item字段(编写items.py文件)

3> 新建爬虫
scrapy genspider baidu baidu.com

4> 编写爬虫代码(编写 baidu.py),提取数据:URL/item (如果是url则构建请求继续发送,如果是item则交给管道保存)

5> 编写pipeline.py文件

6> 更改settings.py的配置信息(并发量、User-Agent、启用管道)

7> 执行爬虫:
# 查看当前项目下的所有爬虫名
scrapy list
# 运行当前项目下的 指定爬虫(根据爬虫名执行)
scrapy crawl baidu
# 运行当前项目下的 指定爬虫(根据爬虫文件名执行)
#scrapy runspider baidu.py


传统开发:半年 ~ 1年, 所有功能开发完毕后再上线
敏捷开发:快速迭代更新, 先实现一部分功能就上线, 后期再持续更新迭代

 

 

5. Scrapy命令行:

scrapy bench:程序启动前组件的加载信息,爬虫运行时的采集信息,爬虫结束后的统计信息
scrapy startproject:创建一个新项目,外层是项目目录,内层有一个同名的代码目录
scrapy genspider:创建一个新爬虫,一个项目可有多个爬虫,scrapy genspider 爬虫名 爬虫可爬虫的域名,爬虫名不能和爬虫名同名
scrapy runspider:在创建项目的地方 运行爬虫 scrapy runspider 爬虫文件名
scrapy shell:以交互模式运行爬虫
scrapy view:在浏览器打开项目
scrapy list:查看爬虫名

scrapy crawl 爬虫名 -o 存储文件名:命令行保存数据
保存文件格式: json(有中括号)、jl(无中括号,按行存储)、xml、csv, 若需存储到数据库时,需要在管道文件中进行编写,并且在setting文件中启用管道

管道文件:
爬虫开启时,调用一次open_spider方法
爬虫运行时,每传递一个item就会调用一次process_item方法
爬虫关闭时,调用一次close_spider方法

 


6. setting.py文件:

BOT_NAME: 项目名
ROBOTSTXT_OBEY: 是否遵循robot协议,默认True遵循
CONCURRENT_REQUESTS: 最大请求并发量(主要用于指定下载器)
DOWNLOAD_DELAY: 下载延时,每一批请求的等待时间
CONCURRENT_REQUESTS_PER_DOMAIN: 根据特定域名定义并发量
CONCURRENT_REQUESTS_PER_IP: 据特定IP定义并发量
COOKIES_ENDBLED: 是否启用cookie,默认开启
DEFAULT_REQUEST_HEADERS: 默认的请求报头

**中间件都遵循:值越小优先级越高,值的范围 0-1000**
SPIDER_MIDDLEWARES: 爬虫中间件,值越小,优先级越高
DOWNLOADER_MIDDLEWARES: 下载中间件
ITEM_PIPELINES: 管道中间件
自定义的中间件需添加到setting文件中: 项目名.模块名.中间件类名

 

7. python补充知识点

锚点: 记录用户从何而来,url路径上的 #

生成器中 yield 作用:
通过yield返回数据,记录方法的状态
通过yield返回不同类型的数据
降低内存占用


python出现异常的方式:
代码错误
手动抛出异常, raise NameError("xxxx")
断言抛出异常,assert 布尔值


控制url查询字符串页码参数的自增量,json文件
提取'下一页按钮的链接',HTML文件
有固定的url地址,可将所有需要请求的url全部保存至start_url中,高并发

python2导入同级目录下的模块无需 . python3导入同级目录下的模块需要加上 .
实现 Python2 & python3 兼容的方法:
try:
from queue import Queue as SameName
except:
from Queue import Queue as SameName

from six.moves.queue import Queue

python有小到大组成: 函数 - 类 - 模块 - 包 - 类库 - 框架
meta字典作为response的属性,进行传递给下一个回调函数


进程、线程、协程:

IO密集(读写网络、磁盘、数据库等):使用多线程,因为io阻塞时,解释器会自动释放GIL尝试让其他线程工作。

互斥锁:一种让多个线程安全、有序的访问内存空间的机制。
GIL:从根本上杜绝了多个线程访问内存空间的安全隐患。

CPU密集(并行计算): 使用多进程,因为不需要切换任务,所以可以充分利用CPU的计算性能。

协程+猴子补丁(处理网络IO密集任务): 猴子补丁可以让Python底层的网络库在处理网络任务时,按异步的方式执行。

并行、并发、同步、异步、阻塞、非阻塞、多线程、多进程、协程、GIL

若方法中没有返回值,返回的None
多进程:并行 适用于CPU计算密集(并行计算)
多线程:并发,适用于io密集(网络、数据库、磁盘、文件)
协程+猴子补丁:处理网络io密集,将python底层的网络库改为 异步非阻塞,同步异步是执行方式,阻塞非阻塞是执行状态
互斥锁:一种让多个线程安全、有序的访问内存空间的机制。
GIL:从根本上杜绝 多个线程访问内存空间的安全隐患。

 

8. 采集多页/多级数据

多页采集数据:
1. 通过自增量控制页码值: 适合处理json文件响应的提取,没有下一页也不确定总页码值,但是可以一直自增偏移量控制页码的翻页,并判断响应是否有数据,来决定是否继续采集。

2. 通过提取 “下一页”连接方式处理多页采集:适合html文件的采集,依赖于网页的 a 标签提取,可以动态的获取所有页面数据,并再最后一页结束提取。

3. 将所有url地址全部保存到start_urls中(可以通过列表推导式、读取磁盘文件、数据库等),前置条件必须提供所有待发的url地址。


多级页面数据采集:
1. 不同页面的数据,保存在不同的item对象中

2. 不同页面的数据,保存在同一个item对象

 

原文地址:https://www.cnblogs.com/hsmwlyl/p/10636571.html