一 . 先了解一下scrapy五大组件的工作流程
二 . 中间件的应用
从上图可以看出来,scrapy的工作流程中有两个中间件,分别是spider中间件,一个是Downloader中间件
这里我们先介绍一下Downloader中间件
爬虫文件(middle.py)
import scrapy
class MiddleSpider(scrapy.Spider):
name = 'middle'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.baidu.com/s?wd=ip']
def parse(self, response):
page_text = response.text
# 这里直接保存一个页面看一下效果,就不写到数据库啦
with open('./ip.html', 'w', encoding='utf-8') as f:
f.write(page_text)
middlewares.py
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 from scrapy import signals 2 import random 3 class MiddleproDownloaderMiddleware(object): 4 5 # 这是UA池,基本包含了各大浏览器的UA 6 user_agent_list = [ 7 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 " 8 "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", 9 "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 " 10 "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", 11 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 " 12 "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", 13 "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 " 14 "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", 15 "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 " 16 "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", 17 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 " 18 "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", 19 "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 " 20 "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", 21 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " 22 "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", 23 "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 " 24 "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", 25 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 " 26 "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", 27 "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " 28 "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", 29 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " 30 "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", 31 "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " 32 "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", 33 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " 34 "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", 35 "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 " 36 "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", 37 "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " 38 "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", 39 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 " 40 "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", 41 "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 " 42 "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24" 43 ] 44 PROXY_http = [ 45 '153.180.102.104:80', 46 '195.208.131.189:56055', 47 ] 48 PROXY_https = [ 49 '120.83.49.90:9000', 50 '95.189.112.214:35508', 51 ] 52 @classmethod 53 def from_crawler(cls, crawler): 54 # This method is used by Scrapy to create your spiders. 55 s = cls() 56 crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) 57 return s 58 59 # 可以处理拦截到所有的非异常的请求 60 # spider参数表示的就是爬虫类实例化的一个对象 61 def process_request(self, request, spider): 62 print('this is process_request()') 63 #UA伪装 64 request.headers['User-Agent'] = random.choice(self.user_agent_list) 65 66 # 测试:代理操作是否生效 67 request.meta['proxy'] = 'https://218.60.8.83:3129' 68 return None 69 # 拦截所有的响应 70 def process_response(self, request, response, spider): 71 72 return response 73 # 拦截发生异常的请求对象 74 def process_exception(self, request, exception, spider): 75 if request.url.split(':')[0] == 'https': 76 request.meta['proxy'] = 'https://'+random.choice(self.PROXY_https) 77 else: 78 request.meta['proxy'] = 'http://' + random.choice(self.PROXY_http) 79 80 def spider_opened(self, spider): 81 spider.logger.info('Spider opened: %s' % spider.name)
应用selenium和中间件对动态生成的 响应数据进行处理
爬虫文件(news.py)
# -*- coding: utf-8 -*-
import scrapy
from ..items import MiddleWareItem
from selenium import webdriver
class NewsSpider(scrapy.Spider):
# scrapy中应用selenium获取动态加载数据
browser = webdriver.Chrome(r'D:\spider\chromedriver.exe')
name = 'news'
sort_urls = [] # 放两个分类的url
# allowed_domains = ['www.xxx.com']
start_urls = ['https://news.163.com/']
def newsContentParse(self, response):
item = response.meta['item']
# 解析新闻内容,然后直接存储到item中
content_list = response.xpath('//div[@id="endText"]//text()').extract()
item['news_content'] = ''.join(content_list)
yield item
# 用来解析分类对应页面中的新闻数据
def parse_detail(self, response):
div_list = response.xpath('//div[@class="ndi_main"]/div')
for div in div_list:
news_title = div.xpath('.//h3/a/text()').extract_first()
detail_news_url = div.xpath('.//h3/a/@href').extract_first()
item = MiddleWareItem()
item['news_title'] = news_title
# 获取新闻的内容,进行请求传参,将item传递给下一个解析方法
yield scrapy.Request(url=detail_news_url, callback=self.newsContentParse, meta={'item': item})
def parse(self, response):
# 解析出两个分类对应url,为了使用一个爬虫函数,要保证这两个分类排版一样
li_list = response.xpath('//div[@class="ns_area list"]/ul/li')
# 取到国内和国际新闻的li标签索引
indexs = [3, 4]
sort_li_list = [] # 放置选出的两个分类对应的li
for index in indexs:
li = li_list[index]
sort_li_list.append(li)
# 解析出两个板块的url
for li in sort_li_list:
sort_url = li.xpath('./a/@href').extract_first()
self.sort_urls.append(sort_url)
# 对每一个分类的url发起请求获取详情页的页面源码数据
yield scrapy.Request(url=sort_url, callback=self.parse_detail)
middlewares.py
from scrapy import signals
from time import sleep
from scrapy.http import HtmlResponse
class MiddleWareDownloaderMiddleware(object):
def process_request(self, request, spider):
return None
# 改方法可以拦截到所有的响应对象(需求中需要处理的是指定的某些响应对象)
def process_response(self, request, response, spider):
"""
1.找出指定的响应对象进行处理操作
2.可以根据指定的请求对象定位到指定的响应对象
3.指定的请求对象可以通过请求的url进行定位
4.定位指定的url方法: spider.sort_urls
"""
sort_urls = spider.sort_urls
browser = spider.browser
if request.url in sort_urls:
"""
1.通过指定的url就定位到了指定request
2.通过指定request就定位到了指定的response(不符合需求的)
3.自己手动创建2个符合要求的新的响应对象
4.使用新的响应对象替换原始的响应对象
"""
browser.get(request.url) # 使用浏览器对两类板块对应的url发起请求
sleep(2) # 看清楚一点
js = 'window.scrollTo(0,document.body.scrollHeight)'
browser.execute_script(js)
sleep(2)
# 页面源码数据中包含来了动态加载出来的新闻数据
page_text = browser.page_source
# 手动创建一个新的响应对象,将page_text作为响应数据封装到响应对象中
return HtmlResponse(url=browser.current_url, body=page_text, encoding='utf-8', request=request)
# body参数表示的就是响应数据
return response
items.py
import scrapy
class MiddleWareItem(scrapy.Item):
news_title = scrapy.Field()
news_content = scrapy.Field()