『第四周』Scrapy框架
文章目录
Scrapy框架
Scrapy是一个快速功能强大的网络爬虫框架
帮助文档:https://scrapy-chs.readthedocs.io/zh_CN/1.0/index.html
—什么是爬虫框架?
—爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。
—爬虫框架是一个半成品,能够帮助用户实现专业网络爬虫。
架构
组件(5+2结构:5个主体和2个中间键)
-
Scrapy Engine
控制所有模块之间的数据流;根据条件触发事件。(无需修改) -
调度器(Scheduler)
对所有爬取请求进行调度管理。(无需修改) -
下载器(Downloader)
根据请求下载网页。(无需修改) -
Spiders
向整个框架提供了最初始的访问链接,同时对每次爬取回来的内容进行解析,再次产生新的爬取请求,并且从内容中分析出提取出相关的数据。 -
Item Pipeline
以流水线方式处理Spider产生的爬取项。
由一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型。
可能操作包括:清理、检验和查重爬取项中的HTML数据、将数据存储到数据库。 -
下载器中间件(Downloader middlewares)
目的:实施Engine、Scheduler和Downloader之间进行用户可配置的控制。
功能:修改、丢弃、新增请求或响应。 -
Spider中间件(Spider middlewares)
目的:对请求和爬取项的再处理。
功能:修改、丢弃、新增请求或爬取项。
在这5个模块之间,数据包括用户提交的网络爬虫请求,以及从网络上获取的相关内容,在这些结构之间进行流动,形成数据流。
三条主要的数据流路径
第一条:
Spiders
→Engine
→Scheduler
-
引擎打开一个网站(open a domain),找到处理该网站的Spider并向该spider请求第一个要爬取的URL(s)。
-
引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler)以Request调度。
第二条:
Scheduler
→Engine
→Downloader
→Spiders
-
引擎向调度器请求下一个要爬取的URL。
-
调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)方向)转发给下载器(Downloader)。
-
一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(返回(response)方向)发送给引擎。
-
引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理。
第三条:
Spiders
→Engine
→Item Pipeline
-
Spider处理Response并返回爬取到的Item及(跟进的)新的Request给引擎。
-
引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度器。
-
(从第二步)重复直到调度器中没有更多地request,引擎关闭该网站。
从前到后,这个框架的入口是Spiders
,出口是Item Pipeline
其中Scheduler
/Engine
/Downloader
都是已有的功能实现
Spiders
/Item Pipeline
需要用户去配置
Request库和Scrapy框架比较
相同点:
-
两者都可以进行页面请求和肥取,Python爬虫的两个重要技术路线。
-
两者可用性都好,文档丰富,入门简单。
-
两者都没有处理js、提交表单、应对验证码等功能(可扩展)。
不同点:
Requests | Scrapy |
---|---|
页面级爬虫 | 网站级爬虫 |
功能库 | 框架 |
并发性考虑不足,性能较差 | 并发性好,性能较高 |
重点在于页面下载 | 重点在于爬虫结构 |
定制灵活 | 一般定制灵活,深度定制困难 |
上手十分简单 | 入门稍难 |
Scrapy爬虫的常用命令
Scrapy命令行格式
scrapy [options] [args]
Scrapy命令 ↑
命令 | 说明 | 格式 |
---|---|---|
startproject | 创建一个新工程 | scrapy startproject [dir] |
genspider | 创建一个爬虫 | scrapy genspider [options] |
settings | 获得爬虫配置信息 | scrapy settings [options] |
crawl | 运行一个爬虫 | scrapy crawl |
list | 列出工程中所有爬虫 | scrapy list |
shell | 启动URL调试命令行 | scrapy shell [url] |
Scrapy爬虫的命令行逻辑
为什么 Scrapy采用命令行创建和运行爬虫?
-
命令行(不是图形界面)更容易自动化,适合脚本控制。
-
本质上,Scrapy是给程序员用的,功能(而不是界面)更重要。
Scrapy爬虫的第一个实例
演示HTML页面地址:http://python123.io/ws/demo.html
文件名称:demo.html
步骤1:建立一个Scrapy爬虫工程
在选定的一个目录中打开cmd,输入scrapy startproject python123demo
会生成一个目录
└─python123demo → 外层目录
│ scrapy.cfg → 部署[^1]Scrapy爬虫的配置文件
│
└─python123demo → Scrapy框架的用户自定义Python代码
│ items.py → Items代码模板(继承类)
│ middlewares.py → Middlewares代码模板(继承类)
│ pipelines.py → Pipelines代码模板(继承类)
│ settings.py → Scrapy爬虫的配置文件
│ __init__.py → 初始化脚本
│
└─spiders → Spiders代码模板目录(继承类)
__init__.py → 初始文件,无需修改
__pycache__/ → 缓存目录,无需修改(我生成的没有该文件)
1:部署:将这样的爬虫放在特定的服务器上,并且在服务器配置好相关的操作接口。
生成文件夹目录结构可以在cmd中进入要生成目录的文件夹路径下,输入
tree /f
详细参照:https://blog.youkuaiyun.com/weixin_43723625/article/details/106172273
步骤2:在工程中产生一个Scrapy爬虫
然后输入
cd python123demo
scrapy genspider demo python123.io
生成一个名称为demo的spider,然后会发现在spiders目录下会生成demo.py文件
这里是使用命令来生成demo.py,实际上可以手动生成该文件
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
allowed_domains = ['python123.io']
start_urls = ['http://python123.io/']
def parse(self, response):
pass
由于爬虫名称为demo,所以类名和name变量中出现demo。很神奇的是当我输入scrapy genspider 123
python123.io
时,文件和类名称会自动在'123'
前加'a'
name | 爬虫名称 |
allowed_domains | 命令行用户提交的域名,指的是这个爬虫在爬取网站的时候,它只能爬取这个域名以下的相关链接 |
start_urls | Scrapy框架所要爬取页面的初始页面 |
def parse | 解析页面的空的方法 |
parse() | 用于处理响应,解析内容形成字典,发现新的URL爬取请求。 |
步骤3:配置产生的spider爬虫
allowed_domains
这一行不需要,可以注释掉
将start_urls
修改为http://python123.io/ws/demo.html
然后更改爬取方法的具体功能
爬取方法有两个参数:
-
self: 面向对象类所属关系的标记
-
response: 从网络中返回内容所存取的内容或对象
这里把response中的内容保存到html文件中
def parse(self, response):
fname = response.url.split('/')[-1] # 从url最后一部分提取文件名
with open(fname, 'wb') as f:
f.write(response.body)
self.log('Saved file %s.' % name)
pass
步骤4:运行爬虫,获取网页
在cmd中输入scrapy crawl demo
在目录下会产生demo.html文件
上面的代码是Scrapy框架提供的简化版的代码
下面展示完整版代码
import scrapy
class DemoSpider(scrapy.Spider):
name = 'demo'
def start_requests(self):
urls = [
'http://python123.io/ws/demo.html'
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
fname = response.url.split('/')[-1] # 从url最后一部分提取文件名
with open(fname, 'wb') as f:
f.write(response.body)
self.log('Saved file %s.' % name)
pass
由命令生成的简化版demo.py文件,它通过 start urls
这个列表来给出初始的url链接。
但Scrapy框架支持另一种使用start_requests
的等价方法。首先定义一个urls列表,并且通过对列表中每一个元素通过yield scrapy.Request
向engine
提出了url访问请求
yield
生成器(generator)
-
生成器是一个不断产生值的函数
-
包含yield语句的函数是一个生成器
-
生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值。
一个函数执行到某一个位置产生了一个值,然后被冻结,再次唤醒后还是从这个位置继续去执行。
可参照:https://blog.youkuaiyun.com/mieleizhi0522/article/details/82142856/
为何要有生成器?
生成器相比一次列出所有内容的优势:
-
更节省存储空间
-
响应更迅速
-
使用更灵活
例如在普通写法中要存储100万,生成器写法只需1。
在规模很大的时候,生成器有很大的存储空间节省优势
Scrapy爬虫的基本使用
Request类
class scrapy.http.Request()
-
Request对象表示一个HTTP请求。
-
由Spider生成,由Downloader执行。
属性或方法 | 说明 |
---|---|
.url | Request对应的请求URL地址 |
.method | 对应的请求方法,‘GET’ 'POST’等 |
.headers | 字典类型风格的请求头 |
.body | 请求内容主体,字符串类型 |
.meta | 用户添加的扩展信息,在Scrapy内部模块间传递信息使用 |
.copy() | 复制该请求 |
Response类
class scrapy.http.Response()
-
Response对象表示一个HTTP响应。
-
由Downloader生成,由Spider处理。
属性或方法 | 说明 |
---|---|
.url | Response对应的URL地址 |
.status | HTTP状态码,默认是200 |
.headers | Response对应的头部信息 |
.body | Response对应的内容信息,字符串类型 |
.flags | 一组标记 |
.request | 产生Response类型对应的Request对象 |
.copy() | 复制该响应 |
Item类
class scrapy.item.Item()
-
Item对象表示一个从HTML页面中提取的信息内容。
-
由Spider生成,由Item Pipeline处理。
-
Item类似字典类型,可以按照字典类型操作。
Scrapy爬虫提取信息的方法
Scrapy爬虫支持多种HTML信息提取方法
-
Beautiful Soup
-
lxml
-
re
-
XPath Selector
-
CSS Selector
CSS Selector的基本使用
<HTML>.css('a::attr(href) ').extract()
# a为标签名称
# href为标签属性
CSS Selector由W3C组织维护并规范
Scrapy性能优化
配置并发连接选项-settings.py文件
选项 | 说明 |
---|---|
CONCURRENT_REQUESTS | Downloader最大并发请求下载数量,默认32 |
CONCURRENT_ITEMS | Item Pipeline最大并发ITEM处理数量,默认100 |
CONCURRENT_REQUESTS_PER_DOMAIN | 每个目标域名最大的并发请求数量,默认8 |
CONCURRENT_REQUESTS_PER_IP | 毎个目标IP最大的并发请求数量,默认0,非0有效 |
更多方法可查询Scrapy文档中有关settings.py的内容