Scrapy 设置代理终极宝典

最新更新-

没有及时更新,实在抱歉,最新代码放在我的网站了,各位看官移步参考,我就不重发了

Scrapy代理配置看这一篇就够了,直接拿去用​xudashuai.com/2021/06/11/scrapy%e4%bb%a3%e7%90%86%e9%85%8d%e7%bd%ae%e7%9c%8b%e8%bf%99%e4%b8%80%e7%af%87%e5%b0%b1%e5%a4%9f%e4%ba%86%ef%bc%8c%e7%9b%b4%e6%8e%a5%e6%8b%bf%e5%8e%bb%e7%94%a8/

总结了一下在scrapy项目中用过的所有代理方法,原因在于代理的种类有点多,代理商、自己的代理池接入方式多变,项目需求也是多变的,肯定没有一种万能的方式,不过我相信这里总有一个适合你。(我尽量写的详细一点:我怕以后我自己看不懂了。。)

常见代理有哪些呢?

最直接的IP:PORT代理;从代理池获取、代理商接口获取;最常见、最灵活、配置方式易懂;代理有效性需要自己检测;

带验证的USER:PASS@IP:PORT代理代理隧道配置起来会有坑;配置成功之后就简单了,不需要去关心代理失效问题;(我这种懒人最喜欢)

代理加载方式:

在spider代码中直接加代理适合小项目;或者是某类请求(在同一个方法中)需要走代理,其他的不需要;

写代理中间件(推荐)这种方式更加灵活,也最科学;

简单介绍完毕,让我们从头开始。。。。

创建测试项目:

创建项目:

> scrapy startproject test_spider > cd test_spider

创建爬虫:

scrapy genspider test test.com

目录结构:

├── scrapy.cfg └── test_spider ├── __init__.py ├── items.py ├── middlewares.py ├── pipelines.py ├── settings.py └── spiders ├── __init__.py └── test.py

非中间件方法:

修改一下spider的start_url, 此时我们的代码是这样:

test.py

# -*- coding: utf-8 -*- import scrapy ​ ​ class TestSpider(scrapy.Spider): name = test allowed_domains = [test.com] start_urls = []# 修改start_url,默认会返回request的IP ​ def parse(self, response): print(response.text) ​

运行爬虫:

> scrapy crawl test ... 2019-08-20 19:19:39 [scrapy.core.engine] DEBUG: Crawled (200) <GET ; (referer: None) 2019-08-20 19:19:40 [scrapy.core.engine] DEBUG: Crawled (200) <GET > (referer: None) { "origin": "116.206.152.179, 116.206.152.179" } ​ 2019-08-20 19:19:40 [scrapy.core.engine] INFO: Closing spider (finished) ...

正常返回了我的外网IP地址,帅···嗝屁,这样去做爬虫要被喷了···

此时,我去某代理商搞个IP回来用···

噔噔咚··· 搜到个免费的代理IP,试试看,首先要改一下代码:

test.py

# -*- coding: utf-8 -*- import scrapy ​ ​ class TestSpider(scrapy.Spider): name = test allowed_domains = [test.com] start_urls = [] ​ def start_requests(self):# 控制爬虫发出的第一个请求 proxy = ":8060" yield scrapy.Request(self.start_urls[0], meta={"proxy": proxy}) ​ def parse(self, response): print(response.text)

运行爬虫:

... 2019-08-20 21:38:02 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET > (failed 1 times): TCP connection timed out: 10060: 由于连接方在一段时间后没有正确答 复或连接的主机没有反应,连接尝试失败。. 2019-08-20 21:38:23 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET > (failed 2 times): TCP connection timed out: 10060: 由于连接方在一段时间后没有正确答 复或连接的主机没有反应,连接尝试失败。. 2019-08-20 21:38:23 [scrapy.core.engine] DEBUG: Crawled (200) <GET > (referer: None) { "origin": "180.175.2.68, 180.175.2.68" } ​ 2019-08-20 21:38:24 [scrapy.core.engine] INFO: Closing spider (finished) ... ​

结果是成功的,连接了两次,终于成功了,可见代理的质量也是很重要的;

这里稍微解释一下修改后的test.py文件:

增加了一个start_requests函数,默认情况下,scrapy在启动爬虫的时候会自动请求start_urls中的链接,请求成功会自动回调parse函数,这样的坏处是无法控制请求;重写start_requests方法,给请求加上代理,方法很简单,在meta中以字典的形式传递proxy参数即可;按照这种方式,理论上可以给每个方法的请求都自定义一个proxy。例如:

# -*- coding: utf-8 -*- import scrapy ​ ​ class TestSpider(scrapy.Spider): name = test allowed_domains = [test.com] start_urls = [] ​ def start_requests(self): proxy = ":8060" yield scrapy.Request(self.start_urls[0], meta={"proxy": proxy}) ​ def parse(self, response): print("parse-->", response.text) proxy = ":3128" yield scrapy.Request( self.start_urls[0], meta={"proxy": proxy}, callback=self.parse_first, dont_filter=True ) ​ def parse_first(self, response): print("parse_first-->", response.text)

