分布式爬取scrapy-redis
主要来解决爬虫效率的问题,用几个机器同时来爬取,并保存到一个计算机。
scrapy.spider
crawlspider
共享爬取队列(待爬取队列):用redis来维护,无序集合,
管道爬取的数据默认会存储在redis中
分布式环境搭建:
pip install scrapy -i xxx
pip install scrapy-redis -i xxx
分析redis里面生成的key
items:爬取下来的数据list
dupefilter:已经入带爬取队列的请求、set去重
requests:待请求的对象,一旦爬取内容完成,就看不见requests
settings里的内容:
配置redis:默认保存到本地,如果需要保存其他机器,需要设置这一行代码,更换ip
REDIS_URL = “redis://127.0.0.1:6379”
bind 127.0.0.1 如果需要连接其他机器,要改为0.0.0.0
scrapy-redis源码分析
xpath模糊匹配:
pipeline.py redis生成key
PIPELINE_KEY = ‘%(spider)s:items’
self.key=’%(spider)s:items’
key = ‘%(spider)s:items’ % {‘spider’: spider.name}
占位符%(spider)s
dupefilter.py :形成一个字符串、完成去重
scheduler.py:调度器,里面的enqueue_request函数,判断请求是否存在、不存在就添加到任务队列
案例:盗墓笔记
爬取需求:爬取小说内容
建立一个文件夹,二级文件夹
找系列名称查看源代码,可以从ul里找名称,但是不完整通过id匹配,模糊匹配 //li[contains{id,"menu-item-")]/afrom daomu.items import DaomuItema_lis = response.xpath('//li[contains(@id, "menu-item-")]/a')for a in a_lis:item = DaomuItem()first_title = a.xpath('./text()').get() # 获取文本数据sencond_href = a.xpath('./@href').get() # 拿到二级页面的url
# 需要获取小标题,进行text文件命名b_list = response.xpath('//article')for b in b_list:charper_title = b.xpath('./a/text()').get()content_url = b.xpath('./a/@href').get()
content_list = response.xpath('//article[@class="article-content"]/p/text()').getall()item['content'] = '\n'.join(content_list) # 把列表元素string用换行符拼接
如果爬取出来的文件名 包含特殊字符会报错,因此要进行处理,正则替换
# 利用正则替换import reimport oss = r'七星鲁王:第一章 血尸' # r防止字符串被转义first_title = re.sub(r'[\\\/\:\*\?\"\<\>\| ]', '_', s) # 把字符集里的符号换成下划线_print(first_title)second_title# 创建文件路径dir_path = r'.\novel/{}'.format(first_title)print(dir_path)# os.makedirs()文件已存在的话就会报错# 文件路径若不存在 再创建if not os.path.exist(dir_path):# 创建文件路径os.makedirs(dir_path)# 小说内容文件具体路径filename = os.path.join(dir_path, first_title)+'.txt'# 写入内容with open(filename, 'w','utf-8') as f:f.write(item['content'])
修改成分布式
先使用普通的scrapy实现爬虫文件中修改继承类scrapyspider--->RedisSpiderfrom copy import deepcopy修改配置文件settings# 需要修改USER_AGENT = 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36 Edg/100.0.1185.50'# 设置去重方式DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"#设置调度器SCHEDULER = "scrapy_redis.scheduler.Scheduler"#是否进行持久保存SCHEDULER_PERSIST = Truepipeline中添加ITEM_PIPELINES = {'daomubiji.pipelines.DaomubijiPipeline': 300,'scrapy_redis.pipelines.RedisPipeline': 400,}配置redisREDIS_URL = "redis://127.0.0.1:6379"
