scrapy中间件之下载中间件使用(网易新闻爬取)
scrapy项目中的middlewarse.py中间件
爬虫中间件:目前先不介绍
下载中间件(需要在settings.py中开启)
(1)请求处理函数:process_request(self, request, spider)
可以针对url请求指定UA伪装、配置代理等功能(UA伪装可以在settings.py中进行全局配置,代理配置更倾向于在异常处理函数,大部分异常都是因为ip的问题)
1 def process_request(self, request, spider): 2 #UA伪装 3 # request.headers['User-Agent']=random.choice(UA_list) 4 5 #ip代理配置(一般更多的放在process_exception异常处理函数中) 6 # request.meta['proxy']='http[s]://ip:port' 7 return None
(2)响应处理函数:process_response(self, request, response, spider)
对于一些网页请求,立即相应的数据可能不完全,页面部分内容是通过触发滚轮或者下拉操作才会动态加载的数据,因此获取的到数据并不是完整的,需要对响应对象进行篡改(比如通过selenium模拟浏览器操作获取到完整数据)后返回。
(3)异常处理函数:process_exception(self, request, exception, spider)
对于请求异常处理,一般可以更换ip设置代理操作
1 def process_exception(self, request, exception, spider): 2 #对请求异常进行修正 3 #更换代理(一定要 return request将请求返回以便再次发起) 4 # request.meta['proxy']='http[s]://ip:port' 5 # return request 6 pass
网易新闻爬取案例:
分析页面可以获知不同板块内容都是页面下拉动态加载的:国内、国际、军事、航空、无人机这几个板块内容都是标题都是在div中的一个a标签中,因此统一来进行爬取解析!
1.新建爬虫项目
scrapy startproject firstPro cd firstPro scrapy genspider middlewareTest www.xxx.com
2.编写爬虫文件middlewareTest.py
1 # -*- coding: utf-8 -*- 2 import scrapy 3 from firstPro.items import FirstproItem 4 from selenium import webdriver 5 6 7 class MiddlewaretestSpider(scrapy.Spider): 8 name = 'middlewareTest' 9 # allowed_domains = ['www.xxx.com'] 10 start_urls = ['https://news.163.com/'] 11 plate_urls=[]#存放板块的url,以便在下载中间件次改请求获取完整标题数据 12 def __init__(self): 13 self.bro=webdriver.Chrome(executable_path=r'E:\Python项目\爬虫\day110_20190809(全站爬取、分布式爬虫)\firstPro\firstPro\spiders\chromedriver.exe')#初始化浏览器实例 14 def parse(self, response): 15 #解析首页标题板块 16 li_list=response.xpath('//div[@class="ns_area list"]/ul/li') 17 print(len(li_list)) 18 #确定爬取的板块 19 index_list=[4,5,7,8,9] 20 for index in index_list: 21 item=FirstproItem() 22 plate=li_list[index-1].xpath('./a/text()').extract_first() 23 url=li_list[index-1].xpath('./a/@href').extract_first() 24 self.plate_urls.append(url) 25 item['plate']=plate 26 # 对每个板块进行发起请求,获取标题信息 27 yield scrapy.Request(url,callback=self.parse_title,meta={"item":item}) 28 break 29 #对每个板块的新闻标题进行解析,但是新闻标题都是动态加载的,因此直接的响应对象不完整,需要通过下载中间件对新闻板块标题获取进行处理 30 #解决思路:为获取板块完整标题内容,需要模拟浏览器下拉操作,结合使用selenuim在下载中间件进行操作 31 def parse_title(self, response): 32 item=response.meta['item'] 33 #解析每个板块中的新闻标题 34 div_list=response.xpath('//div[@class="ndi_main"]/div') 35 for div in div_list: 36 title=div.xpath('./div/div[1]/h3/a/text()').extract_first() 37 url=div.xpath('./div/div[1]/h3/a/@href').extract_first() 38 item["title"]=title 39 #对每个标题详情发起请求 40 yield scrapy.Request(url,callback=self.parse_detail,meta={"item":item}) 41 42 def parse_detail(self,response): 43 item = response.meta['item'] 44 #解析每个标题对应的详细新闻内容 45 content="".join(response.xpath('//*[@id="endText"]//text()').extract()) 46 item["content"]=content 47 yield item 48 49 # 程序全部结束的时候被调用 50 def closed(self, spider): 51 print('结束爬虫!!!') 52 self.bro.quit()
3.定义items.py字段属性
1 import scrapy 2 3 class FirstproItem(scrapy.Item): 4 # define the fields for your item here like: 5 # name = scrapy.Field() 6 #新闻板块 7 plate=scrapy.Field() 8 #新闻标题 9 title=scrapy.Field() 10 #新闻详情 11 content=scrapy.Field() 12 pass
4.管道pipelines.py持久化
1 import redis 2 class FirstproPipeline(object): 3 #持久化存储在redis数据库中 4 conn=None 5 # def open_spider(self,spider): 6 # self.conn=redis.Redis(host="127.0.0.1",port=6379) 7 8 def process_item(self, item, spider): 9 # self.conn.lpush('wangyi',dict(item)) 10 print(item) 11 return item
5.settings.py配置
1 #UA伪装 2 USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" 3 4 #robots协议 5 ROBOTSTXT_OBEY = False 6 7 #输出日志等级 8 LOG_LEVEL="ERROR" 9 10 #打开下载中间件 11 DOWNLOADER_MIDDLEWARES = { 12 'firstPro.middlewares.FirstproDownloaderMiddleware': 543, 13 } 14 15 #打开管道 16 ITEM_PIPELINES = { 17 'firstPro.pipelines.FirstproPipeline': 300, 18 }