运行爬虫:

... 2019-08-20 21:56:11 [scrapy.core.engine] DEBUG: Crawled (200) <GET > (referer: None) parse--> { "origin": "180.175.2.68, 180.175.2.68" } ​ 2019-08-20 21:56:13 [scrapy.core.engine] DEBUG: Crawled (200) <GET > (referer: ) parse_first--> { "origin": "47.94.89.87, 47.94.89.87" } ​ 2019-08-20 21:56:13 [scrapy.core.engine] INFO: Closing spider (finished) ... ​

看结果,每个方法都使用了不同的代理,这段代码就不解释了。

下面应该是带有验证信息的代理介绍···奈何我没找到那种代理···贴个帖子,感谢大佬整理的,我就不重复打字了Scrapy框架之如何给你的请求添加代理。

重点放在中间件部分。

中间件方法:

重头戏来了,中间件。使用过scrapy的童鞋应该多少都写过中间件,来满足业务需求。中间件是开关式的,在settings中打开关闭都很方便,一次编写,重复利用。

直接上···

普通代理中间件: 实现上半篇相同的功能。

首先还原test.py

# -*- coding: utf-8 -*- import scrapy ​ ​ class TestSpider(scrapy.Spider): name = test allowed_domains = [test.com] start_urls = [] ​ def parse(self, response): print("parse-->", response.text)

我们来编写一个代理中间件,中间件写在middlewares.py文件中:

class TestProxyMiddleware(object): def process_request(self, request, spider): proxy = ":3128" request.meta["proxy"] = proxy print(f"TestProxyMiddleware --> {proxy}")

代码很简单,简单解释一下。

中间件,可以理解为spider在发送和接受请求过程中的中间环节,在这里我们可以对每个请求进行重新编辑,包括请求的header和proxy这些,都可以重写编辑再让请求发送出去,这样的好处是,我们在spider里可以专心写逻辑代码部分,请求相关的配置,可以留在中间件统一处理。

在这个中间件里,我们自定义的中间件名字为TestProxyMiddleware,我们重写了一个方法process_request,看函数名就知道这是一个处理请求的方法,我们给经过这个中间件的所有请求的meta都加了一个proxy参数。

process_request函数有2个参数,request就是spider中发送的请求,我们可以重新编辑这个请求的属性。spider当前运行的spider相关信息,比如爬虫的名字可以在这里获取,对于不同名称的爬虫,同一个中间件中可以做到分离处理。

下面来测试一下···

先将我们写的中间件打开,在settings.py中,打开配置:

将默认的中间件注释掉,打开我们写的。

# Enable or disable downloader middlewares # See DOWNLOADER_MIDDLEWARES = { # test_spider.middlewares.TestSpiderDownloaderMiddleware: 543, test_spider.middlewares.TestProxyMiddleware: 543, }

运行爬虫:

... scrapy.extensions.logstats.LogStats] 2019-08-20 22:25:56 [scrapy.middleware] INFO: Enabled downloader middlewares: [scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware, ... test_spider.middlewares.TestProxyMiddleware, ... scrapy.downloadermiddlewares.stats.DownloaderStats] 2019-08-20 22:25:56 [scrapy.middleware] INFO: Enabled spider middlewares: ... 2019-08-20 22:25:56 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023 TestProxyMiddleware --> :3128 2019-08-20 22:26:00 [scrapy.core.engine] DEBUG: Crawled (200) <GET > (referer: None) parse--> { "origin": "47.94.89.87, 47.94.89.87" } ​ 2019-08-20 22:26:00 [scrapy.core.engine] INFO: Closing spider (finished) ... ​

可以看到,我们的中间件在项目中开启了,并且运行成功。

这样我们的爬虫代码是很简洁的,请求相关的事情,交给中间件处理。而且这样写了一个中间件,所有的爬虫都可以使用。

目前是很简单的将代理写死了,静态的,实际项目中,多数都需要不断换IP,这时就需要将proxy参数写成动态的,要么是从本地代理池获取一个,要么是代理商拿代理,这又是另一个故事了。

带有验证的代理也是一样,在中间件加上验证就可以了。这里就不写了。有童鞋用到不会写的话就度娘或者私信我。

我想了想,简单贴一下:

import base64 class ProxyMiddleware(object): def process_request(self,request,spider): proxy = "xxx.xxx.xxx.xxx:port" # 设置代理的认证信息 auth = base64.b64encode(bytes("USERNAME:PASSWORD", utf-8)) request.headers[Proxy-Authorization] = bBasic + auth request.meta[proxy] = http:// + proxy

代理隧道: 这是我比较喜欢用的代理方式,动态切换IP的事情交给代理商,我们将每个请求通过中间件转发给代理商,代理商将结果返回给我,至于他们是怎么获取的,我们不用关心,当然我们要提前测试代理隧道是不是每次请求都换了IP,再使用。

这里的坑比较多...未完待续...准备写几个常用的代理中间件直接贴出来。

主要处理代理的去除过滤,返回的响应错误重试, 不同方法分离处理, 多个代理隧道同时使用等。

和scrapy对代理隧道的验证问题。