中间件这绝对是个老生常谈的话题了。遥想当年,第一次接触中间件的概念还是在使用ThinkPHP5.1框架中,后来在使用laravel5.8框架的时候,也是用了框架中的中间件,二者是何其的相似~
跑题了跑题了,今天看的是python框架scrapy的中间件。虽然语言不同,但是中间件的原理都是相同的。这一点没什么质疑的。
Scrapy的下载中间件分为:爬虫中间件、下载中间件
下载中间件scrapy框架为我们定义了拦截请求(process_request)和拦截响应(process_response)、拦截异常请求(process_exception)其余的方法没啥用,可以删除了。
接下来,我们来从字面分析一下三个请求的使用情况。.
拦截请求,当然就是拦截所有请求。
拦截异常请求,就是拦截异常的请求,拦截完异常的请求我们该怎么做呢?正常做法是处理异常请求,再次发起请求,那么我们如何处理异常请求呢?通常都是使用UA伪装。那么,按照正常逻辑,我们应该在拦截异常请求这里设置UA伪装。但是我的习惯一般是在拦截请求这里设置UA伪装。具体UA伪装如何设置,这个稍后再说。
拦截响应,对请求响应进行拦截。
一:设置UA池:
这里我们需要尽可能的给不同的请求提供不同的请求载体,因此我们这里可能需要定义一个UA池(其实也就是个列表)
这个去百度上查就好了,有很多类似的文章
我这里参考的是:blog.csdn.net/weixin_4909…
随机UA伪装:
def process_request(self, request, spider):
# UA伪装
request.headers['User-Agent'] = random.choice(self.user_agent_list)
return None
二:设置代理池:
一般请求发生异常基本上就是我们的请求IP被封禁了,那我们就需要在请求异常拦截中设置代理IP再次进行请求,那么按照正常道理来说,我们可能就需要准备多个ip,那我们这里就需要封装一个代理IP池,关于代理ip请求的部分请移步《Python爬虫(十二)代理在爬虫中的应用》
Ip池如下,我们这里区分http与https请求链接
PROXY_http = [
'121.41.166.74:8877',
'182.139.110.14:9000',
]
PROXY_https = [
'103.37.141.69:80',
'106.75.171.235:8080',
]
接下来,我们在请求异常拦截中对异常的请求做一下处理在转发至请求拦截:
def process_exception(self, request, exception, spider):
if request.url.split(':')[0] == 'http':
request.meta['proxy'] = 'http://'+random.choice(self.PROXY_http)
else:
request.meta['proxy'] = 'https://' + random.choice(self.PROXY_https)
# 将修正之后的请求对象进行重新发送
return request
然而,我们测试的时候一般情况下可能测试不到请求异常的情况,那我们直接将在异常拦截部分的代码直接搬到请求拦截即可。
def process_request(self, request, spider):
# UA伪装
request.headers['User-Agent'] = random.choice(self.user_agent_list)
# 显然,我们测试的时候一般情况下可能测试不到请求异常的情况,那我们直接将在异常拦截部分的代码直接搬到请求拦截即可。
if request.url.split(':')[0] == 'http':
request.meta['proxy'] = 'http://'+random.choice(self.PROXY_http)
else:
request.meta['proxy'] = 'https://' + random.choice(self.PROXY_https)
return None
到这儿,中间件的准备完成了,但是这并不意味着我们直接可以使用他了。使用它之前,我们仍需要在settings.py中开启一下中间件。
我们目前使用的是下载中间件:
DOWNLOADER_MIDDLEWARES = {
'scrpayProject.middlewares.ScrpayprojectDownloaderMiddleware': 543,
}
接下来,我们来定义一下爬虫文件:很简单,就是将页面的内容写入一个html文件中:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time : 2022/3/31 18:01
# @Author : camellia
# @Email : 805795955@qq.com
# @File : beike.py
# @Software: PyCharm
import scrapy
import asyncio
class BeikeSpider(scrapy.Spider):
name = 'middle'
start_urls = ['http://www.baidu.com/s?wd=ip']
def parse(self, response):
print(response.body.decode(response.encoding))
page_text = response.body.decode(response.encoding)
with open('ip.html','w',encoding='utf-8') as fp:
fp.write(page_text)
执行一下:
scrapy crawl middle
打开项目根目录,就会出现一个ip.html的文件。双击打开,理论上应该是这个样子的:
但是呢,我玩的次数比较多,爬取到的页面长这个样子:
且玩且珍惜吧。
最后放一下中间件的完整代码:
from scrapy import signals
import random
class ScrpayprojectDownloaderMiddleware:
# Not all methods need to be defined. If a method is not defined,
# scrapy acts as if the downloader 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
user_agent_list = [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60',
'Opera/8.0 (Windows NT 5.1; U; en)',
'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2 ',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)',
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0) ',
]
def process_request(self, request, spider):
# UA伪装
request.headers['User-Agent'] = random.choice(self.user_agent_list)
# 显然,我们测试的时候一般情况下可能测试不到请求异常的情况,那我们直接将在异常拦截部分的代码直接搬到请求拦截即可。
if request.url.split(':')[0] == 'http':
request.meta['proxy'] = 'http://'+random.choice(self.PROXY_http)
else:
request.meta['proxy'] = 'https://' + random.choice(self.PROXY_https)
return None
def process_response(self, request, response, spider):
return response
PROXY_http = [
'121.41.166.74:8877',
'182.139.110.14:9000',
'223.82.60.202:8060',
'119.165.64.183:9999',
'120.24.33.141:8000',
'112.6.117.178:8085'
]
PROXY_https = [
'103.37.141.69:80',
'106.75.171.235:8080',
'120.71.3.208:30003',
'58.220.95.42:10174',
'116.62.181.105:38888',
'1.71.132.64:30003',
'117.28.95.138:57114',
]
def process_exception(self, request, exception, spider):
if request.url.split(':')[0] == 'http':
request.meta['proxy'] = 'http://'+random.choice(self.PROXY_http)
else:
request.meta['proxy'] = 'https://' + random.choice(self.PROXY_https)
# 将修正之后的请求对象进行重新发送
return request
def spider_opened(self, spider):
spider.logger.info('Spider opened: %s' % spider.name)
有好的建议,请在下方输入你的评论。