跳转到内容

用 Python 抓取网站:如何使用代理绕过封锁

Кейсы
用 Python 抓取网站:如何使用代理绕过封锁

用 Python 抓取网站数据,尤其是大规模抓取时,必然会遇到为阻止自动化数据采集而设置的反爬机制。代理是应对这一挑战的根本方案:它是一层不可或缺的中间层,可以隐藏您的 IP 地址、轮换身份并实现地理定位,从而有效绕过目标网站施加的请求频率限制、IP 封禁和地区限制。

网页抓取在现代数据格局中的重要性

在当今的数字经济中,能否高效采集并分析公开的网络数据,是一项关键的竞争优势。企业将网页抓取用于众多场景:市场调研、竞争情报、价格监控、获客线索、情感分析以及学术研究等。Python 拥有 requestsBeautifulSoupSelenium 等强大的库生态,是开发复杂网页爬虫的首选语言。

然而,自动化数据采集本身往往与网站所有者的利益相冲突,这促使他们部署愈发复杂的反机器人和反抓取机制。这些措施旨在检测并阻止自动化访问,从而保护服务器资源、知识产权和用户隐私。抓取方常见的挑战包括:

  • IP 封禁:网站会识别并封禁在短时间内发出过多请求的 IP 地址。
  • 请求频率限制:对单个 IP 在特定时间段内可发出的请求数量设置上限。
  • CAPTCHA 验证码:用于区分真人用户与机器人的验证挑战。
  • User-Agent 字符串检查:检测非浏览器或过时的 user-agent 字符串。
  • 地区限制:根据用户的地理位置限制内容访问。
  • 蜜罐与陷阱:用于捕获自动化爬虫的隐藏链接或页面元素。
  • JavaScript 渲染内容:需要完整的浏览器环境才能渲染动态内容。

不解决这些问题就贸然进行大规模抓取,必然导致立即被封、数据集不完整以及计算资源浪费。直接用本地机器或云服务器的单个 IP 地址去抓取,对任何严肃的网页抓取项目来说都无法持续。

代理是稳健抓取的基石

代理充当您的 Python 爬虫与目标网站之间的中间服务器。爬虫不再直接连接网站,而是把请求发给代理服务器,再由代理转发到目标站点。网站看到的是代理服务器的 IP 地址,而不是您的 IP。正是这一基本机制让代理成为网页抓取中不可或缺的一环。

代理从几个关键方面直接解决反爬难题:

  • IP 轮换:通过一个包含大量不同 IP 地址的池来转发请求,代理可避免任何单个 IP 触发频率限制或被标记为可疑活动。每个请求或每一批请求都可以来自不同的 IP,模拟大量独立用户的行为。
  • 地理定位:位于特定国家或地区的代理可让爬虫访问受地区限制的内容。这对跨地区的市场调研或绕过区域内容封锁至关重要。例如 GProxy 提供丰富的地理定位选项,可在全球数百个位置中选择代理。
  • 匿名性与安全性:代理隐藏您的真实 IP 地址,在抓取过程中增加一层匿名性并保护您的身份。在处理敏感数据或竞争情报时尤为重要。
  • 负载分摊:在大规模抓取任务中,稳健的代理网络可将请求负载分散到多个 IP 地址,避免任何单个 IP 表现得像激进的机器人,并确保更快、更高效地获取数据。
  • 绕过封禁:若某个 IP 被封,爬虫可直接切换到池中另一个可用 IP,业务不中断地持续运行。

对任何严肃的网页抓取工作而言,接入高质量代理服务不是可选项,而是必需品。GProxy 提供多种专门针对这些需求设计的代理方案,提供成功采集数据所必需的可靠、高速且干净的 IP 地址。

了解代理类型,制定最优抓取策略

并非所有代理都一样。选对代理类型,对抓取工作的成败和效率至关重要。最佳选择取决于目标网站反爬机制的复杂程度、所需数据量以及您的预算。

住宅代理

住宅代理是互联网服务提供商(ISP)分配给真实家庭用户的 IP 地址。它们是与实体位置和设备关联的合法 IP 地址,因此在网站眼中可信度极高,看起来就像真人在上网。网站极难区分通过住宅代理发出的请求与真人用户发出的请求。

  • 优点:匿名性和信任度最高,非常适合绕过复杂的反爬系统,支持城市/州级别的地理定位,极少被封。
  • 缺点:由于要经过真实用户设备转发,通常比数据中心代理慢,成本更高。
  • 适用场景:抓取防护严密的网站(电商、社交媒体、机票聚合平台)、广告验证、品牌保护、以高成功率访问受地区限制的内容。GProxy 的住宅网络提供全球数百万 IP,即使面对最棘手的目标也能带来出色的成功率。

