爬虫篇 6 手动请求发送 五大核心组件 请求传参 中间件初识 虎牙全站爬取
- 管道的持久化存储:
- 数据解析(爬虫类)
- 将解析的数据封装到item类型的对象中(爬虫类)
- 将item提交给管道:yield item(爬虫类)
- 在官大类的process_item中接收item对象并且进行任意形式的持久化存储操作(管道类)
- 在配置文件中开启管道
- 细节:
- 将爬取的数据进行备份?
- 一个管道类对应一种平台的持久化存储
- 有多个管道类是否意味着多个管道类都可以接受到爬虫文件提交的item?
- 只有优先级最高的管道才可以接受到item,剩下的管道类是需要从优先级最高的管道类中接收item
- 基于Spider父类进行全站数据的爬取
- 全站数据的爬取:将所有页码对应的页面数据进行爬取
- 手动请求的发送(get):
yield scrapy.Request(url,callback)
- 对yield的总结:
- 向管道提交item的时候:yield item
- 手动请求发送:yield scrapy.Request(url,callback)
- 手动发起post请求:
yield scrapy.FormRequest(url,formdata,callback):formdata是一个字典表示的是请求参数
虎牙全站爬取(多页面)
定义一个
import scrapy from huyaAll.items import HuyaallItem class HuyaSpider(scrapy.Spider): name = 'huya' # allowed_domains = ['www.ccc.com'] start_urls = ['https://www.huya.com/g/xingxiu'] url = 'https://www.huya.com/cache.php?m=LiveList&do=getLiveListByPage&gameId=1663&tagAll=0&page=%s' def parse(self, response): li_list = response.xpath('//*[@id="js-live-list"]/li') all_data = [] for li in li_list: title = li.xpath('./a[2]/text()').extract_first() # 去【】 author = li.xpath(' ./span/span[1]/i/text()').extract_first() hot = li.xpath('./ span / span[ 2] / i[2]/text()').extract_first() # print(title,author,hot) # dic = { # 'title':title, # 'author':author, # 'hot':hot # } # all_data.append(dic) # return all_data item = HuyaallItem() item['title'] = title item['author'] = author item['hot'] = hot yield item # 提交给管道 print(1) for page in range(2, 5): new_url = format(self.url % page) print(2) yield scrapy.Request(url=new_url, callback=self.parse_other) def parse_other(self, response): print(3) print(response.text) # 解析方法没有写
害!难受
哥们自己解析了一下
for page in range(2,3): new_url = format(self.url % page) yield scrapy.Request(url=new_url, callback=self.parse_other, meta={'item': item}) def parse_other(self, response,): item = response.meta['item'] s = '' htmlBody = response.xpath('//text()').extract() for aa in htmlBody: s = s + str(aa) res = json.loads(s) res_data = res['data']['datas'] for i in res_data: item['title'] = i['roomName'] item['author'] = i['nick'] item['hot'] =i['totalCount'] yield item
- scrapy五大核心组件
引擎(Scrapy)
用来处理整个系统的数据流处理, 触发事务(框架核心)
调度器(Scheduler)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
下载器(Downloader)
用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
爬虫(Spiders)
爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
项目管道(Pipeline)
负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过 几个特定的次序处理数据。
- scrapy的请求传参
- 作用:实现深度爬取。
- 使用场景:如果使用scrapy爬取的数据没有存在同一张页面中
- 传递item:yield scrapy.Request(url,callback,meta)
- 接收item:response.meta
import scrapy from moivePro.items import MoiveproItem class MovieSpider(scrapy.Spider): name = 'movie' # allowed_domains = ['www.xxx.com'] start_urls = ['http://www.4567kan.com/index.php/vod/show/class/喜剧/id/1.html'] url = 'http://www.4567kan.com/index.php/vod/show/class/喜剧/id/1/page/%s.html' page = 1 def parse(self, response): print('正在爬取第{}页电影。。。'.format(self.page)) li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li') url_h = 'http://www.4567kan.com' for li in li_list: item = MoiveproItem() name = li.xpath('./div/div/h4/a').extract_first() item['name'] = name # 请求传参:Requset将一个字典{meta=}传递给回调函数 detail_url = url_h + li.xpath('./div/div/h4/a/@href').extract_first() yield scrapy.Request(detail_url, callback=self.parse_other, meta={'item': item}) if self.page < 5: self.page += 1 new_url = format(self.url % self.page) yield scrapy.Request(new_url, callback=self.parse) def parse_other(self, response): # 接收请求传参的数据(字典) item = response.meta['item'] desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[3]/text()').extract_first() item['desc'] = desc yield item
- 提升scrapy爬取数据的效率
- 在配置文件中进行相关的配置即可:
增加并发:
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
降低日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO’
禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False
禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False
减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s
- scrapy的中间件
- 爬虫中间件
- 下载中间件(***):处于引擎和下载器之间
- 作用:批量拦截所有的请求和响应
- 为什么拦截请求
- 篡改请求的头信息(UA伪装)
1、在设置里面打开下载中间键
2、不在设置里面写UA
3、在middlewares.py中重写 ,class MiddleproDownloaderMiddleware:、
可以创建按一个UA池
# Define here the models for your spider middleware # # See documentation in: # https://docs.scrapy.org/en/latest/topics/spider-middleware.html from scrapy import signals # useful for handling different item types with a single interface from itemadapter import is_item, ItemAdapter import random # class MiddleproSpiderMiddleware: # # Not all methods need to be defined. If a method is not defined, # # scrapy acts as if the spider middleware does not modify the # # passed objects. # # @classmethod # def from_crawler(cls, crawler): # # This method is used by Scrapy to create your spiders. # s = cls() # crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) # return s # # def process_spider_input(self, response, spider): # # Called for each response that goes through the spider # # middleware and into the spider. # # # Should return None or raise an exception. # return None # # def process_spider_output(self, response, result, spider): # # Called with the results returned from the Spider, after # # it has processed the response. # # # Must return an iterable of Request, or item objects. # for i in result: # yield i # # def process_spider_exception(self, response, exception, spider): # # Called when a spider or process_spider_input() method # # (from other spider middleware) raises an exception. # # # Should return either None or an iterable of Request or item objects. # pass # # def process_start_requests(self, start_requests, spider): # # Called with the start requests of the spider, and works # # similarly to the process_spider_output() method, except # # that it doesn’t have a response associated. # # # Must return only requests (not items). # for r in start_requests: # yield r # # def spider_opened(self, spider): # spider.logger.info('Spider opened: %s' % spider.name) user_agent_list = [ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 " "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24" ] class MiddleproDownloaderMiddleware: # 拦截请求 def process_request(self, request, spider): # 进行UA伪装 request.headers['User-Agent'] = random.choice(user_agent_list) print(request.headers['User-Agent']) return None # 拦截所有的响应 def process_response(self, request, response, spider): return response # 拦截发生异常的请求对象 def process_exception(self, request, exception, spider): pass # def spider_opened(self, spider): # spider.logger.info('Spider opened: %s' % spider.name)
- 修改请求对应的ip(代理)
# Define here the models for your spider middleware # # See documentation in: # https://docs.scrapy.org/en/latest/topics/spider-middleware.html from scrapy import signals # useful for handling different item types with a single interface from itemadapter import is_item, ItemAdapter import random # class MiddleproSpiderMiddleware: # # Not all methods need to be defined. If a method is not defined, # # scrapy acts as if the spider middleware does not modify the # # passed objects. # # @classmethod # def from_crawler(cls, crawler): # # This method is used by Scrapy to create your spiders. # s = cls() # crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) # return s # # def process_spider_input(self, response, spider): # # Called for each response that goes through the spider # # middleware and into the spider. # # # Should return None or raise an exception. # return None # # def process_spider_output(self, response, result, spider): # # Called with the results returned from the Spider, after # # it has processed the response. # # # Must return an iterable of Request, or item objects. # for i in result: # yield i # # def process_spider_exception(self, response, exception, spider): # # Called when a spider or process_spider_input() method # # (from other spider middleware) raises an exception. # # # Should return either None or an iterable of Request or item objects. # pass # # def process_start_requests(self, start_requests, spider): # # Called with the start requests of the spider, and works # # similarly to the process_spider_output() method, except # # that it doesn’t have a response associated. # # # Must return only requests (not items). # for r in start_requests: # yield r # # def spider_opened(self, spider): # spider.logger.info('Spider opened: %s' % spider.name) user_agent_list = [ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 " "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24" ] class MiddleproDownloaderMiddleware: # 拦截请求 def process_request(self, request, spider): # 进行UA伪装 request.headers['User-Agent'] = random.choice(user_agent_list) print(request.headers['User-Agent']) # 代理 request.meta['proxy'] = 'http://163.204.94.131:9999' print(request.meta['proxy']) return None # 拦截所有的响应 def process_response(self, request, response, spider): return response # 拦截发生异常的请求对象 def process_exception(self, request, exception, spider): pass # def spider_opened(self, spider): # spider.logger.info('Spider opened: %s' % spider.name)
- 为什么拦截响应
- 篡改响应数据,篡改响应对象
- 爬取网易新闻的新闻标题和内容
- selenium在scrapy中的使用流程
- 在爬虫类中定义一个bro的属性,就是实例化的浏览器对象
- 在爬虫类重写父类的一个closed(self,spider),在方法中关闭bro
- 在中间件中进行浏览器自动化的操作
- 作业:
- 网易新闻
- http://sc.chinaz.com/tupian/xingganmeinvtupian.html网站中的图片数据进行爬取