ip代理加速器23邻近云速捷_Scrapy 设置代理终极宝典
总结了一下在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 = ['http://httpbin.org/ip'] # 修改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 http://httpbin.org/robots.txt> (referer: None)
2019-08-20 19:19:40 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://httpbin.org/ip> (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 = ['http://httpbin.org/ip']
def start_requests(self): # 控制爬虫发出的第一个请求
proxy = "http://180.175.2.68: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 http://httpbin.org/ip> (failed 1 times): TCP connection timed out: 10060: 由于连接方在一段时间后没有正确答
复或连接的主机没有反应,连接尝试失败。.
2019-08-20 21:38:23 [scrapy.downloadermiddlewares.retry] DEBUG: Retrying <GET http://httpbin.org/ip> (failed 2 times): TCP connection timed out: 10060: 由于连接方在一段时间后没有正确答
复或连接的主机没有反应,连接尝试失败。.
2019-08-20 21:38:23 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://httpbin.org/ip> (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 = ['http://httpbin.org/ip']
def start_requests(self):
proxy = "http://180.175.2.68:8060"
yield scrapy.Request(self.start_urls[0], meta={"proxy": proxy})
def parse(self, response):
print("parse-->", response.text)
proxy = "http://47.94.89.87: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 http://httpbin.org/ip> (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 http://httpbin.org/ip> (referer: http://httpbin.org/ip)
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 = ['http://httpbin.org/ip']
def parse(self, response):
print("parse-->", response.text)
我们来编写一个代理中间件,中间件写在middlewares.py
文件中:
class TestProxyMiddleware(object):
def process_request(self, request, spider):
proxy = "http://47.94.89.87: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 https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
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 --> http://47.94.89.87:3128
2019-08-20 22:26:00 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://httpbin.org/ip> (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'] = b'Basic ' + auth
request.meta['proxy'] = 'http://' + proxy
代理隧道: 这是我比较喜欢用的代理方式,动态切换IP的事情交给代理商,我们将每个请求通过中间件转发给代理商,代理商将结果返回给我,至于他们是怎么获取的,我们不用关心,当然我们要提前测试代理隧道是不是每次请求都换了IP,再使用。
这里的坑比较多...未完待续...准备写几个常用的代理中间件直接贴出来。
主要处理代理的去除过滤,返回的响应错误重试, 不同方法分离处理, 多个代理隧道同时使用等。
和scrapy对代理隧道的验证问题。