数据中心代理

数据中心代理是由第三方公司提供的 IP 地址,通常托管在大型数据中心,不与 ISP 或实际住宅地址关联。虽然它们速度快、性价比高,但其“数字指纹”有时更容易被高级反爬系统识别,尤其当大量请求来自同一子网时。

  • 优点:速度极快,单 IP 成本更低,适合对匿名性要求不高的高并发请求,可用池规模大。
  • 缺点:信任度低于住宅 IP,更容易被高级反爬系统检测和封禁,地理定位有限(通常只到国家/城市级别,不如住宅代理精细)。
  • 适用场景:抓取防护较弱的网站、以速度优先的大规模数据采集、访问公开信息(如新闻站点、通用目录)、SEO 监控。

移动代理

移动代理使用移动运营商分配给移动设备(智能手机、平板)的 IP 地址。由于其动态特性以及大量用户常常共用同一个移动 IP,它们是可信度最高的代理类型。网站很少封禁移动 IP,因为存在误封正常移动用户的风险。

  • 优点:信任度极高,非常适合绕过最激进的反爬系统,IP 高度动态。
  • 缺点:是最贵的代理类型,通常比数据中心代理慢,可用池较小。
  • 适用场景:抓取对移动端极敏感的网站、反爬措施极严格的社交媒体平台、App 数据采集。

共享代理与独享代理

  • 共享代理:这些 IP 由多个客户同时使用。价格更便宜,但存在被其他用户的恶意行为“污染”的风险。
  • 独享代理:这些 IP 仅分配给单一用户,可靠性更高、性能更好、历史记录更干净,非常适合关键的抓取任务。GProxy 为住宅代理和数据中心代理都提供独享选项。

HTTP/HTTPS 代理与 SOCKS5 代理

  • HTTP/HTTPS 代理:这是应用层代理,主要面向网页流量(HTTP/HTTPS)。它们理解 Web 协议,能够修改请求头。大多数网页抓取任务都使用这类代理。
  • SOCKS5 代理:这是更底层的代理,可处理任意类型的流量和协议(不限于 HTTP/HTTPS)。通用性更强,但通常不解析网络流量,只做原始数据转发。适用于非网页类抓取任务,或需要更高匿名性的场景。
特性 住宅代理 数据中心代理 移动代理
信任度 最高(真实 ISP IP) 中等(商用 IP) 极高(移动运营商 IP)
速度 中等 非常高 中等偏低
成本 低到中等 非常高
被检测风险 非常低 中等偏高 极低
地理定位 非常精细(城市/州) 国家/主要城市 国家/主要城市
最适合 复杂、防护严密的站点;特定地区数据 高并发、防护较弱的站点;对速度要求高的任务 极敏感站点;社交媒体;App 数据

从 GProxy 这样可靠的服务商处选择正确的代理类型,是构建高效且稳健的网页抓取系统的第一步。

用 Python 抓取网站:如何使用代理绕过封锁

在 Python 中为网页抓取配置代理

借助常用库,将代理集成到 Python 抓取脚本中非常简单。下面分别介绍用于静态内容的 requests 和用于 JavaScript 渲染的动态内容的 Selenium

使用 requests

requests 库是 Python 中发起 HTTP 请求的事实标准,提供了配置代理的简单方式。

基础代理配置

把代理配置定义为一个字典,将协议映射到代理 URL。

import requests

# 替换为您的 GProxy 凭据和代理接入点
proxy_host = "proxy.gproxy.net"
proxy_port = 12345
proxy_user = "your_username"
proxy_pass = "your_password"

proxies = {
    "http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
    "https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
}

target_url = "http://httpbin.org/ip" # 一个显示您 IP 的简易服务

try:
    response = requests.get(target_url, proxies=proxies, timeout=10)
    response.raise_for_status() # 遇到错误状态码时抛出异常
    print(f"Request successful! IP used: {response.json()['origin']}")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")

对于 SOCKS5 代理,需在代理 URL 中指定 "socks5://"

