自定义一个关于ImagesPipeline该父类的管道类,在pipelines.py中重写如下三个方法
from scrapy.pipelines.images import ImagesPipeline import scrapy class ImgproPipeline(ImagesPipeline): # 发起请求 def get_media_requests(self, item, info): imgSrc = item[\'imgSrc\'] # 请求传参,将meta字典传递给了file_path这个方法 yield scrapy.Request(url=imgSrc, meta={\'item\': item}) # 定制get_media_request请求到数据持久化存储的路径(文件夹路径+文件名称) def file_path(self, request, response=None, info=None): # 通过request.meta接收请求传参传递过来的meta字典 imgName = request.meta[\'item\'][\'imgName\'] return imgName # 如果配置文件中没指定文件夹 # return \'文件夹/%s.jpg\' % (image_guid) def item_completed(self, results, item, info): return item CrawlSpider 全站数据爬取
CrawlSpider就是Spider的一个子类
创建一个基于CrawlSpider爬虫文件
scrapy genspider -t crawl spiderName
LinkExtractor(allow=r\'正则表达式\'):链接提取器
作用:可以根据指定的指定的规则(allow)进行链接提取
Rule(link,callback,follow=True):规则解析器
link:链接提取
callback:回调函数,字符串反射调用函数,解析数据
follow=True:将链接提取器 继续作用到 链接提取器提取到的链接的对应页面中
作用:
1.将链接提取器提取到的链接进行请求发送(get)请求发送
2.请求到的数据根据指定的规则进行数据解析
深度爬取
手动发送请求解析数据,请求传参和LinkExtractor,Rule一起使用实现深度爬取
Rule(LinkExtractor(allow=r\'正则表达式提取指定url\'),callback=\'函数名\',follow=True(提取全站页码url)/Flase(提取当前叶页码url))
使用链接提取器提取详情页的url实现深度爬取
案例:阳光问政spiderName.py中代码
问题:实例化在持久化存储后无法实现数据一一对应的汇总
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule # 实例化了两个item对象 from sunPro.items import TitleItem, ContentItem class SunSpider(CrawlSpider): name = \'sun\' # allowed_domains = [\'www.xxx.com\'] start_urls = [\'http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1\'] # 根据正则提取全站页码 link = LinkExtractor(allow=r\'id=1&page=\d+\') # 提取标题对应的详情页链接 link_detail = LinkExtractor(allow=r\'politics/index\?id=\d+\') rules = ( Rule(link, callback=\'parse_item\', follow=True), Rule(link_detail, callback=\'parse_detail\', follow=False), ) def parse_item(self, response): li_list = response.xpath(\'/html/body/div[2]/div[3]/ul[2]/li\') for li in li_list: title = li.xpath(\'./span[3]/a/text()\').extract_first() detail_url = item = TitleItem() item[\'title\'] = title yield item def parse_detail(self, response): content = response.xpath(\'/html/body/div[3]/div[2]/div[2]/div[2]/pre/text()\').extract_first() item = ContentItem() item[\'content\'] = content yield item
解决上述问题
手动发送请求解析详情页的内容,请求传参,传给一个item
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from sunPro.items import SunproItem class SunSpider(CrawlSpider): name = \'sun\' # allowed_domains = [\'www.xxx.com\'] start_urls = [\'http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1\'] link = LinkExtractor(allow=r\'id=1&page=\d+\') rules = ( Rule(link, callback=\'parse_item\', follow=False), ) def parse_item(self, response): li_list = response.xpath(\'/html/body/div[2]/div[3]/ul[2]/li\') for li in li_list: title = li.xpath(\'./span[3]/a/text()\').extract_first() detail_url = "http://wz.sun0769.com/" + li.xpath(\'./span[3]/a/@href\').extract_first() item = SunproItem() item[\'title\'] = title yield scrapy.Request(url=detail_url, callback=self.parse_detail, meta={\'item\': item}) def parse_detail(self, response): content = response.xpath(\'/html/body/div[3]/div[2]/div[2]/div[2]/pre/text()\').extract_first() item = response.meta[\'item\'] item[\'content\'] = content yield item 分布式实际应用中很少,一般都是面试时问道,主要是文原理。
概念:搭建一个分布式机群,共同执行一组代码,联合对同一个资源的数据进行分布且联合爬取
实现方式:
简称:scrapy + redis
全称:Scrapy框架 + scrapy-redis组件
原生的scrapy框架无法实现分布式
原生scrapy的调度器和管道无法共享
scrapy-redis组件的作用
可以给原生的scrapy框架,提供可以被共享的管道和调度器
环境安装
pip install scrapy-redis
实现流程
修改爬虫文件中爬虫类对应的操作
导包:from scrapy_redis.spiders import RedisCrawlSpider
CrawlSpider 导入 RedisCrawlSpider Spider 导入 RedisSpider
爬虫类的父类修改成RedisCrawlSpider
将start_urls删除,添加一个redis_key=\'可以被共享调度器队列的名称\'
进行常规的请求和解析和向管道提交item操作即可
对settings.py进行配置
配置管道
ITEM_PIPELINES = { # scrapy组件中有管道,是基于redis的,所以目前只能用redis存储 \'scrapy_redis.pipelines.RedisPipeline\':400, }