返回博客

如何在Python requests中设置代理进行解析、API和自动化:带代码示例的完整指南

完整的Python requests库代理连接指南——从基本设置到IP轮换和在解析和自动化时绕过封锁。

📅2026年4月3日
```html

如果您的 Python 脚本收到 403 错误、验证码或 IP 禁止——这意味着目标网站已经注意到您。将代理连接到 requests 库可以解决这个问题:您更改 IP 地址,绕过地理限制,并在多个地址之间分配负载。在本指南中——从基本连接到高级轮换,提供真实的代码示例。

在 Python 脚本中使用代理的原因

大多数网站和 API 会跟踪进入请求的 IP 地址。如果一个地址每分钟发送 100 个以上的请求——它将被阻止。这是 Wildberries、Ozon、Avito、Google、Instagram 和其他数百个平台使用的标准防止机器人保护措施。代理允许通过具有不同 IP 地址的中间服务器发送请求,使您对保护系统不可见。

下面是 Python 中代理的主要任务:

  • 解析市场——从 Wildberries、Ozon、Yandex.Market 收集价格而不被 IP 阻止
  • 竞争对手监控——每 5-15 分钟定期向竞争对手网站发送请求
  • 处理有限制的 API——在多个 IP 之间分配请求,以避免超过速率限制
  • 地理定位测试——检查网站在不同国家和地区的外观
  • 表单和注册自动化——从不同 IP 创建帐户或填写表单
  • SEO 监控——从俄罗斯和其他国家的不同地区获取排名

没有代理,即使是写得很好的解析器也会在几个小时的工作后遇到阻止。通过正确设置的 IP 轮换,同样的脚本可以不间断地工作数周。

在 requests 中的基本代理设置

requests 库本身支持代理——无需额外的包。代理通过请求参数中的字典 proxies 传递。

最简单的示例——单个请求的 HTTP 代理:

import requests

proxies = {
    "http": "http://123.45.67.89:8080",
    "https": "http://123.45.67.89:8080",
}

response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
# {'origin': '123.45.67.89'}
  

请注意:在字典 proxies 中需要指定两个键——httphttps。如果只指定一个,第二个协议的请求将直接发送而不使用代理。这是新手常犯的错误,导致真实 IP 泄漏。

为了确保代理正常工作,请使用服务 httpbin.org/ip——它返回请求来源的 IP 地址。如果响应中您看到的是代理服务器的 IP,而不是您自己的——一切设置正确。

HTTP、HTTPS 和 SOCKS5 代理:区别和代码示例

代理有不同类型,每种类型适合不同的任务。在 Python requests 的上下文中,了解三种主要协议之间的区别非常重要:

类型 URL 中的协议 速度 支持 UDP 最佳场景
HTTP http:// 解析 HTTP 网站
HTTPS https:// 解析受保护的网站
SOCKS5 socks5:// 完全匿名,支持任何协议

在 Python 中使用 SOCKS5 需要安装额外的包:

pip install requests[socks]
# 或单独安装:
pip install PySocks
  

安装后,SOCKS5 代理的连接如下:

import requests

# SOCKS5 代理
proxies = {
    "http": "socks5://123.45.67.89:1080",
    "https": "socks5://123.45.67.89:1080",
}

response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
  

SOCKS5 是需要匿名性任务的首选协议。与 HTTP 代理不同,SOCKS5 不会添加 X-Forwarded-For 头,这可能会泄露您的真实 IP。

带用户名和密码的代理

大多数付费代理服务使用用户名和密码进行身份验证。这是标准做法——没有授权,代理将不会允许您的请求。在 requests 库中,授权数据直接传递到代理的 URL 中。

import requests

# 格式:协议://用户名:密码@主机:端口
proxy_url = "http://myuser:[email protected]:8080"

proxies = {
    "http": proxy_url,
    "https": proxy_url,
}

response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.status_code)
print(response.json())
  

如果密码或用户名中包含特殊字符(例如 @#%),则需要进行 URL 编码。为此,请使用 urllib.parse 模块:

import requests
from urllib.parse import quote

username = "myuser"
password = "p@ss#word!"  # 特殊字符

# URL 编码用户名和密码
encoded_user = quote(username, safe="")
encoded_pass = quote(password, safe="")

proxy_url = f"http://{encoded_user}:{encoded_pass}@123.45.67.89:8080"

proxies = {
    "http": proxy_url,
    "https": proxy_url,
}

response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
  

💡 安全建议

永远不要在脚本代码中硬编码用户名和密码。使用环境变量或 .env 文件与 python-dotenv 库。这样可以避免在 GitHub 上发布代码时意外泄露凭据。

代理轮换:自动更换 IP 进行解析

一个代理——仍然是一个 IP 地址,可能会被阻止。真正的防止封禁的方式是轮换:每个请求(或每 N 个请求)都使用新的 IP。以下是实现轮换的几种方法。

方法 1:从列表中随机选择

import requests
import random

# 代理列表
proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

def get_random_proxy():
    proxy = random.choice(proxy_list)
    return {"http": proxy, "https": proxy}

# 解析 10 个页面并轮换 IP
urls = [f"https://example.com/page/{i}" for i in range(1, 11)]

for url in urls:
    proxies = get_random_proxy()
    try:
        response = requests.get(url, proxies=proxies, timeout=10)
        print(f"URL: {url} | IP: {proxies['http'].split('@')[1]} | 状态: {response.status_code}")
    except requests.RequestException as e:
        print(f"错误: {e}")
  

方法 2:通过 itertools 循环轮换

import requests
import itertools

proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

# 创建一个无限循环的代理列表
proxy_cycle = itertools.cycle(proxy_list)

def get_next_proxy():
    proxy = next(proxy_cycle)
    return {"http": proxy, "https": proxy}

# 每个请求使用下一个代理
for i in range(9):
    proxies = get_next_proxy()
    response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
    print(f"请求 {i+1}: {response.json()['origin']}")
  

对于每小时数千个请求的工业任务,建议使用 住宅代理,它们内置自动轮换——提供商在每个请求中自动更换 IP,通过单个端点,您无需手动管理地址列表。

通过会话使用代理:持久连接和 Cookie

当需要在一个会话中进行多个请求(例如,登录然后进行请求)时,请使用对象 requests.Session()。它在请求之间保存 Cookie、头和代理设置——无需在每次调用中单独传递代理。

import requests

# 创建带代理的会话
session = requests.Session()
session.proxies = {
    "http": "http://user:[email protected]:8080",
    "https": "http://user:[email protected]:8080",
}

# 添加头以模拟浏览器
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Accept-Language": "ru-RU,ru;q=0.9",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
})

# 步骤 1:授权
login_data = {"username": "myuser", "password": "mypass"}
session.post("https://example.com/login", data=login_data)

# 步骤 2:使用 Cookie 和代理进行请求
response = session.get("https://example.com/dashboard")
print(response.status_code)

# 步骤 3:关闭会话
session.close()
  

使用 Session 在性能上也更有效:TCP 连接被重用,而不是为每个请求重新打开。在解析 1000 个以上的页面时,这会显著提高速度。

错误、超时处理和自动重试

代理服务器可能不可用、响应缓慢或返回连接错误。可靠的解析脚本应能够处理这些情况,并在失败时自动切换到其他代理。

import requests
import random
import time

proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

def fetch_with_retry(url, max_retries=3, timeout=10):
    """
    进行请求并在错误时自动更换代理。
    返回 Response 对象或在尝试耗尽时返回 None。
    """
    available_proxies = proxy_list.copy()
    random.shuffle(available_proxies)

    for attempt, proxy_url in enumerate(available_proxies[:max_retries], 1):
        proxies = {"http": proxy_url, "https": proxy_url}
        try:
            response = requests.get(
                url,
                proxies=proxies,
                timeout=timeout,
                headers={"User-Agent": "Mozilla/5.0"}
            )
            response.raise_for_status()  # 在 4xx/5xx 时引发异常
            print(f"✓ 尝试 {attempt} 成功")
            return response

        except requests.exceptions.ProxyError:
            print(f"✗ 尝试 {attempt}:代理不可用—— {proxy_url}")
        except requests.exceptions.Timeout:
            print(f"✗ 尝试 {attempt}:超时—— {proxy_url}")
        except requests.exceptions.HTTPError as e:
            print(f"✗ 尝试 {attempt}:HTTP 错误 {e.response.status_code}")
            if e.response.status_code == 403:
                print("  → 收到封禁,尝试下一个代理...")
        except requests.exceptions.RequestException as e:
            print(f"✗ 尝试 {attempt}:一般错误—— {e}")

        time.sleep(1)  # 尝试之间的暂停

    print(f"✗ {url} 的所有 {max_retries} 次尝试已用尽")
    return None

# 使用
result = fetch_with_retry("https://httpbin.org/ip")
if result:
    print(result.json())
  

请注意 raise_for_status()——此方法在 HTTP 状态 4xx 和 5xx 时会自动引发异常。没有它,脚本会将即使是 403(封禁)或 429(请求超限)的响应视为成功。

通过环境变量使用代理:安全存储数据

requests 库会自动读取环境变量 HTTP_PROXYHTTPS_PROXY。这使得无需在代码中存储凭据,并且可以轻松在代理之间切换,而无需更改脚本。

在终端中设置变量(Linux/macOS):

export HTTP_PROXY="http://user:[email protected]:8080"
export HTTPS_PROXY="http://user:[email protected]:8080"
export NO_PROXY="localhost,127.0.0.1"
  

或者通过 .env 文件与 python-dotenv 库:

# .env 文件(添加到 .gitignore 中!)
HTTP_PROXY=http://user:[email protected]:8080
HTTPS_PROXY=http://user:[email protected]:8080
  
# Python 脚本
from dotenv import load_dotenv
import requests
import os

load_dotenv()  # 加载 .env 中的变量

# requests 自动使用 HTTP_PROXY 和 HTTPS_PROXY
response = requests.get("https://httpbin.org/ip")
print(response.json())

# 或者明确从环境变量中获取:
proxies = {
    "http": os.getenv("HTTP_PROXY"),
    "https": os.getenv("HTTPS_PROXY"),
}
response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
  

⚠️ 重要:NO_PROXY 变量

变量 NO_PROXY 允许排除特定地址不使用代理。务必将 localhost127.0.0.1 添加到其中,以确保本地请求不通过代理。

真实场景:解析市场、使用 API 和自动化

让我们看看开发人员最常遇到的三个实际场景。

场景 1:从市场解析价格

在监控 Wildberries 或 Ozon 的价格时,重要的是模拟真实用户的行为:传递正确的浏览器头,在请求之间添加延迟并轮换 IP。对于这个任务,数据中心代理 非常合适——它们在处理大量数据时快速且便宜。

import requests
import time
import random

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": "application/json, text/plain, */*",
    "Accept-Language": "ru-RU,ru;q=0.9",
    "Referer": "https://www.wildberries.ru/",
}

PROXIES = [
    {"http": "http://user:[email protected]:8080",
     "https": "http://user:[email protected]:8080"},
    {"http": "http://user:[email protected]:8080",
     "https": "http://user:[email protected]:8080"},
]

def get_product_price(article_id: int) -> dict:
    """根据 Wildberries 的文章 ID 获取商品价格。"""
    url = f"https://card.wb.ru/cards/v1/detail?appType=1&curr=rub&nm={article_id}"
    proxies = random.choice(PROXIES)

    try:
        resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        product = data["data"]["products"][0]
        return {
            "id": product["id"],
            "name": product["name"],
            "price": product["salePriceU"] / 100,  # 价格以分为单位
        }
    except (requests.RequestException, KeyError, IndexError) as e:
        return {"error": str(e)}

# 解析多个文章 ID 并添加延迟
articles = [12345678, 87654321, 11223344]
for article in articles:
    result = get_product_price(article)
    print(result)
    time.sleep(random.uniform(1.5, 3.0))  # 随机延迟 1.5-3 秒
  

场景 2:通过代理使用 API

一些 API 限制来自同一 IP 的请求数量(速率限制)。在多个代理之间分配请求可以绕过此限制:

import requests
import itertools
from typing import Optional

class ProxyAPIClient:
    """通过代理轮换与 API 交互的客户端。"""

    def __init__(self, api_key: str, proxy_list: list):
        self.api_key = api_key
        self.proxy_cycle = itertools.cycle(proxy_list)
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        })

    def _get_proxy(self) -> dict:
        proxy = next(self.proxy_cycle)
        return {"http": proxy, "https": proxy}

    def get(self, url: str, **kwargs) -> Optional[dict]:
        proxies = self._get_proxy()
        try:
            resp = self.session.get(url, proxies=proxies, timeout=10, **kwargs)
            resp.raise_for_status()
            return resp.json()
        except requests.RequestException as e:
            print(f"API 请求失败:{e}")
            return None

# 使用
proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

client = ProxyAPIClient(api_key="your_api_key", proxy_list=proxy_list)
data = client.get("https://api.example.com/products")
  

场景 3:地理定位测试

市场营销人员和 SEO 专家经常检查网站在不同地区的外观。通过来自所需位置的代理,可以自动化此过程:

import requests

# 来自不同地区的代理
regional_proxies = {
    "莫斯科":        "http://user:[email protected]:8080",
    "圣彼得堡": "http://user:[email protected]:8080",
    "新西伯利亚":   "http://user:[email protected]:8080",
    "美国":           "http://user:[email protected]:8080",
}

url = "https://example.com/prices"

for region, proxy_url in regional_proxies.items():
    proxies = {"http": proxy_url, "https": proxy_url}
    try:
        resp = requests.get(url, proxies=proxies, timeout=15)
        print(f"[{region}] 状态: {resp.status_code} | "
              f"大小: {len(resp.content)} 字节")
    except requests.RequestException as e:
        print(f"[{region}] 错误: {e}")
  

如何选择适合您任务的代理类型

选择代理类型直接影响您项目的成功。便宜的数据中心代理可能在某些任务中表现良好,而在其他任务中完全失败。以下是选择的实用指南:

任务 代理类型 原因
解析市场(Wildberries、Ozon) 住宅代理 看起来像普通用户,更少被封禁
解析公开数据、新闻 数据中心 快速、便宜、足够匿名
与 Facebook API、Instagram 的交互 移动代理 社交网络更信任移动 IP
地理定位测试 带地理定位的住宅代理 精确的地理定位,真实的目标区域 IP
高负载解析(每小时 10k+ 请求) 数据中心(池) 在大规模下的速度和成本
授权和帐户交互 住宅或移动代理 更少触发反欺诈系统

对于需要最大可靠性和在与受保护网站交互时最小封禁风险的任务,开发人员通常选择 移动代理——它们使用真实移动运营商(MTS、Beeline、Megafon)的 IP 地址,这些地址极少进入封禁列表。

使用代理前的检查清单

  • ✅ 通过 httpbin.org/ip 检查 IP——您的真实地址是否可见?
  • ✅ 检查速度——响应时间不应超过 2-3 秒
  • ✅ 通过 blocklist.deipqualityscore.com 确保代理不在封禁列表中
  • ✅ 通过 ipinfo.io 检查地理位置——是否与预期区域一致?
  • ✅ 在目标网站上进行一次请求测试,然后再启动完整脚本
  • ✅ 确保 HTTPS 流量也通过代理(字典中两个键都存在)

结论

在 Python requests 中设置代理并不复杂,但需要关注细节。值得记住的主要原则是:在代理字典中始终指定两个键(httphttps),在多步骤场景中使用 Session,务必处理错误和超时,并将凭据存储在环境变量中,而不是代码中。

对于每天数千个请求的工业解析,手动代理列表是不够的——需要轮换。如果您正在解析像 Wildberries 或 Ozon 这样的受保护市场,或者与社交网络交互,或进行地理定位测试,建议尝试 住宅代理——它们提供高水平的信任,支持通过单个端点自动轮换 IP,这大大简化了您的脚本代码。

```