proxies_socks5 = {
    "http": f"socks5://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
    "https": f"socks5://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
}

管理多个代理(简单轮换)

要持续抓取,您需要一个代理池和一套轮换机制。基础的轮询(round-robin)方式是不错的起点。

import requests
import random
import time

# GProxy 代理列表(替换为您的实际列表)
# 格式:"user:pass@host:port"
proxy_list = [
    "user1:[email protected]:12345",
    "user2:[email protected]:12345",
    "user3:[email protected]:12345",
    # ... 更多代理
]

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

target_url = "http://httpbin.org/ip"

for i in range(5): # 发送 5 次请求,轮换代理
    current_proxies = get_random_proxy()
    print(f"Attempting request {i+1} with proxy: {current_proxies['http'].split('@')[1]}")
    try:
        response = requests.get(target_url, proxies=current_proxies, timeout=15)
        response.raise_for_status()
        print(f"Success! Origin IP: {response.json()['origin']}")
    except requests.exceptions.RequestException as e:
        print(f"Request failed: {e}")
    time.sleep(random.uniform(1, 3)) # 加入随机延迟

使用 Selenium 处理动态内容

当网站高度依赖 JavaScript 渲染内容时,就需要像 Selenium 这样的无头浏览器自动化工具。您可以通过浏览器选项让 Selenium 使用代理。

在 Chrome 中配置代理(建议使用 undetected_chromedriver 提升隐蔽性)

为了更强的隐蔽性,通常更推荐 undetected_chromedriver 而非标准的 selenium.webdriver.Chrome,因为它会尝试绕过常见的机器人检测技术。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import undetected_chromedriver as uc
import time

# 替换为您的 GProxy 凭据和代理接入点
proxy_host = "proxy.gproxy.net"
proxy_port = 12345
proxy_user = "your_username"
proxy_pass = "your_password"

# 设置 Chrome 选项
chrome_options = Options()
# chrome_options.add_argument("--headless") # 取消注释以启用无头模式
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument(f"--proxy-server=http://{proxy_host}:{proxy_port}") # 用于 HTTP/HTTPS

# 对于需要认证的代理,Selenium 需要一个扩展
# 或者,若使用 undetected_chromedriver,通常可直接把凭据写进代理字符串
# 不过从稳健性考虑,处理认证时代理扩展通常更可靠。

# 在 Selenium 中处理认证代理的简单办法是使用代理扩展
# 为便于演示,这里假设代理不需要认证,或者
# 由 undetected_chromedriver 通过 --proxy-server 字符串处理认证。
# 若认证更复杂,则需要为代理扩展生成 CRX 文件。

# 初始化 undetected_chromedriver
driver = uc.Chrome(options=chrome_options)

# 如果代理需要认证且您没有使用扩展,
# 只要代理字符串格式正确,undetected_chromedriver 通常能够处理。
# 但在标准 Selenium 中,往往仍需要扩展。
# 我们尝试直接传入凭据,这在 UC 中有时是可行的。
# 注意:在标准 Selenium 中,这通常需要代理扩展或特定的 driver 配置。
# `uc.Chrome` 构造函数对 `user:pass@host:port` 格式的支持可能更好。

# UC 直接使用代理字符串的示例(可能有所不同)
# 如果您的 GProxy 住宅代理采用 IP 白名单,字符串中就不需要 user/pass。
# 如果需要 user/pass,`undetected_chromedriver` 库通常处理得更聪明。
# 为简单起见,这里只用不带认证的代理服务器参数,
# 或者假设该代理已加入 IP 白名单。
# 对于未加白名单的认证代理,通常需要使用代理扩展。

target_url = "http://httpbin.org/ip" # 或者一个重度依赖 JS 的动态站点

try:
    driver.get(target_url)
    print(f"Current URL: {driver.current_url}")
    # 在这里解析内容,例如 driver.find_element_by_tag_name("pre").text
    # 对于 httpbin.org/ip,IP 会直接显示在 body 或 pre 标签中。
    print(f"Page content (showing IP): {driver.find_element('tag name', 'body').text}")
except Exception as e:
    print(f"Selenium request failed: {e}")
finally:
    driver.quit()

在标准 Selenium 中使用需要认证的代理时,通常必须自行创建一个 Chrome 扩展来处理认证,过程较为繁琐。undetected_chromedriver 往往能简化这一点:它会尝试直接传递凭据,或要求代理使用 IP 白名单。

