scrapy入门(二)请求传参和中间件
scrapy的请求传参
作用 : 实现深度爬取
使用场景 : 爬取的数据没有在同一张页面
例如, 爬取电影首页全部电影的详情页信息
#请求传参: 让Request将一个数据值(字典)传递给回调函数 #在第一页中将item对象的第一个属性赋值,然后通过请求传参将item对象传过去 #手动发送get请求: model_index = [3,4,6,7,8] for index in model_list: li =li_list[index] model_url = li.xpath('xxxxxxx').extract_first() self.model_urls.append(model_url) #for li in li_list: #这种适用于所有的li标签都需要的情况下,当只需要某几个标签时,选用上面的方式 #... yield scrapy.Request(url=, callback=my_parse, meta={'item':item}) if self.page < 5: self.page += 1 new_url = format(self.url%self.page) yield scrapy.Request(url=new_url,callback=parse) def my_parse(self, response): #接受请求传参的数据,还原出item对象 item = response.meta['item'] #解析item对象需要的第二个属性 xxx = respnse.xpath('').extract_first() #给item对象的第二个属性赋值 item['xxx'] = xxx #还可以接着请求传参,这里不再演示 yield item
scrapy的中间件, 和管道一样, 需要在配置文件中开启中间件
下载中间件 : 批量拦截requests和response
作用:
- 修改请求的头信息
- 修改请求的ip地址 (代理模式)
- 修改响应对象(数据)
middlewares.py文件: 修改成如下形式
import scrapy #构建UA池,这样可以不在settings文件中写死 user_agent_list = [ 'xxxxxx', 'xxxxxxxxx', 'xxxxxxxxxxxxxxxxxxx' ] class SecondtestDownloaderMiddleware(object): #拦截正常请求 def process_request(self, request, spider): #进行UA伪装,构建UA池 request.headers['User-Agent'] = random.choice(user_agent_list) #代理,也可以构建自己的代理池 request.meta['proxy'] = 'xxxxxxxxxxxx' return None #拦截所有的响应 def process_response(self, request, response, spider): #拦截由于动态加载得到的不符合需求的响应对象 #request表示请求对应的??对象 #response表示所有的响应对象 #spider是SecondSpider类(爬虫源文件对应的类)的实例化对象 if request.url in spider.model_urls: #body 有selenium中的page_source返回 browser = spider.browser browser.get(request.url) sleep(3) page_text = browser.page_source new_response = HtmlResponse(url=request.url,body=page_text,encoding ='utf-8',request=request) return new_response else: return response return response #拦截发生异常的请求对象 def process_exception(self, request, exception, spider): #对异常的url请求进行修正 return request #重新发送
源文件中进行修改
#在爬虫类中定义一个属性model_urls =[]用来保存解析得到的li标签的url # from selenium import webdriver class xxx(scrapy.Spider): name = '' model_urls =[] browser = webdriver.Chrome(executable_path ='') #下面三个函数调用过程中可能出现请求传参的情况 def parse(self,response): pass def parse_model(self,response): pass def parse_new_detail(self,response): content = response.xpath('xxxx//text()').extract()#解析所有的文本内容,跨标签,返回的是列表 content = ''.jion(content) pass #该方法只会在程序结束时调用一次 def closed(self,spider): self.browser.quit()
提升爬取效率
- 增加并发: 32---->100
- 降低日志等级
- 不需要cookie的时候可以禁止,默认是开启. 设置为COOKIES_ENABLED = False为禁止
- 禁止重试RETRY_ENABLED = False
- DOWNLOAD_TIMEOUT = 1