跳到主要内容Scrapy 框架配置免费代理 IP 及爬虫防封方法 | 极客日志Python
Scrapy 框架配置免费代理 IP 及爬虫防封方法
Scrapy 配置免费代理 IP 是爬虫防封的重要手段。本文介绍了三种配置方式:直接在 Request 指定、通过下载中间件随机切换、动态获取代理。重点讲解了代理筛选脚本编写、settings.py 配置(如下载延迟、User-Agent)以及处理异常状态码的重试逻辑。同时提供了使用免费代理的注意事项,包括避免高频请求、优先高匿代理及法律合规建议。
MongoKing0 浏览 在爬虫开发中,IP 封禁是最常见的阻碍之一。Scrapy 作为 Python 生态中最强大的爬虫框架,通过合理配置代理 IP 可以有效规避单 IP 访问频率限制,降低被封风险。
一、免费代理 IP 的获取与筛选
在配置代理前,首先要解决'代理从哪来'的问题。免费代理 IP 虽然稳定性差,但胜在成本低,适合小规模爬虫场景。
1.1 免费代理 IP 的获取渠道
市面上有很多免费代理 IP 分享平台,这类平台会定期更新公开的代理资源,涵盖 HTTP/HTTPS 等类型,很多提供 API 接口获取,能满足基础的爬虫使用需求。
1.2 代理有效性筛选
免费代理的可用率通常不足 10%,必须先筛选出存活的 IP 才能使用。以下是一个简单的代理检测脚本:
import requests
import time
def check_proxy(proxy):
"""
检测代理是否可用
:param proxy: 代理格式 'http://ip:port'
:return: True/False
"""
test_url = "http://httpbin.org/ip"
timeout = 5
try:
response = requests.get(
test_url, proxies={"http": proxy, "https": proxy}, timeout=timeout
)
if response.status_code == 200:
print(f"代理可用:{proxy}")
return True
except Exception as e:
print(f"代理不可用:{proxy}, 原因:{str(e)[:50]}")
return False
if __name__ == "__main__":
proxy_list = [
"http://112.14.47.6:52024",
"http://180.122.151.186:3000",
"http://223.241.78.143:8080"
]
valid_proxies = []
for proxy in proxy_list:
if check_proxy(proxy):
valid_proxies.append(proxy)
print(f"可用代理列表:{valid_proxies}")
- 测试地址优先选择
httpbin.org/ip,可直接返回当前出口 IP,验证代理是否生效
- 超时时间建议设置为 3-5 秒,过长会降低筛选效率,过短会误判可用代理
- 免费代理存活时间短,建议每次爬取前重新筛选
二、Scrapy 中配置代理 IP 的 3 种方式
Scrapy 配置代理的核心是修改请求的 meta 参数或通过下载中间件(Downloader Middleware)实现,以下是 3 种实战方案,从简单到进阶逐步讲解。
2.1 方式 1:直接在 Request 中指定(单次生效)
适合临时测试或少量请求的场景,直接在生成 Request 时添加代理参数:
import scrapy
class ProxyTestSpider(scrapy.Spider):
name = "proxy_test"
allowed_domains = ["httpbin.org"]
start_urls = ["http://httpbin.org/ip"]
def start_requests(self):
proxy = "http://112.14.47.6:52024"
for url in self.start_urls:
yield scrapy.Request(
url=url,
callback=self.parse,
meta={"proxy": proxy}
)
def parse(self, response):
self.logger.info(f"响应结果:{response.text}")
优点:简单直接,无需额外配置;缺点:无法自动切换代理,复用性差
2.2 方式 2:通过下载中间件实现代理池随机切换(推荐)
这是生产环境中最常用的方案,通过自定义下载中间件,每次请求从代理池中随机选择一个 IP,实现自动切换。
步骤 1:编写代理中间件(middlewares.py)
import random
from scrapy import signals
class ProxyMiddleware:
"""自定义代理中间件,实现随机切换代理 IP"""
def __init__(self, proxy_list):
self.proxy_list = proxy_list
@classmethod
def from_crawler(cls, crawler):
proxy_list = crawler.settings.getlist("PROXY_LIST")
return cls(proxy_list)
def process_request(self, request, spider):
"""在请求发送前添加代理"""
if self.proxy_list:
proxy = random.choice(self.proxy_list)
request.meta["proxy"] = proxy
spider.logger.info(f"当前使用代理:{proxy}")
return None
def process_response(self, request, response, spider):
"""处理响应,若返回异常状态码则更换代理重试"""
if response.status in [403, 407, 503, 504]:
spider.logger.warning(f"代理失效,状态码:{response.status}")
if self.proxy_list:
new_proxy = random.choice(self.proxy_list)
request.meta["proxy"] = new_proxy
return request.copy()
return response
def process_exception(self, request, exception, spider):
"""处理请求异常,更换代理重试"""
spider.logger.error(f"请求异常:{exception}")
if self.proxy_list:
new_proxy = random.choice(self.proxy_list)
request.meta["proxy"] = new_proxy
return request.copy()
步骤 2:配置 settings.py
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': None,
'your_project_name.middlewares.ProxyMiddleware': 750,
}
PROXY_LIST = [
"http://112.14.47.6:52024",
"http://180.122.151.186:3000",
"http://223.241.78.143:8080",
]
COOKIES_ENABLED = False
DOWNLOAD_DELAY = 2
RANDOMIZE_DOWNLOAD_DELAY = True
DEFAULT_REQUEST_HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
}
RETRY_TIMES = 3
RETRY_HTTP_CODES = [403, 407, 500, 502, 503, 504]
步骤 3:编写测试爬虫
import scrapy
class ProxyPoolSpider(scrapy.Spider):
name = "proxy_pool"
allowed_domains = ["httpbin.org"]
start_urls = ["http://httpbin.org/ip"]
def parse(self, response):
self.logger.info(f"出口 IP: {response.text}")
yield scrapy.Request(
url="http://httpbin.org/get",
callback=self.parse_get
)
def parse_get(self, response):
self.logger.info(f"GET 请求响应:{response.text[:200]}")
2.3 方式 3:动态获取免费代理(进阶)
免费代理列表需要定期更新,手动维护效率低,可通过爬虫自动抓取代理分享平台的 IP,实时更新代理池。
import random
import requests
from scrapy import signals
from lxml import etree
class DynamicProxyMiddleware:
"""动态获取免费代理的中间件"""
def __init__(self):
self.proxy_list = []
self.refresh_proxy_list()
def refresh_proxy_list(self):
"""从代理分享平台抓取并筛选可用代理"""
url = "https://www.66daili.com/get-ip/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}
try:
response = requests.get(url, headers=headers, timeout=10)
html = etree.HTML(response.text)
ip_list = html.xpath('//tr/td[2]/text()')
port_list = html.xpath('//tr/td[3]/text()')
temp_proxies = [f"http://{ip}:{port}" for ip, port in zip(ip_list, port_list)]
self.proxy_list = [p for p in temp_proxies if self.check_proxy(p)]
print(f"更新代理池,可用代理数量:{len(self.proxy_list)}")
except Exception as e:
print(f"获取代理失败:{e}")
def check_proxy(self, proxy):
"""检测代理有效性"""
test_url = "http://httpbin.org/ip"
try:
resp = requests.get(test_url, proxies={"http": proxy}, timeout=3)
return resp.status_code == 200
except:
return False
def process_request(self, request, spider):
"""每次请求前检查代理池,为空则刷新"""
if not self.proxy_list:
self.refresh_proxy_list()
if self.proxy_list:
proxy = random.choice(self.proxy_list)
request.meta["proxy"] = proxy
return None
三、免费代理 IP 使用避坑指南
- 不要过度依赖免费代理:免费代理可用率低(通常 < 10%)、存活时间短(分钟级),仅适合小规模、低频率爬虫,大规模爬取建议使用付费代理池或自建代理。
- 避免请求频率过高:即使使用代理,短时间内对同一网站发起大量请求仍会被封,务必设置
DOWNLOAD_DELAY(建议 2-5 秒),并开启 RANDOMIZE_DOWNLOAD_DELAY。
- 优先选择高匿代理:免费代理分透明、匿名、高匿三种,只有高匿代理能完全隐藏真实 IP,透明代理会暴露真实 IP,等于没用。
- 处理代理失效重试:一定要在中间件中处理 403/503 等状态码和连接异常,自动更换代理重试,否则爬虫会频繁中断。
- 不要爬取敏感网站:部分网站对爬虫监控严格,即使使用代理也可能被封,且可能涉及法律风险,爬取前需确认网站 robots 协议和相关法规。
四、完整配置验证
2026-02-25 10:00:00 [proxy_pool] INFO: 当前使用代理:http:
2026-02-25 10:00:02 [proxy_pool] INFO: 出口 IP: {"origin":"112.14.47.6"}
2026-02-25 10:00:04 [proxy_pool] INFO: 当前使用代理:http:
2026-02-25 10:00:06 [proxy_pool] INFO: GET 请求响应:{"args":{},"headers":{"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8","Host":"httpbin.org","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","X-Amzn-Trace-Id":"Root=1-67e3b8c6-1234567890abcdef12345678"},"origin":"180.122.151.186","url":"http://httpbin.org/get"}
若日志中显示的 origin 为代理 IP,说明配置成功。
总结
- Scrapy 配置免费代理的核心是通过
meta["proxy"] 参数为请求添加代理,推荐使用下载中间件实现代理池随机切换,兼顾灵活性和易用性;
- 免费代理必须先筛选再使用,且要处理代理失效后的重试逻辑,否则会导致爬虫效率极低;
- 代理只是防封手段之一,需配合下载延迟、随机 UA、禁用 Cookie 等配置,才能最大程度降低被封风险。
免费代理适合学习和小规模爬取场景,若需稳定的爬虫服务,建议结合付费代理池、分布式爬虫等方案,进一步提升爬虫的稳定性和效率。
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown 转 HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
- HTML 转 Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online