处理 User-Agent 和请求头

除了代理,轮换 user-agent 和其他 HTTP 请求头同样关键。网站会检查这些信息来识别机器人。请始终发送真实且不断轮换的 user-agent 字符串,并考虑 Accept-LanguageRefererConnection 等其他请求头。

import requests
import random

user_agents = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15",
]

def get_random_headers():
    return {
        "User-Agent": random.choice(user_agents),
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.5",
        "Connection": "keep-alive",
    }

# 配合 requests 的用法示例
headers = get_random_headers()
# response = requests.get(target_url, proxies=current_proxies, headers=headers)

错误处理

对任何生产级爬虫来说,稳健的错误处理都至关重要。这包括捕获连接错误、HTTP 状态码(如 403 Forbidden、429 Too Many Requests),并实现重试逻辑,必要时换用另一个代理。

import requests
import time

def make_request_with_retry(url, proxies, headers, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.get(url, proxies=proxies, headers=headers, timeout=20)
            response.raise_for_status() # 对错误响应(4xx 或 5xx)抛出 HTTPError
            return response
        except requests.exceptions.HTTPError as e:
            print(f"HTTP Error on attempt {attempt+1}: {e.response.status_code} - {e.response.reason}")
            if e.response.status_code in [403, 429]: # Forbidden 或 Too Many Requests
                print("Switching proxy and retrying...")
                # 在真实场景中,这里应换取一个新代理
                time.sleep(random.uniform(5, 10)) # 重试前先等待
            else:
                raise # 其他 HTTP 错误继续抛出
        except requests.exceptions.RequestException as e:
            print(f"Network/Connection Error on attempt {attempt+1}: {e}")
            print("Retrying with current proxy after delay...")
            time.sleep(random.uniform(3, 7)) # 等待网络问题恢复
    raise Exception(f"Failed to retrieve {url} after {max_retries} attempts.")

# 用法示例:
# response = make_request_with_retry(target_url, get_random_proxy(), get_random_headers())
用 Python 抓取网站:如何使用代理绕过封锁

高级代理管理与最佳实践

对于大规模、持续运行的抓取业务,简单的轮询式代理轮换并不总是够用。高级管理技巧可确保效率与可靠性,并把封禁降到最低。

代理池管理

管理良好的代理池是成功爬虫的骨架。它远不只是一份代理列表。

  • 加载代理:可从文件(CSV、JSON)、数据库,或直接通过代理服务商的 API 加载代理列表。GProxy 提供 API,便于集成和动态获取代理。
  • 智能轮换:不要止步于轮询,应实现智能轮换。若某个代理返回 403 或 429 状态码而失败,把它标记为“不可用”或“临时封禁”,并在一段时间内(如 10-30 分钟)避免使用。优先使用新鲜、未用过的代理。
  • 代理校验与健康检查:定期检查代理的健康状况和延迟。移除或标记那些持续缓慢、无法连接或返回错误内容的代理。用 httpbin.org/ip 这类服务做一次简单检查,即可确认连通性和 IP 地址。
  • 粘性会话:有些网站要求一系列请求保持同一个 IP 地址(如登录、加入购物车)。可使用 GProxy 的粘性住宅代理,它会在切换到新 IP 之前,将同一 IP 保持一段可配置的时间(如 10 分钟、30 分钟)。

频率限制与限速

即使使用了代理,从单个 IP(哪怕是轮换的 IP)过于激进地访问网站,仍可能触发封禁。请在请求之间加入延迟。

  • time.sleep()最简单的做法是在请求之间加入随机延迟(如 time.sleep(random.uniform(1, 5)))。随机延迟比固定延迟更接近真人行为。
  • 指数退避:请求失败时(如 429 状态),按指数递增的时长等待后再重试。例如先等 2 秒,再等 4 秒,然后 8 秒,依此类推。
  • 并发上限:控制对单个域名的并发请求数。即便使用不同代理,也不要同时对同一目标打开数百个连接。

使用 requests.Session() 管理会话

使用 requests.Session() 很有好处,因为它会在多次请求之间保留某些参数,例如 cookie 和连接池。这样可以提升性能,并有助于在通过同一代理发出的多个请求中保持一致的“身份”。

import requests

s = requests.Session()
s.proxies = get_random_proxy() # 为该会话设置代理
s.headers.update(get_random_headers()) # 为该会话设置请求头

try:
    response1 = s.get("http://example.com/page1")
    # 后续请求会复用 cookie 和连接
    response2 = s.get("http://example.com/page2")
except requests.exceptions.RequestException as e:
    print(f"Session request failed: {e}")

代理之外的隐蔽技巧

代理必不可少,但它只是整盘棋中的一枚棋子。要真正模拟真人行为、躲开高级机器人检测,还需要:

  • 真实的 User-Agent 字符串:如前所示,轮换一批当前主流浏览器的 user-agent。
  • 浏览器指纹:使用 Selenium 时,避开常见的 Selenium 检测特征。undetected_chromedriver 这类库对此有帮助。
  • Referer 请求头:发送真实的 Referer 头以模拟正常的页面跳转。
  • Cookie 管理:像真实浏览器那样接收并管理 cookie。requests.Session() 会自动处理这一点。
  • JavaScript 执行:对重度依赖 JavaScript 的站点,必须使用 Selenium 或 Playwright。请确保浏览器环境具备完整的浏览器能力。
  • 随机延迟:在动作与请求之间引入类似真人的、非均匀的延迟。

常见陷阱与排查

即便策略再好,抓取也是一场猫鼠游戏。了解常见陷阱有助于高效排查问题。

  • 代理耗尽:可用的新鲜、未被封的 IP 用完了。这在免费或低质量代理列表中很常见。投入使用 GProxy 这类服务商提供的大规模、多样化的高质量住宅代理池,可显著缓解该问题。
  • 代理质量差:使用不可靠、缓慢或早已“被污染”的代理。免费代理几乎总是浪费时间:它们往往超载、缓慢,或很快被封。请始终选择口碑良好的付费服务。
  • 配置错误:代理 URL 中的简单拼写错误、端口写错或认证信息不正确。请仔细核对代理字符串,确保与服务商的规范一致。
  • IP 之外的网站指纹识别:即使轮换了 IP,网站仍会用多种手段识别机器人,包括分析 user-agent、HTTP 请求头、浏览器特征(如屏幕尺寸、插件)、JavaScript 执行模式,甚至鼠标移动轨迹。如果代理质量不错却仍被封,就要仔细排查这些其他因素。
  • CAPTCHA 验证码:代理不能解决验证码。如果频繁遇到验证码,可考虑接入验证码识别服务(如 2Captcha、Anti-Captcha),或重新调整抓取模式,让它更不像机器人。
  • 地区不匹配:访问特定地区内容时用错了地理位置的代理。请确认目标内容所属地区,并从 GProxy 丰富的位置选项中选择相应代理。
  • SSL/TLS 错误:Python 版本过旧或缺少 SSL 证书,都可能导致访问 HTTPS 网站时报错,尤其是在经由代理转发时。请确保 Python 环境为最新版本并正确配置 SSL。

要点总结

面对复杂的反爬措施,用 Python 玩转网页抓取,根本上依赖一套稳健的代理策略。代理不只是附加项,而是不可或缺的组成部分:它通过隐藏身份、轮换 IP 地址、绕过地区限制,让持续、大规模的数据采集成为可能。

代理类型的选择——住宅代理主打高信任度、数据中心代理主打速度、移动代理主打极致隐蔽——至关重要,应与目标网站的防护强度以及项目的具体需求相匹配。在 Python 中有效地落地这些代理,并结合智能轮换、会话管理和其他隐蔽技巧,就能把脆弱的爬虫变成稳健的数据采集机器。

以下是提升抓取成功率的一些实用建议:

  1. 先小规模试跑并观察:在启动大规模抓取之前,务必先在目标网站上做小规模测试。观察它的行为、错误码以及响应的任何变化。这有助于您理解其反爬机制,并微调代理策略。
  2. 优先做好智能代理管理:不要停留在简单的轮询轮换。实现相应逻辑,剔除或临时拉黑失败的代理、优先使用健康的代理,并在必要时使用粘性会话。这种主动管理能显著提升数据获取成功率并减少停机时间。
  3. 选择优质代理服务商:不要贪图免费或廉价、不可靠的代理。它们最终只会带来挫败感、浪费开发时间并导致数据质量低下。请与 GProxy 这样口碑良好的服务商合作,其住宅代理、数据中心代理和移动代理构成的多样化高质量网络,可确保稳定的性能以及您所需的 IP 资源。
support_agent
GProxy Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.