scrapy框架 - 什么是框架? - 就是一个集成了很多功能并且具有很强通用性的一个项目模板。 - 如何学习框架? - 专门学习框架封装的各种功能的详细用法。 - 什么是scrapy? - 爬虫中封装好的一个明星框架。功能:高性能的持久化存储,异步的数据下载,高性能的数据解析,分布式 - scrapy框架的基本使用 - 环境的安装: - mac or linux:pip install scrapy - windows: - pip install wheel - 下载twisted,下载地址为http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted - 安装twisted:pip install Twisted‑17.1.0‑cp36‑cp36m‑win_amd64.whl - pip install pywin32 - pip install scrapy 测试:在终端里录入scrapy指令,没有报错即表示安装成功! - 创建一个工程:scrapy startproject xxxPro - cd xxxPro - 在spiders子目录中创建一个爬虫文件 - scrapy genspider spiderName www.xxx.com - 执行工程: - scrapy crawl spiderName - scrapy数据解析 - scrapy持久化存储 - 基于终端指令: - 要求:只可以将parse方法的返回值存储到本地的文本文件中 - 注意:持久化存储对应的文本文件的类型只可以为:'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle - 指令:scrapy crawl xxx -o filePath - 好处:简介高效便捷 - 缺点:局限性比较强(数据只可以存储到指定后缀的文本文件中) - 基于管道: - 编码流程: - 数据解析 - 在item类中定义相关的属性 - 将解析的数据封装存储到item类型的对象 - 将item类型的对象提交给管道进行持久化存储的操作 - 在管道类的process_item中要将其接受到的item对象中存储的数据进行持久化存储操作 - 在配置文件中开启管道 - 好处: - 通用性强。 - 面试题:将爬取到的数据一份存储到本地一份存储到数据库,如何实现? - 管道文件中一个管道类对应的是将数据存储到一种平台 - 爬虫文件提交的item只会给管道文件中第一个被执行的管道类接受 - process_item中的return item表示将item传递给下一个即将被执行的管道类 - 基于Spider的全站数据爬取 - 就是将网站中某板块下的全部页码对应的页面数据进行爬取 - 需求:爬取校花网中的照片的名称 - 实现方式: - 将所有页面的url添加到start_urls列表(不推荐) - 自行手动进行请求发送(推荐) - 手动请求发送: - yield scrapy.Request(url,callback):callback专门用做于数据解析 - 五大核心组件 引擎(Scrapy) 用来处理整个系统的数据流处理, 触发事务(框架核心) 调度器(Scheduler) 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址 下载器(Downloader) 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的) 爬虫(Spiders) 爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面 项目管道(Pipeline) 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。 - 请求传参 - 使用场景:如果爬取解析的数据不在同一张页面中。(深度爬取) - 需求:爬取boss的岗位名称,岗位描述 - 图片数据爬取之ImagesPipeline - 基于scrapy爬取字符串类型的数据和爬取图片类型的数据区别? - 字符串:只需要基于xpath进行解析且提交管道进行持久化存储 - 图片:xpath解析出图片src的属性值。单独的对图片地址发起请求获取图片二进制类型的数据 - ImagesPipeline: - 只需要将img的src的属性值进行解析,提交到管道,管道就会对图片的src进行请求发送获取图片的二进制类型的数据,且还会帮我们进行持久化存储。 - 需求:爬取站长素材中的高清图片 - 使用流程: - 数据解析(图片的地址) - 将存储图片地址的item提交到制定的管道类 - 在管道文件中自定制一个基于ImagesPipeLine的一个管道类 - get_media_request - file_path - item_completed - 在配置文件中: - 指定图片存储的目录:IMAGES_STORE = './imgs_bobo' - 指定开启的管道:自定制的管道类 - 中间件 - 下载中间件 - 位置:引擎和下载器之间 - 作用:批量拦截到整个工程中所有的请求和响应 - 拦截请求: - UA伪装:process_request - 代理IP:process_exception:return request - 拦截响应: - 篡改响应数据,响应对象 - 需求:爬取网易新闻中的新闻数据(标题和内容) - 1.通过网易新闻的首页解析出五大板块对应的详情页的url(没有动态加载) - 2.每一个板块对应的新闻标题都是动态加载出来的(动态加载) - 3.通过解析出每一条新闻详情页的url获取详情页的页面源码,解析出新闻内容 - CrawlSpider:类,Spider的一个子类 - 全站数据爬取的方式 - 基于Spider:手动请求 - 基于CrawlSpider - CrawlSpider的使用: - 创建一个工程 - cd XXX - 创建爬虫文件(CrawlSpider): - scrapy genspider -t crawl xxx www.xxxx.com - 链接提取器: - 作用:根据指定的规则(allow)进行指定链接的提取 - 规则解析器: - 作用:将链接提取器提取到的链接进行指定规则(callback)的解析 #需求:爬取sun网站中的编号,新闻标题,新闻内容,标号 - 分析:爬取的数据没有在同一张页面中。 - 1.可以使用链接提取器提取所有的页码链接 - 2.让链接提取器提取所有的新闻详情页的链接 - 分布式爬虫 - 概念:我们需要搭建一个分布式的机群,让其对一组资源进行分布联合爬取。 - 作用:提升爬取数据的效率 - 如何实现分布式? - 安装一个scrapy-redis的组件 - 原生的scarapy是不可以实现分布式爬虫,必须要让scrapy结合着scrapy-redis组件一起实现分布式爬虫。 - 为什么原生的scrapy不可以实现分布式? - 调度器不可以被分布式机群共享 - 管道不可以被分布式机群共享 - scrapy-redis组件作用: - 可以给原生的scrapy框架提供可以被共享的管道和调度器 - 实现流程 - 创建一个工程 - 创建一个基于CrawlSpider的爬虫文件 - 修改当前的爬虫文件: - 导包:from scrapy_redis.spiders import RedisCrawlSpider - 将start_urls和allowed_domains进行注释 - 添加一个新属性:redis_key = 'sun' 可以被共享的调度器队列的名称 - 编写数据解析相关的操作 - 将当前爬虫类的父类修改成RedisCrawlSpider - 修改配置文件settings - 指定使用可以被共享的管道: ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 } - 指定调度器: # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据 SCHEDULER_PERSIST = True - 指定redis服务器: - redis相关操作配置: - 配置redis的配置文件: - linux或者mac:redis.conf - windows:redis.windows.conf - 代开配置文件修改: - 将bind 127.0.0.1进行删除 - 关闭保护模式:protected-mode yes改为no - 结合着配置文件开启redis服务 - redis-server 配置文件 - 启动客户端: - redis-cli - 执行工程: - scrapy runspider xxx.py - 向调度器的队列中放入一个起始的url: - 调度器的队列在redis的客户端中 - lpush xxx www.xxx.com - 爬取到的数据存储在了redis的proName:items这个数据结构中
Scrapy
- 什么是框架?
- 就是一个集成了很多功能并且具有很强通用性的一个项目模板。
- 如何学习框架?
- 专门学习框架封装的各种功能的详细用法。
- 什么是scrapy?
- 爬虫中封装好的一个明星框架。功能:高性能的持久化存储,异步的数据下载,高性能的数据解析,分布式
-qiubaiPro.demo
from scrapy import cmdline cmdline.execute("scrapy crawl cnblog_spider --nolog".split()) #--nolog是以不显示日志的形式运行,如果需要看详细信息,可以去掉
# -*- coding: utf-8 -*- import scrapy from qiubaiPro.items import QiubaiproItem class QiubaiSpider(scrapy.Spider): name = 'qiubai' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.qiushibaike.com/text/'] # def parse(self, response): # #解析:作者的名称+段子内容 # div_list = response.xpath('//div[@id="content-left"]/div') # all_data = [] #存储所有解析到的数据 # for div in div_list: # #xpath返回的是列表,但是列表元素一定是Selector类型的对象 # #extract可以将Selector对象中data参数存储的字符串提取出来 # # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract() # author = div.xpath('./div[1]/a[2]/h2/text()').extract_first() # #列表调用了extract之后,则表示将列表中每一个Selector对象中data对应的字符串提取了出来 # content = div.xpath('./a[1]/div/span//text()').extract() # content = ''.join(content) # # dic = { # 'author':author, # 'content':content # } # # all_data.append(dic) # # # return all_data (基于终端指令保存文件) def parse(self, response): #解析:作者的名称+段子内容 div_list = response.xpath('//div[@class="col1 old-style-col1"]/div') for div in div_list: #xpath返回的是列表,但是列表元素一定是Selector类型的对象 #extract可以将Selector对象中data参数存储的字符串提取出来 # author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract() author = div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span/h2/text()').extract_first() #列表调用了extract之后,则表示将列表中每一个Selector对象中data对应的字符串提取了出来 content = div.xpath('./a[1]/div/span//text()').extract() content = ''.join(content) item = QiubaiproItem() item['author'] = author item['content'] = content yield item#将item提交给了管道
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class QiubaiproItem(scrapy.Item): # define the fields for your item here like: author = scrapy.Field() content = scrapy.Field() # pass
# -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html import pymysql class QiubaiproPipeline(object): fp = None #重写父类的一个方法:该方法只在开始爬虫的时候被调用一次 def open_spider(self,spider): print('开始爬虫......') self.fp = open('./qiubai.txt','w',encoding='utf-8') #专门用来处理item类型对象 #该方法可以接收爬虫文件提交过来的item对象 #该方法没接收到一个item就会被调用一次 def process_item(self, item, spider): author = item['author'] content= item['content'] self.fp.write(author+':'+content+'\n') return item #就会传递给下一个即将被执行的管道类 def close_spider(self,spider): print('结束爬虫!') self.fp.close() #管道文件中一个管道类对应将一组数据存储到一个平台或者载体中 class mysqlPileLine(object): conn = None cursor = None def open_spider(self,spider): self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='123456',db='qiubai',charset='utf8') def process_item(self,item,spider): self.cursor = self.conn.cursor() try: self.cursor.execute('insert into qiubai values("%s","%s")'%(item["author"],item["content"])) self.conn.commit() except Exception as e: print(e) self.conn.rollback() return item def close_spider(self,spider): self.cursor.close() self.conn.close() #爬虫文件提交的item类型的对象最终会提交给哪一个管道类? #先执行的管道类
# 设置UA USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36' # Obey robots.txt rules ROBOTSTXT_OBEY = False LOG_LEVEL = 'ERROR' # 开启管道 ITEM_PIPELINES = { 'qiubaiPro.pipelines.QiubaiproPipeline': 300, # 'qiubaiPro.pipelines.mysqlPileLine': 301, #300表示的是优先级,数值越小优先级越高 }
- scrapy框架相关命令
- 环境的安装: - mac or linux:pip install scrapy - windows: - pip install wheel - 下载twisted,下载地址为http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted - 安装twisted:pip install Twisted‑17.1.0‑cp36‑cp36m‑win_amd64.whl - pip install pywin32 - pip install scrapy (一般可以直接安装,不行的话在执行以上操作) 测试:在终端里录入scrapy指令,没有报错即表示安装成功! - 创建一个工程:scrapy startproject xxxPro - cd xxxPro - 在spiders子目录中创建一个爬虫文件 - scrapy genspider spiderName www.xxx.com - 执行工程: - scrapy crawl spiderName
– 解析-存储-管道-回调
- scrapy数据解析 - scrapy持久化存储(示例:qiubaiPro) - 基于终端指令: - 要求:只可以将parse方法的返回值存储到本地的文本文件中 - 注意:持久化存储对应的文本文件的类型只可以为:'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle - 指令:scrapy crawl xxx -o filePath - 好处:简介高效便捷 - 缺点:局限性比较强(数据只可以存储到指定后缀的文本文件中) - 基于管道: - 编码流程: - 数据解析 - 在item类中定义相关的属性 - 将解析的数据封装存储到item类型的对象 - 将item类型的对象提交给管道进行持久化存储的操作 - 在管道类的process_item中要将其接受到的item对象中存储的数据进行持久化存储操作 - 在配置文件中开启管道 - 好处: - 通用性强。 - 问题:将爬取到的数据一份存储到本地一份存储到数据库,如何实现? - 管道文件中一个管道类对应的是将数据存储到一种平台 - 爬虫文件提交的item只会给管道文件中第一个被执行的管道类接受 - process_item中的return item表示将item传递给下一个即将被执行的管道类 - 回调函数的使用: - 基于Spider的全站数据爬取(示例:xiaohuaPro) - 就是将网站中某板块下的全部页码对应的页面数据进行爬取 - 需求:爬取校花网中的照片的名称 - 实现方式: - 将所有页面的url添加到start_urls列表(不推荐) - 自行手动进行请求发送(推荐) - 手动请求发送: - yield scrapy.Request(url,callback):callback专门用做于数据解析
- 五大核心组件
引擎(Scrapy)
用来处理整个系统的数据流处理, 触发事务(框架核心)
调度器(Scheduler)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
下载器(Downloader)
用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
爬虫(Spiders)
爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
项目管道(Pipeline)
负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
– 自定制管道类(图片存储)
--使用scrapy爬取图片
- 需求:爬取站长素材中的高清图片 http://sc.chinaz.com/tupian/- 使用流程:
- 数据解析(图片的地址)
- 将存储图片地址的item提交到制定的管道类
- 在管道文件中自定制一个基于ImagesPipeLine的一个管道类
- get_media_request 发送请求
- file_path 获取文件名
- item_completed 将item传给下一个指定执行的管道类
- 在配置文件中:
- 指定图片存储的目录:IMAGES_STORE = './imgs_bobo'
- 指定开启的管道:自定制的管道类
spiders/img.py
items.py
pipelines.py
settings.py
– meta传参,cookie设置
- 请求传参 - 使用场景:如果爬取解析的数据不在同一张页面中。(深度爬取) - 需求:爬取boss的岗位名称,岗位描述 detail_url = 'https://www.zhipin.com'+li.xpath('.//div[@class="info-primary"]/div[1]/div[1]//div[1]/span[1]/a/@href').extract_first() #对详情页发请求获取详情页的页面源码数据 #手动请求的发送 #请求传参:meta={},可以将meta字典传递给请求对应的回调函数 yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})
- 设置cookie def start_requests(self): # 该cookie是登陆后获取的cookie字符串。 cookies ="lastCity=101280600; __zp_seo_uuid__=6e0b7a8a-bddd-4649-8665-3f0499d721d3; __g=-; __l=r=https%3A%2F%2Fwww.sogou.com%2Flink%3Furl%3DhedJjaC291Oa2YscKbYXZDtGMBTLg3lG&l=%2Fwww.zhipin.com%2Fshenzhen%2F&s=1&g=&s=3&friend_source=0; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1610982279; __c=1610982279; __a=47655612.1610982279..1610982279.2.1.2.2; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1610982335; __zp_stoken__=ce26bZzVnTEARJFNSDGwQIXM0Lh9YBHxkBlhjMWIKSHN4VGR5ZVEgD1BSQjtlSn1lHh8PIE4CIHFPaz0abRR2UX4SQFxbagYKaDYZfDNjOFskSn9HCVkWYXYyOxpNZTQTGE4FGX99IHdsQHV5YQ%3D%3D" # 转换成字典 cookies = {i.split("=")[0]: i.split("=")[1] for i in cookies.split("; ")} # headers = {"Cookie":cookies} # cookie放到headers中无效 yield scrapy.Request( self.start_urls[0], callback=self.parse, cookies=cookies # 携带cookie进行请求 # headers = headers # cookie放到headers中无效 ) -- seetting COOKIES_ENABLED = True
spiders/boss.py
items.py
pipelines.py
settings.py
– 中间件的使用
- 需求:爬取网易新闻中的新闻数据(标题和内容) - 1.通过网易新闻的首页解析出五大板块对应的详情页的url - 2.每一个板块对应的新闻标题都是动态加载出来的(动态加载) - 3.通过解析出每一条新闻详情页的url获取详情页的页面源码,解析出新闻内容 知识点: 1 中间件的使用 ,拦截请求,拦截响应数据 2 在scrapy中使用selenium,获取动态加载的数据 - 中间件(示例:middlePro) - 下载中间件 - 位置:引擎和下载器之间 - 作用:批量拦截到整个工程中所有的请求和响应 - 拦截请求: - UA伪装:process_request - 代理IP:process_exception:return request - 拦截响应: - 篡改响应数据,响应对象 -开启中间件(settings.py)
DOWNLOADER_MIDDLEWARES = {
'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543,
}
spiders/wangyi.py
items.py
middlewares.py
pipelines.py
settings.py
- CrawlSpider:类,Spider的一个子类
#需求:爬取sun网站中的编号,新闻标题,新闻内容,标号
- 分析:爬取的数据没有在同一张页面中。
- 1.可以使用链接提取器提取所有的页码链接
- 2.让链接提取器提取所有的新闻详情页的链接
- CrawlSpider:类,Spider的一个子类(用于全站数据爬取)
- 全站数据爬取的方式(对应板块所有页码数据的爬取)
- 基于Spider:手动请求
- 基于CrawlSpider
- CrawlSpider的使用:
- 创建一个工程
- cd XXX
- 创建爬虫文件(CrawlSpider):
- scrapy genspider -t crawl xxx www.xxxx.com
- 链接提取器:
- 作用:根据指定的规则(allow)进行指定链接的提取
- 规则解析器:
- 作用:将链接提取器提取到的链接进行指定规则(callback)的解析知识点:
-xpath表达式中不可以出现tbody标签
tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
-pipelines中如何区分不同的item
spiders/sun.py
items.py
pipelines.py
- 分布式爬虫
- 分布式爬虫 - 概念:我们需要搭建一个分布式的机群,让其对一组资源进行分布联合爬取。 - 作用:提升爬取数据的效率 - 如何实现分布式? - 安装一个scrapy-redis的组件 - 原生的scarapy是不可以实现分布式爬虫,必须要让scrapy结合着scrapy-redis组件一起实现分布式爬虫。 - 为什么原生的scrapy不可以实现分布式? - 调度器不可以被分布式机群共享 - 管道不可以被分布式机群共享 - scrapy-redis组件作用: - 可以给原生的scrapy框架提供可以被共享的管道和调度器 - 实现流程 (示例:fbsPro) - 创建一个工程 - 创建一个基于CrawlSpider的爬虫文件 - 修改当前的爬虫文件: - 导包:from scrapy_redis.spiders import RedisCrawlSpider - 将start_urls和allowed_domains进行注释 - 添加一个新属性:redis_key = 'sun' 可以被共享的调度器队列的名称 - 编写数据解析相关的操作 - 将当前爬虫类的父类修改成RedisCrawlSpider - 修改配置文件settings - 指定使用可以被共享的管道: ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 } - 指定调度器: # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据 SCHEDULER_PERSIST = True - 指定redis服务器: setting: #指定redis REDIS_HOST = '127.0.0.1' #redis远程服务器的ip(修改) REDIS_PORT = 6379 - redis相关操作配置: - 配置redis的配置文件: - linux或者mac:redis.conf - windows:redis.windows.conf - 代开配置文件修改: - 将bind 127.0.0.1进行删除 - 关闭保护模式:protected-mode yes改为no - 结合着配置文件开启redis服务 - redis-server 配置文件 - 启动客户端: - redis-cli - 执行工程: - scrapy runspider xxx.py - 向调度器的队列中放入一个起始的url: - 调度器的队列在redis的客户端中 - lpush xxx www.xxx.com - 爬取到的数据存储在了redis的proName:items这个数据结构中
-增量式爬虫
增量式爬虫 - 概念:监测网站数据更新的情况,只会爬取网站最新更新出来的数据。 - 分析: - 指定一个起始url - 基于CrawlSpider获取其他页码链接 - 基于Rule将其他页码链接进行请求 - 从每一个页码对应的页面源码中解析出每一个电影详情页的URL - 核心:检测电影详情页的url之前有没有请求过 - 将爬取过的电影详情页的url存储 - 存储到redis的set数据结构 - 对详情页的url发起请求,然后解析出电影的名称和简介 - 进行持久化存储
spiders/movie.py
items.py
pipelines.py
《Scrapy框架简介》有3个想法