scrapy学习
整体流程图
中间件介绍
-
middlewares.py
-
# 爬虫中间件: 处于spider和引擎之间(不常用) # 下载中间件: 处于引擎和下载器之间(常用) class MiddleproDownloaderMiddleware: def process_request(self, request, spider): """ 拦截所有的请求 :param request: 拦截到的请求对象 :param spider: 爬虫文件中爬虫类实例化的对象 """ # 对请求头进行相关操作 # request.headers['Cookie'] = 'xxx' pass def process_response(self, request, response, spider): """ 拦截所有的响应 :param response: 响应对象 :param spider: 爬虫文件中爬虫类实例化的对象 :return: 返回响应 """ return response def process_exception(self, request, exception, spider): """ 拦截发生异常的请求 :param spider: 爬虫文件中爬虫类实例化的对象 :return: 返回修正后的请求 """ # 将代理的设置写在此处 # request.meta['proxy'] = 'https://ip:port' # 将修正后的请求对象重新进行请求发送 return request
-
配置文件中打开
-
DOWNLOADER_MIDDLEWARES = { 'middlePro.middlewares.MiddleproDownloaderMiddleware': 543, }
-
CrawlSpider
-
作用: 实现全站数据爬取
-
创建:
scrapy genspider -t crawl test www.xxx.com
-
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule class TestSpider(CrawlSpider): name = 'test' allowed_domains = ['www.xxx.com'] start_urls = ['http://www.xxx.com/'] link = LinkExtractor(allow=r'Items/') # 核心一: 链接提取器,使用正则匹配出页面中所有符合的链接数据 rules = ( Rule(, callback='parse_item', follow=True), ) # 核心二: 规则提取器,follow=True可以深度提取 def parse_item(self, response): item = {} return item
分布式
-
概念: 可以组建一个分布式机群,然后让其对同一组网络资源进行联合且分布的数据爬取。
-
实现原理: 使用scrapy-redis组件结合着scrapy实现分布式
- scrapy-redis作用: 提供可以被共享的管道和调度器
-
实现步骤
-
创建工程并进入:
scrapy startproject dcsPro
,cd dcsPro
-
创建爬虫文件:
scrapy genspider -t crawl dcs www.xx.com
-
修改爬虫文件
-
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from scrapy_redis.spiders import RedisCrawlSpider from dcsPro.items import DcsproItem """ 导包:from scrapy_redis.spiders import RedisCrawlSpider 修改爬虫的父类为:RedisCrawlSpider 将start_urls替换成redis_key = ‘xxx’:调度器队列的名称 编写正常的数据爬取操作 """ class DcsSpider(RedisCrawlSpider): name = 'dcs' # allowed_domains = ['www.xx.com'] # start_urls = ['http://www.xx.com/'] redis_key = 'dcsQueue' # 调度器队列名称 rules = ( Rule(LinkExtractor(allow=r'index_\d+\.html'), callback='parse_item', follow=True), ) def parse_item(self, response): div_list = response.xpath('/html/body/div[3]/div[2]/div') for div in div_list: title = div.xpath('./div/a/text()').extract_first() img_url = "https" + div.xpath('./img/@ata-original').extract_first() item = DcsproItem() item['title'] = title item['url'] = img_url yield item
-
-
根据爬虫文件中用到的item类修改items.py文件
-
import scrapy class DcsproItem(scrapy.Item): title = scrapy.Field() url = scrapy.Field()
-
-
修改settings.py配置文件
-
ROBOTSTXT_OBEY = False # 是否遵循robots协议 USER_AGENT = '...' # UA LOG_LEVEL = 'ERROR' # 设置日志等级 COOKIES_ENABLED = True # 打开cookie机制 ITEM_PIPELINES = { ... 'scrapy_redis.pipelines.RedisPipeline': 400, # 指定管道 } # 使用scrapy-redis组件的去重队列 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 是否允许暂停 SCHEDULER_PERSIST = True # 指定redis REDIS_HOST = '127.0.0.1' # 填写redis地址 REDIS_PORT = 6379 # 填写redis端口
-
-
修改redis的配置文件
redis.window.conf
-
关闭默认绑定:56行:# bind 127.0.0.1 关闭保护模型:75行:protected-mode no
-
-
启动redis服务端和客户端
-
redis-server --service-start # 启动redis服务端
-
-
执行当前工程
-
scrapy crawl dcs
-
-
向调度器的队列中扔入一个起始的url
-
redis-cli # 进入redis客户端 lpush dcsQueue 网址 # 队列名称在第3步爬虫文件中有定义 # 在dcs:items中可以看到存储的数据
-
-
增量式
-
作用: 监测网站数据更新的情况
-
核心: 去重
-
实现步骤
-
创建工程并进入:
scrapy startproject incrementalPro
,cd incrementalPro
-
创建爬虫文件:
scrapy genspider -t crawl incremental www.xxx.com
-
修改爬虫文件
-
# incremental.py # 以下是以当时测试的网站为例 import scrapy from redis import Redis from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from incrementalPro.items import IncrementalproItem class IncrementalSpider(CrawlSpider): name = 'incremental' # allowed_domains = ['www.xxx.com'] start_urls = ['https://sc.chinaz.com/tupian/'] conn = Redis(host='127.0.0.1', port=6379) rules = ( Rule(LinkExtractor(allow=r'index_\d+\.html'), callback='parse_item', follow=True), ) def parse_item(self, response): div_list = response.xpath('/html/body/div[3]/div[2]/div') for div in div_list: detail_url = 'https://sc.chinaz.com' + div.xpath('./div/a/@href').extract_first() ex = self.conn.sadd('urls', detail_url) if ex == 1: """ 有数据更新的情况 """ yield scrapy.Request(detail_url, callback=self.parse_detail) else: """ 无数据更新 """ pass def parse_detail(self, response): title = response.xpath('/html/body/div[3]/div[1]/div[1]/div[2]/div[1]/h1/text()').extract_first() blurb = response.xpath('/html/body/div[3]/div[1]/div[1]/div[2]/div[3]/div[1]/p[2]/text()').extract_first() if title and blurb: """ 标题和简介存在的情况下 """ item = IncrementalproItem() item['title'] = title item['blurb'] = blurb yield item
-
-
根据爬虫文件中用到的item类修改items.py文件
-
# items.py import scrapy class IncrementalproItem(scrapy.Item): title = scrapy.Field() blurb = scrapy.Field()
-
-
修改管道文件pipelines.py
-
# pipelines.py # 注意事项: 因为这边往redis中扔入的是一个字典,可能有些版本是不适用的,我这边使用的是redis-2.10.6版本 # pip install -U redis==2.10.6 class IncrementalproPipeline: def process_item(self, item, spider): spider.conn.lpush('imgData', item) return item
-
-
修改settings.py配置文件
-
USER_AGENT = '...' ROBOTSTXT_OBEY = False LOG_LEVEL = 'ERROR' COOKIES_ENABLED = True ITEM_PIPELINES = { 'incrementalPro.pipelines.IncrementalproPipeline': 300, }
-
-
启动redis服务端:
redis-server --service-start
-
启动工程:
scrapy crawl incremental
- 在imgData中可以看到存储的数据
-