7-爬虫-crawlSpider、分布式爬虫、增量式爬虫、爬虫内容总结
crawlSpider
是Spider的一个子类。自己派生出独有的方法和属性。
功能:作用全站数据爬取场景
使用:
- 创建工程
- cd 工程
- 创建爬虫文件:
- 创建一个基于CrawlSpider的爬虫文件
- 指令:scrapy genspider -t crawl spiderName www.xxx.com
- 执行工程
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule class CrawlModelSpider(CrawlSpider): name = 'crawl_model' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.4567kan.com/index.php/vod/show/class/动作/id/1.html'] # LinkExtractor叫做链接提取器 # 作用:根据指定的规则(allow='正则')在页面中进行相关链接(url)的提取 link = LinkExtractor(allow=r'/id/1/page/\d+\.html') rules = ( # Rule叫做规则解析器,链接提取器是被作用在规则解析器 # 作用:可以接受link提取到的链接,且对链接进行请求发送,根据指定规则(callback)对请求到的数据进行数据解析 # follow=True:可以将 链接提取器 继续作用到 链接提取器 提取到的页码 所对应的页面源码中 Rule(link, callback='parse_item', follow=True), ) def parse_item(self, response): print(response)
crawlspider全站数据爬取
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule import scrapy from moviePro.items import MovieproItem class MovieSpider(CrawlSpider): name = 'movie' # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.4567kan.com/index.php/vod/show/class/动作/id/1/page/1.html'] rules = ( # 提取页码链接 Rule(LinkExtractor(allow=r'/id/1/page/\d+\.html'), callback='parse_item', follow=False), # 提取详情页链接 # Rule(LinkExtractor(allow=r'/movie/index\d+\.html'),callback='parse_detail',follow=False) ) def parse_item(self, response): # 解析电影的名称 li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li') for li in li_list: title = li.xpath('./div/a/@title').extract_first() detail_url = 'https://www.4567kan.com' + li.xpath('./div/a/@href').extract_first() item = MovieproItem() item['title'] = title yield scrapy.Request(url=detail_url, callback=self.parse_detail, meta={'item': item}) def parse_detail(self, response): desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first() item = response.meta['item'] item['desc'] = desc yield item
分布式爬虫
概念:搭建一个分布式机群,然后让每一台电脑进行联合且分布的数据爬取。
原生的scrapy框架是无法实现分布式
- 调度器无法被机群共享
- 管道无法被共享
必须要要scrapy结合scrapy-redis组件一起实现分布式
- scrapy-redis组件的作用:
- 可以给scrapy提供可以被共享的管道和调度器
- 为什么组件的名称叫做scrapy-redis
- 爬取到的数据只能存储到redis中
环境安装:
- pip install scrapy-redis
实现流程:
- 1.新建工程(基于CrawlSpider),也可以用Spider
- 2.修改爬虫文件
- 导包:from scrapy_redis.spiders import RedisCrawlSpider
- 修改当前爬虫类的父类为RedisCrawlSpider
- 将start_urls替换成redis_key属性,属性值为字符串,表示可以被共享的调度器队列的名称
- 编写后序的爬虫文件相关操作
- 3.进行setting配置文件的配置(直接将配置代码复制进配置文件中)
- 指定管道
# 指定使用scrapy-redis组件中的调度器
# 使用scrapy-redis组件的去重队列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis组件自己的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 帮分布式实现增量式
SCHEDULER_PERSIST = True
- 指定调度器
# 指定共享管道(不能修改,只能往redis存)
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 400
}
- 指定redis
# 指定redis数据库服务器和端口号
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379
- 4.对redis的配置文件进行配置:redis.windows.conf
- 56行:关闭默认绑定,允许外网有访问该redis数据库, # bind 127.0.0.1 # 将这个代码注释掉
- 75行:关闭保护模式,允许其他设备有redis写入的权限,protected-mode no # 将参数由yes改为no
- 5.启动redis的服务端和客户端
- 6.执行工程
- 7.向调度器队列中扔入一个起始的url:调度器的队列是存在于redis中
- 在redis的客户端执行如下指令:
- lpush 调度器队列的名称 起始的url
- 该指令一旦执行成功,则分布式机群就可以进行数据的爬取
- 8.可以在redis中查看爬取到的数据
- xxx:items:存储的是爬取到的数据
settings.py
# 指定使用scrapy-redis组件中的调度器 # 使用scrapy-redis组件的去重队列 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 帮分布式实现增量式 SCHEDULER_PERSIST = True # 指定共享管道(不能修改,只能往redis存) ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 } # 指定redis数据库服务器和端口号 REDIS_HOST = '127.0.0.1' REDIS_PORT = 6379
fbs.py
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from scrapy_redis.spiders import RedisCrawlSpider from fbsPro.items import FbsproItem class FbsSpider(RedisCrawlSpider): name = 'fbs' # allowed_domains = ['www.xxx.com'] # start_urls = ['http://www.xxx.com/'] redis_key = 'sun_queue' # 调度器队列的名称 rules = ( Rule(LinkExtractor(allow=r'id=1&page=\d+'), callback='parse_item', follow=True), ) def parse_item(self, response): # 在xpath表达式中不可以出现tbody标签,否则xpath表达式无效 li_list = response.xpath('/html/body/div[2]/div[3]/ul[2]/li') for li in li_list: status = li.xpath('./span[2]/text()').extract_first() title = li.xpath('./span[3]/a/text()').extract_first() item = FbsproItem() item['title'] = title item['status'] = status yield item
items.py
import scrapy class FbsproItem(scrapy.Item): # define the fields for your item here like: title = scrapy.Field() status = scrapy.Field()
增量式爬虫
概念:来检测网站数据更新情况。为爬取网站最新更新出来的数据。
实现核心:记录表
- 记录表中要存储爬取过的记录。
- 在电影网站中,每一部电影详情页的url就可以作为电影的唯一标识(爬取的记录)
- 谁可以充当记录表:
- 1.记录表需要有去重的功能
- 2.记录表需要持久化存储
- 可以使用redis中的set集合充当记录表
zls.py
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from zlsPro.items import ZlsproItem from redis import Redis class ZlsSpider(CrawlSpider): name = 'zls' conn = Redis(host='127.0.0.1', port=6379) # allowed_domains = ['www.xxx.com'] start_urls = ['https://www.4567kan.com/index.php/vod/show/class/%E5%8A%A8%E4%BD%9C/id/1/page/1.html'] rules = ( Rule(LinkExtractor(allow=r'/id/1/page/\d+\.html'), callback='parse_item', follow=False), ) def parse_item(self, response): # 解析电影的名称 li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li') for li in li_list: title = li.xpath('./div/a/@title').extract_first() detail_url = 'https://www.4567kan.com' + li.xpath('./div/a/@href').extract_first() # ex=1:插入成功,0表示插入失败(插入了重复的数据) ex = self.conn.sadd('movie_urls', detail_url) if ex == 1: item = ZlsproItem() item['title'] = title print('正在爬取的电影是:', title) yield scrapy.Request(url=detail_url, callback=self.parse_detail, meta={'item': item}) else: print('暂无更新数据可爬!!!') def parse_detail(self, response): desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first() item = response.meta['item'] item['desc'] = desc yield item
pipelines.py
class ZlsproPipeline: def process_item(self, item, spider): spider.conn.lpush('movie_data', item) return item
items.py
import scrapy class ZlsproItem(scrapy.Item): # define the fields for your item here like: title = scrapy.Field() desc = scrapy.Field()
爬虫内容总结
反爬机制
- robots协议
- UA检测
- 动态加载数据
- 验证码
- cookie
- 代理
- js加密
- js逆向
- js混淆
- 动态变化的请求参数
爬虫
- requests
- get,post请求:方法参数
- 参数动态
- cookie,验证码,代理,模拟登录
- 数据解析
- xpath,bs4
- 异步爬虫
- 线程池,协程,生产者消费者模式
- selenium
- 爬取动态加载数据
- 模拟登录
- scrapy
- 请求发送
- 数据解析
- 全站数据爬取
- 手动请求发送
- 请求传参实现的深度爬取
- 核心组件
- 中间件
- crawlspider
- 分布式
- 增量式