在本指南中,你将学到:
- 什么是代理以及为什么要使用代理
- 什么是代理轮换以及何时需要它
- 如何在 Python 中旋转代理
- 在 Python 中旋转代理时常见的限制
让我们开始吧!
什么是代理?
代理是一种服务器,它在用户与网络资源之间充当中介。在 Internet 上,你可以把代理视作一个“中间人”,在请求方和被请求方之间转发请求和响应。
为什么在 Python 中使用代理?
当你使用代理向某网站发送请求时,请求会先经过代理服务器,然后由代理将请求转发给网站,并将响应返回给你。这个过程会隐藏你的真实 IP,使网站看来请求来自代理服务器而不是你的设备。
通常在网页请求自动化或网络爬取的场景下,你会想要使用代理。在这些场景里,Python 拥有丰富的库以及庞大的社区支持,是最适合进行网页爬取的语言之一。
什么是代理轮换?为什么需要它?
如果从同一 IP 地址发出过多请求,网站可能会通过速率限制或直接封禁 IP。在这种情况下,使用代理来进行代理轮换就能派上用场。
通过系统地在不同代理服务器之间切换来发送网络请求,是IP 地址轮换的最佳方式之一,这么做能够帮助你绕过常见的反爬虫策略,带来如下好处:
- 避免 IP 被封禁:将请求分散到多个 IP,让网站更难检测并封禁你的爬取行为。
- 绕过速率限制:许多网站会对单个 IP 在一定时间内的请求数量进行限制。代理轮换可以让你在某个 IP 达到请求上限后,继续使用其他 IP 进行爬取。
- 访问受地理位置限制的内容:一些网站会根据地理位置显示不同内容。使用来自不同国家/地区的代理来轮换,可以获取特定地区的内容。
在 Python 中如何旋转代理:三种方法
现在你已经了解了什么是代理以及为什么要对其进行轮换,接下来我们将从实践出发,使用不同的方式和库介绍如何在 Python 中旋转代理。
三个脚本示例中都会用到相同的目标站点,即/ip
端点,它会返回调用方的 IP 地址,非常适合用来测试代理是否在轮换。
让我们正式开始在 Python 中旋转代理吧!
环境要求
要复制文中的示例,你需要在本机安装 Python 3.7 及以上版本。
先决条件
假设你的主项目文件夹名为 proxy_rotation/
。在完成所有操作后,目录结构将如下所示:
proxy_rotation/
├── requests_file.py
├── async.py
├── scrapy_rotation/
└── venv/
其中:
requests_file.py
、async.py
分别存储使用 Requests 和 AIOHTTP 进行代理轮换的逻辑。scrapy_rotation/
是一个 Scrapy 项目文件夹,稍后会创建和初始化。venv/
包含虚拟环境。
你可以按以下方式创建 venv/
虚拟环境:
python -m venv venv
在 Windows 上,激活环境:
venv\Scripts\activate
在 macOS 或 Linux上,执行:
source venv/bin/activate
最后,你需要获取一个代理列表。本文示例可使用我们的 免费代理列表。
如何使用 Requests 在 Python 中旋转代理
在此部分,你将学习如何使用 Requests 库来实现 Python 中的代理轮换。
步骤 #1:安装依赖
在已激活的虚拟环境中,运行:
pip install requests
步骤 #2:定义轮换逻辑
在 requests_file.py
文件中添加如下代码:
import random
import requests
# Define a list of proxies and return a random one
def get_random_proxy():
proxies = [
"http://PROXY_1:PORT_X",
"http://PROXY_2:PORT_Y",
"http://PROXY_3:PORT_X",
# Add more proxies here...
]
# Randomly pick a proxy
return random.choice(proxies)
for i in range(3):
proxy_url = get_random_proxy()
proxies = {
"http": proxy_url,
"https": proxy_url,
}
response = requests.get("https://httpbin.io/ip", proxies=proxies)
print(response.text)
说明:
get_random_proxy()
函数存储了你获取的代理列表,并使用random.choice()
随机返回其中一个。for
循环会遍历随机选出的代理列表,并通过requests.get()
方法发送实际请求。更多用法可参考我们关于在 Python Requests 中使用代理的指南。
步骤 #3:运行脚本
执行:
python requests_file.py
预期返回结果示例:
{
"origin": "PROXY_3:PORT_K"
}
{
"origin": "PROXY_1:PORT_N"
}
{
"origin": "PROXY_2:PORT_P"
}
完美!你的脚本在请求时已成功轮换了不同的出口 IP。
如何使用 AIOHTTP 在 Python 中旋转代理
使用 Requests 随机选择代理的主要限制在于一次只能使用一个代理,需要等某次请求结束后才能开始下一次代理使用。
为避免这一限制,可以使用 AIOHTTP。该库允许你执行异步请求,从而以非阻塞方式同时使用多个代理。换言之,你可以通过并发方式发送请求并在其中轮换你的代理列表。详见我们关于异步网络爬取的介绍。
以下部分展示如何在 Python 中使用 AIOHTTP 进行代理轮换。
步骤 #1:安装依赖
在已激活的虚拟环境中,执行:
pip install aiohttp
步骤 #2:定义轮换逻辑
要在 Python 中使用 AIOHTTP 来旋转代理,请在 async.py 文件中写入以下代码:
import asyncio
import aiohttp
# Define a list of proxies
proxies_list = [
"http://PROXY_1:PORT_X",
"http://PROXY_2:PORT_Y",
"http://PROXY_3:PORT_X",
# Add more proxies here...
]
async def fetch_ip(session, proxy_address, attempt):
print(f"Attempt {attempt} using proxy: {proxy_address}")
async with session.get("https://httpbin.io/ip", proxy=proxy_address) as response:
json_response = await response.json()
print(f"Response from httpbin.io/ip (Attempt {attempt}):")
print(f"IP Address: {json_response.get('origin', 'Unknown')}")
print("-" * 40)
return json_response
async def main():
async with aiohttp.ClientSession() as session:
tasks = []
num_attempts = 3
for i in range(num_attempts):
# Rotate proxies using the modulus operator.
proxy_address = proxies_list[i % len(proxies_list)]
tasks.append(fetch_ip(session, proxy_address, i + 1))
# Run all requests concurrently
await asyncio.gather(*tasks)
# Launch the script
asyncio.run(main())
此代码实现了以下功能:
fetch_ip()
函数:接收 session、代理和尝试次数作为参数,向目标网站发起GET
请求并打印响应结果。main()
函数:- 通过
aiohttp.ClientSession()
方法创建 session 来管理 HTTP 连接。 - 设置一个任务列表来并发发送多个请求,以及请求次数。
- 使用取模运算(
i % len(proxies_list)
)进行轮询,以便在请求数量大于代理数量时也能重用代理。更多用法可阅读我们关于在 AIOHTTP 中设置代理的教程。 - 使用
asyncio.gather()
方法并发执行所有任务。
- 通过
步骤 #3:运行脚本
执行:
python async.py
预期输出结果:
Attempt 1 using proxy: http://PROXY_1:PORT_X
Attempt 2 using proxy: http://PROXY_2:PORT_Y
Attempt 3 using proxy: http://PROXY_3:PORT_Z
Response from httpbin.io/ip (Attempt 3):
IP Address: xxx.xxx.xxx.xxx
----------------------------------------
Response from httpbin.io/ip (Attempt 1):
IP Address: yyy.yyy.yyy.yyy
----------------------------------------
Response from httpbin.io/ip (Attempt 2):
IP Address: zzz.zzz.zzz.zzz
----------------------------------------
非常好!各次请求均成功使用不同 IP。
如何配合 Python Scrapy 进行代理轮换
在一篇早前文章中,我们提到可以通过Scrapy及其scrapy-rotating-proxies
库来实现 Python 中的代理轮换。
下面便是相关操作的简要实践!
步骤 #1:安装依赖
在已激活的虚拟环境中,执行:
pip install scrapy scrapy-rotating-proxies
步骤 #2:创建新的 Scrapy 项目
在主项目文件夹 proxy_rotation/
内,使用以下命令初始化一个新的 Scrapy 项目:
scrapy startproject scrapy_rotation
上述命令会新建一个名为 scrapy_rotation/
的子文件夹,其结构大致如下:
scrapy_rotation/
├── scrapy_rotation/
│ ├── __init__.py
│ ├── items.py # Defines the data structure for scraped items
│ ├── middlewares.py # Custom middlewares
│ ├── pipelines.py # Handles post-processing of scraped data
│ ├── settings.py # Project settings
│ └── spiders/ # Folder for all spiders
└── scrapy.cfg # Scrapy configuration file
然后进入 scrapy_rotation/
文件夹:
cd scrapy_rotation
接下来你可以创建一个新的爬虫来访问目标网站:
scrapy genspider rotation http://httpbin.io/ip
这条命令会在 spiders/
目录下生成 rotation.py
文件。
步骤 #3:定义轮换逻辑
可以在 settings.py
文件中添加以下设置来管理代理轮换:
# Enable the rotating proxies middleware
DOWNLOADER_MIDDLEWARES = {
"rotating_proxies.middlewares.RotatingProxyMiddleware": 610,
"rotating_proxies.middlewares.BanDetectionMiddleware": 620,
}
# List of proxies to rotate
ROTATING_PROXY_LIST = [
"http://PROXY_1:PORT_X",
"http://PROXY_2:PORT_Y",
"http://PROXY_3:PORT_Z",
# Add more proxies as needed
]
# Configure retry settings
RETRY_TIMES = 5 # Number of retries for failed requests
RETRY_HTTP_CODES = [500, 502, 503, 504, 408] # HTTP codes to retry
实现代理轮换的关键是 DOWNLOADER_MIDDLEWARES
中的 rotating_proxies.middlewares.RotatingProxyMiddleware: 610
配置,它负责从 ROTATING_PROXY_LIST
中选择代理,并为每个请求分配一个代理。
同时,rotating_proxies.middlewares.BanDetectionMiddleware: 620
配置可帮助识别 IP 是否被目标网站封禁。如果请求失败,该中间件会使用新代理重试请求。它与 RotatingProxyMiddleware
协同工作,自动避免已被封禁的代理。
接着,在 spiders/
文件夹中的 rotation.py
中编写以下内容:
import scrapy
class IpSpider(scrapy.Spider):
name = "ip_spider"
start_urls = ["http://httpbin.io/ip"]
def parse(self, response):
# Extract and print the IP address from the response
ip = response.json().get("origin")
self.log(f"IP Address: {ip}")
该类会启动爬虫并在每次请求时打印返回的 IP。
步骤 #4:运行脚本
使用 IpSpider
类的名称(即 ip_spider
)来启动爬虫:
scrapy crawl ip_spider
Scrapy 在命令行输出的信息会比较详细,如果一切正常,你将在大量输出信息中看到类似:
2025-02-18 14:55:17 [rotating_proxies.expire] DEBUG: Proxy <http://PROXY_1:PORT_X> is GOOD
2025-02-18 14:55:17 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://httpbin.io/robots.txt> (referer: None)
2025-02-18 14:55:24 [rotating_proxies.middlewares] INFO: Proxies(good: 1, dead: 0, unchecked: 2, reanimated: 0, mean backoff time: 0s) unchecked: 2, reanimated: 0, mean backoff time: 0s)
上述代理轮换方法的局限性
以上提到的几种代理轮换方法都非常实用,但也存在一些局限:
- 需要手动获取和管理代理列表。
- 包含不少模板化的代码。
- 如果代理本身不够优质,依旧有被禁 IP 的可能性。
如果你想要更高效、稳定的代理轮换方式,Bright Data 提供了市面上最佳的旋转代理之一。只需要一个单一的代理 URL 袖手整合到你的 HTTP 客户端或爬取库,就可以免去模板化轮换代码和手动管理的麻烦。
此方法的其它关键好处包括:
- 自动 IP 轮换,支持设置固定 IP
- 可使用 72+ 百万住宅 IP
- 可控制代理服务器所在的地理位置
- 支持 HTTP、HTTPS 和 SOCKS 协议
让代理管理更轻松——了解我们的 自动旋转代理!
总结
本文介绍了如何使用 Requests、AIOHTTP 和 Scrapy 这三种库,在 Python 中实现代理轮换。通过上文详述的步骤,你可以在代码里轻松添加轮换逻辑。
但同时,也需注意:
- 上述方法包含不少相关的“样板代码”,可维护性较低。
- 你需要自己管理并维护一个庞大的代理列表。
幸运的是,通过 Bright Data 的自动旋转代理,你可以避免这些麻烦,从而更高效地在 Python 中进行代理轮换。
Bright Data 拥有全世界顶尖的代理网络资源,为 500 强企业及逾 2 万客户提供服务,提供多种类型的代理:
- 数据中心代理 – 超过 770,000 个数据中心 IP。
- 住宅代理 – 在 195 个以上的国家拥有 7,200+ 万住宅 IP。
- ISP 代理 – 超过 700,000 个 ISP IP。
- 移动代理 – 超过 700 万移动 IP。
立即注册 Bright Data 的免费账号来测试我们各种代理与爬取解决方案吧!