scrapy
scrapy记录
简介
功能
- 持久化
- 数据下载
- 数据解析
- 分布式
安装
| 安装 | |
|---|---|
| 执行安装命令 | linux: pip3 install scrapywindows python -m pip install -U pippip intsall lxmlpip install wheelwget https://download.lfd.uci.edu/pythonlibs/w3jqiv8s/Twisted-20.3.0-cp37-cp37m-win_amd64.whlpip install Twisted-20.3.0-cp37-cp37m-win_amd64.whlpip install pywin32pip install scrapy |
| 检测是否安装成功 | 终端执行scrapy |
- 遇到
from cryptography.hazmat.bindings._openssl import ffi, lib |
- 需要重新安装openssl
pip uninstall pyopenssl |
简单使用
| 简单使用 | |
|---|---|
| 创建项目 | scrapy startproject 项目名称 |
| 创建任务 | cd 项目名称scrapy genspider 任务名称 www.baidu.com |
| 执行任务 | scrapy crawl 任务名称 |
| pycharm调试 | from scrapy import cmdline``cmdline.execute("scrapy crawl dmoz".split()) |
交互模式
- 进入交互模式:
scrapy shell quotes.toscrap.com - 执行命令:
quotes = response.css('.quote')
指令汇总
| global指令 | |
|---|---|
| startproject | 创建项目 |
| genspider | 创建spider |
| settings | 获取配置信息 |
| runspider | 执行spider |
| shell | 命令行交互模式 |
| fetch | 简单抓取某个网页 |
| view | 把网页保存成文件,再用浏览器打开 |
| version | scrapy版本信息 |
| 项目指令 | |
|---|---|
| crawl | 执行spider的方法 |
| check | 检查代码是否有错误 |
| list | 所有spider名称 |
| edit | 编辑spider |
| parse | |
| bench | 测试,运行的性能 |
设置
- 设置settings.py文件
| 设置示例 | |
|---|---|
| 设置log级别 | LOG_LEVEL = "WARNING” # DEBUG INFO WARN ERROR FATAL |
| 项目名称 | BOT_NAME=默认: 'scrapybot' 这将用于默认情况下构造 User-Agent,也用于日志记录。当您使用startproject命令创建项目时,它会自动填充您的项目名称。 |
| 启用中间件 | 设置请求头 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36' |
| 是否遵守robots协议,默认是遵守 | ROBOTSTXT_OBEY = True |
| 设置并发请求的数量,默认是16个 | CONCURRENT_REQUESTS |
| 下载延迟,默认无延迟 | DOWNLOAD_DELAY |
| 开启cookie,每次请求带上前一次cookie,默认开启 | COOKIES_ENABLED |
| 开启cookie显示 | COOKIES_DEBUG |
| 设置默认请求头 | DEFAULT_REQUEST_HEADERS |
| 爬虫中间件,设置过程和管道相同 | SPIDER_MIDDLEWARES |
| 下载中间件 | DOWNLOADER_MIDDLEWARES |
选择器
- response.selector类
| 选择器 | 说明 | 示例 |
|---|---|---|
| xpath | response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法 | response.selector.xpath("//title/text()") |
| css | response.selector.css("title::text") |
|
| 简写模式 | response.xpath("//title/text()").extract_first()response.css("title::text").extract_first() |
|
| 迭代查找 | response.xpath("//title/text()").css("title::text") |
|
| 获取属性 | response.xpath("//title").css("img::attr(src)") |
|
| 防止报错,设置默认提取 | response.xpath("//title/text()").extract_first(default='') |
|
| 获取内容 | extract() 返回一个包含有字符串的列表 extract_first() 返回列表中的第一个字符串,列表为空没有返回None |
`` |
| 正则表达式匹配 | response.re("name:'(.*?)'")response.re_first("name:'(.*?)'") |
执行器
- scrapy.spider.Spider基类
| 执行器 | 说明 | 示例 |
|---|---|---|
| name | spider名字,是任务的唯一标识 | |
| start_urls | URL列表,起始。要实现不停的爬取,需要重写start_url,设置while、True,然后将don’t_filter设置为True | |
| allowed_domains | 需要开启offsiteMiddleware,允许爬取的域名列表。需要抓取的、url地址必须属于allowed_domains,但是start_urls中的url地址没有这个限制 | |
| crawler | 提供对spider核心组件的访问 | |
| setting | 控制核心插件的配置 | |
| from_crawler | 可以通过它获取全局配置 | |
| custom_settings | 覆盖settings全局的配置 | |
| start_requests | 可以改写请求方式Request(url="http://www.example.com",|cookies={'currency': 'USD', 'country': 'UY'}) |
|
| parse | 回调函数,spider中的parse方法必须有返回值,需要通过yield返回可以传递给管道,只能返回request、baseitem、dict和none值 callback:默认是parse处理的 headers: meta:实现数据的传递,需要注意,传递字典和列表时,要用eepcopy操作,否则在后续调用时引用相同,会造成数据错乱。 error_back:设置错误处理的函数,决定执行的逻辑。 filter:请求过的url将被过滤,默认为过滤 |
|
| log | message level |
|
| closed | ||
| 自定义参数 | ||
| POST请求formRequest |
- response对象
| 属性 | 说明 | 示例 |
|---|---|---|
| response.body | 响应体,也就是html代码,默认是byte类型 | |
| response.body_as_unicode | 响应体 | |
| response.copy | ||
| response.css | ||
| response.encoding | ||
| response.flags | ||
| response.follow | 补全地址 | |
| response.headers | 响应头 | |
| response.meta | ||
| response.replace | ||
| response.requests.headers | 当前响应的请求头 | |
| response.request.url | 当前响应对应的请求的url地址 | |
| response.selector | ||
| response.status | ||
| response.text | ||
| response.url | 当前响应的url地址 | |
| response.urljoin | ||
| response.xpath |
- spider对象
| 属性 | 说明 | 示例 |
|---|---|---|
| spider.close | ||
| spider.crawler | ||
| spider.custom_settings | ||
| spider.from_crawler | ||
| spider.handles_request | ||
| spider.log | ||
| spider.logger | ||
| spider.make_requests_from_url | ||
| spider.name | ||
| spider.parse | ||
| spider.set_crawler | ||
| spider.settings | ||
| spider.start_requests | ||
| spider.start_urls | ||
| spider.update_settings |
- request对象
yield scrapy.Request(url,callback,meta)
| 属性 | 说明 | 示例 |
|---|---|---|
| request.body | ||
| request.callback | ||
| request.cookies | 设定cookie信息 | scrapy.Request(cookies=cookie) |
| request.copy | ||
| request.dont_filter | ||
| request.encoding | ||
| request.errback | ||
| request.flags | ||
| request.headers | ||
| request.meta | ||
| request.method | ||
| request.priority | ||
| request.replace | ||
| request.url |
- FormRequest对象
- 用于post请求
scrapy.FormRequest(url=url,formdata=data,callback=self.parse)
| 属性 | 说明 | 示例 |
|---|---|---|
| formdata | post数据 |
item和管道
item
- item类型对象
- 用于定义要存储的数据结构
class XXXItem(scrapy.Item): |
- 在spider获取的数据建立XXXItem对象,并对author和content赋值,yield即可传递给管道。
item = XXXItem() |
pipeline
- pipeline对象
- pipeline中process_item的方法必须有,否则item没有办法接受和处理;
- 有多个pipeline的时候,process_item的方法必须return item,否则后一个pipeline取到的数据为None值
- process_item方法接受item和spider,其中spider表示当前传递item过来的spider
- 使用之前需要在settings中开启,优先级:0~1000
- pipeline在settings中能够开启多个,实现不同的pipeline可以处理不同爬虫的数据,不同的pipeline能够进行不同的数据处理的操作,比如一个进行数据清洗,一个进行数据的保存
| pipeline | |
|---|---|
| process_item | 返回两种:1、item;2、dropitem |
| open_spider | spider开启调用一次 |
| close_spider | spider关闭调用一次 |
| from_crawler | 获取项目配置信息 |
class XXXPipline: |
ImagePipeline
- 在settings.py中设置文件保存的目录
IMAGES_STORE = 'datas' |
- 设置图片pipeline,还有保存的名字
from scrapy.pipeline import ImagesPipline |
| ImagesPipeline | |
|---|---|
| get_media_requests | 根据图片地址,进行图片数据请求 |
| file_path | 指定图片存储的路径 |
| item_completed | 返回item,给下一个pipeline |
中间件
爬虫中间件
- spiderMiddleware
下载中间件
- 位于引擎和下载器之间,下载中间件可以拦截所有请求,以及所有请求返回相应对象。
- 功能:UA修改,Proxy修改;篡改相应
| ImagesPipeline | |
|---|---|
| from_crawler | |
| process_request | 拦截请求 输入request,spider 需要返回数据 None:返回none不会对框架产生影响,继续向后执行中间件, Response:返回Response,不在调用其他中间件的request方法,而调用process_response方法 request:返回request,则会把request重新放入项目队列中去,循环往复的调度 raise |
| process_response | 拦截相应 输入:request、response、spider 返回 Response:返回Response,不会对框架产生影响,继续向后执行中间件 request:返回request,则会把request重新放入项目队列中去,循环往复的调度 raise |
| process_exception | 拦截异常 输入:request、response、spider 返回: None:返回None不会对框架产生影响,继续向后执行中间件 Response:返回Response,不在调用其他中间件的request方法,而调用process_response方法,成功的放回 request:返回request,则会把request重新放入项目队列中去,循环往复的调度,相当于重新发送请求 raise |
scrapy分布式
-
scrapy-redis是scrapy的组件,通过redis与调度器连接,存放调度器传递过来的指纹,存放request对象,默认存放redispipe保存的数据。
-
增量式爬虫,基于request对象的增量、基于数据的增量
-
实现request对象的指纹去重,使用sha1,加密请求方法、url地址、请求体得到16进制字符串。指纹存在redisset中,判断redis.sadd()存在则返回0
安装
pip3 install scrapy_redis |
实现增量式爬虫
| 增量爬虫设置 | |
|---|---|
| 更改调度器 | SCHEDULER = "scrapy_redis.scheduler.Scheduler" |
| 去重 | DUPEFILTER_CLASS="scrapy_redis.dupefilter.RFPDupeFilter" |
| 调度器持久化存储 | SCHEDULER_PERSIST = True不清空redis指纹,建议为false |
| redis连接 | REDIS_URL="redis://root:user@ip:port" |
| 清空之前的所有指纹,重新爬取 | SCHEDULER_FLUSH_ON_START=True |
- settings代码如下
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" |
- scrapy-redis将下面三个内容在redis中储存:
- Scheduler队列:存放待请求的request对象,过程是pop操作,获取一个去除一个。
- 指纹集合:存放已经进入Scheduler队列的request对象的指纹,指纹默认由请求方法、url和请求体组成
- item信息:只有开启RedisPipeline才会存入。
分布式爬虫RedisSpider
- 配置跟增量相同
- 实现代码
from scrapy_redis.spiders import RedisSpider |
- 增加了一个redis_key的键,没有start_urls,因为分布式中,如果每台电脑都请求一次start_url就会重复
- 多了__init__方法,该方法不是必须的,可以手动指定allow_domains
分布式爬虫RedisCrawlSpider
from scrapy.spiders import Rule |
scrapy分布式部署
安装
pip3 install scrapyd==1.2.0a1 |
配置和使用
| 分布式部署 | |
|---|---|
| 配置远程主机 | ---scrapy.cfg----[deploy]url = http://47.95.229.68:6800/addversion.jsonproject = taobao |
| 执行部署 | scrapyd-deploy |
| 远程调度API | 访问http://scrapyd.readthedocs.io/en/lasted/api.html |
| 查看所有上传项目状态 | curl http://47.95.229.68:6800/listprojects.json |
| 项目版本 | curl http://47.95.229.68:6800/listversions.json?project=taobao |
| 远程任务启动 | curl http://47.95.229.68:6800/schedule.json -d project=taobao -d spider=goods请求多次可以开启多个进程 |
| 查看任务状态 | curl http://47.95.229.68:6800/listjobs.json?project=taobao #可以查看job代号 |
| 任务取消 | curl http://47.95.229.68:6800/cancel.json -d project=taobao -d job=job代号 |
api封装
-
对scrapyd的封装,在python中就可以调度项目
-
安装:
pip3 install python-srcapyd-api
crawlspider
- crawlspider是scrapy的另一种模板,可以自动从response中提取所有的满足规则的url地址,自动的构造自己requests请求,发送给引擎。
使用
| 使用 | |
|---|---|
| 创建任务 | scrapy genspider –t crawl 任务名 www.xxx.cn |
- 注意点
- crawlspider中不能再有以parse为名字的方法,这个方法被用来实现基础url提取功能
- 一个Rule对象接收很多参数,包含LinkExtractor、callback、和follow
- 不指定callback,如果follow为true,满足该rule的url还会继续请求
- 如果多个rule都满足某一个url,则会从rules中选择第一个进行操作
spider
| spider | |
|---|---|
| rules | 是一个元组或者是列表,包含的是Rule对象 |
| Rule | 表示规则,其中包含LinkExtractor,callback和follow |
| LinkExtractor | 连接提取器,可以通过正则或者是xpath来进行url地址的匹配 |
| callback | 表示经过连接提取器提取出来的url地址响应的回调函数,可以没有,没有表示响应不会进行回调函数的处理(有需要数据提取时设置True) |
| follow | 表示进过连接提取器提取的url地址对应的响应是否还会继续被rules中的规则进行提取,True表示会,Flase表示不会(有需要url提取时设置True) |
class xxxxSpider(CrawlSpider): |
| LinkExtractor | |
|---|---|
| allow(re) | 满足正则表达式的url会被提取,如果为空,则全部匹配 |
| deny(re) | 满足正则表达式,则一定不提取,优先级高于allow |
| allow_domains(domain) | 会被提取的domains |
| deny_domains(domain) | 不会被提取的domains |
| restrict_xpaths | 使用xpath表达式,和allow共同作用过滤链接 |
| Rule | |
|---|---|
| link_extractor | linkextract对象用于定义需要提取的方法 |
| callback | 获得连接后,指定回调函数 |
| follow(bool) | 指定改规则的response是否需要跟进 |
| process_links | 指定该spider中那个函数将会被调用,从link_extractor中获取到链接列表时将会调用该函数,该方法主要用来过滤url |
| process_request | 指定该spider中哪个函数将会被调用,改规则提取到每个request时都会调用该函数,用于过滤request |
