写爬虫时用了代理还被封?Python 代理的那些隐藏坑,我替你踩明白了
作为一名编程讲师,我经常遇到学生抱怨:“我明明用了代理,为什么还是被网站封了?” 这个问题看似简单,但背后的坑却多得让人头疼。今天,我就从基础概念讲到高级用法,用真实代码带你绕过这些隐藏陷阱。无论你是刚入门的新手,还是经验丰富的开发者,这篇文章都能帮你少走弯路。## 基础概念:代理是什么?为什么用了还会被封?代理(Proxy)本质上是你的爬虫和目标网站之间的“中间人”。它把你的请求转发给网站,返回响应给你,这样网站看到的是代理的 IP,而不是你的真实 IP。但很多新手以为只要随便找个代理,就能高枕无忧了。错!网站的反爬虫机制不仅检查 IP,还会检查其他因素,比如:- 请求头(Headers):代理本身不会修改你的请求头,如果请求头暴露了你的真实信息(如 User-Agent 过于单一),封你没商量。- 请求频率:代理 IP 不是万能药。如果你用同一个代理 IP 每秒发 100 个请求,网站照样会认为这是恶意行为。- 代理质量:免费代理通常不稳定、速度慢,甚至本身就是“蜜罐”(用于追踪爬虫的陷阱)。所以,用了代理还被封,核心原因不是代理这个“工具”有问题,而是你的“使用方式”有漏洞。接下来,我会带你逐步排查这些问题。## 初级陷阱:只换 IP,不换请求头很多人写爬虫时,第一步就是找代理,然后直接套用,比如这样:pythonimport requests# 伪代码:获取代理proxy = {"http": "http://123.45.67.89:8080", "https": "http://123.45.67.89:8080"}# 用代理发送请求response = requests.get("https://example.com", proxies=proxy)print(response.status_code)这段代码看似正确,但实际运行后很可能被封。原因在于:requests 库默认发送的请求头(如 User-Agent)是 python-requests/2.x.x,这种标识在网站看来就是爬虫的特征。代理虽然换了 IP,但请求头没变,网站一看“哦,又是那个熟悉的 Python 爬虫”,直接封掉。解决方案:手动设置一个真实的浏览器 User-Agent,并且随机切换。### 完整代码示例 1:基础代理 + 随机 User-Agentpythonimport requestsimport random# 常见浏览器 User-Agent 列表USER_AGENTS = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"]def fetch_with_proxy(url, proxy): """使用指定代理和随机 User-Agent 发送请求""" headers = { "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" } try: response = requests.get(url, proxies=proxy, headers=headers, timeout=5) print(f"状态码: {response.status_code}, 使用代理: {proxy['http']}") return response except requests.exceptions.RequestException as e: print(f"请求失败: {e}") return None# 测试proxy = {"http": "http://123.45.67.89:8080", "https": "http://123.45.67.89:8080"}fetch_with_proxy("https://httpbin.org/ip", proxy)这个例子中,我们不仅用了代理,还模拟了真实浏览器的请求头。网站看到“Mozilla/5.0”这种标识,会更倾向于认为这是一个正常用户。但注意:这只是第一步,如果请求频率过高,仍然会被封。## 中级陷阱:忽略请求频率与 IP 池管理代理 IP 池是爬虫进阶的必备工具。但很多人的做法是:找一个代理 IP,然后循环使用,每隔 0.1 秒发一次请求。结果可想而知——代理 IP 被网站标记,然后封禁整个 IP 段。### 完整代码示例 2:带 IP 池和延时控制的爬虫pythonimport requestsimport timeimport random# 模拟一个代理 IP 池(实际使用中可以从代理服务商获取)PROXY_POOL = [ {"http": "http://111.222.33.44:8080", "https": "http://111.222.33.44:8080"}, {"http": "http://55.66.77.88:3128", "https": "http://55.66.77.88:3128"}, {"http": "http://99.100.101.102:80", "https": "http://99.100.101.102:80"}]def smart_scraper(url, target_count=10): """智能爬虫:随机代理 + 随机延时 + 重试机制""" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" } for i in range(target_count): # 随机选择一个代理 proxy = random.choice(PROXY_POOL) # 设置随机延时(1到3秒之间),模拟人类行为 delay = random.uniform(1, 3) print(f"请求 {i+1}/{target_count},使用代理: {proxy['http']},延时 {delay:.2f} 秒") time.sleep(delay) try: response = requests.get(url, proxies=proxy, headers=headers, timeout=5) if response.status_code == 200: print(f"成功获取数据,状态码: {response.status_code}") else: print(f"异常状态码: {response.status_code},可能被封") except requests.exceptions.ProxyError: print(f"代理 {proxy['http']} 失效,尝试下一个") continue except requests.exceptions.Timeout: print("请求超时,跳过") continue# 测试smart_scraper("https://httpbin.org/ip", target_count=5)这个代码的关键点在于:- IP 池:使用多个代理轮换,降低单个 IP 的请求频率。- 随机延时:random.uniform(1, 3) 让请求间隔不固定,更像人类操作。- 异常处理:代理失效时自动跳过,避免程序崩溃。但即使这样,如果你爬取的目标网站反爬虫力度很强(比如淘宝、知乎),仍然可能被封。这就引出了高级用法。## 高级用法:应对高级反爬虫机制当网站使用更复杂的手段(如检测浏览器指纹、JavaScript 渲染、IP 地理位置一致性)时,普通代理和延时策略就失效了。这里我分享两个高级技巧:1. 使用 Session 保持 Cookie:很多网站会通过 Cookie 跟踪会话。如果你每次请求都用新代理和新 Session,网站会认为你是不同用户,但如果你用同一个 Session 配合代理切换,会暴露你的真实行为。 – 正确做法:为每个代理创建独立的 Session,模拟不同用户。2. 使用 Headless 浏览器 + 代理:对于需要 JavaScript 渲染的网站,用 requests 无法获取数据。这时可以用 Selenium 或 Playwright 结合代理。### 高级示例:Playwright + 代理抓取动态页面pythonfrom playwright.sync_api import sync_playwrightimport timedef scrape_with_browser_and_proxy(url, proxy_server): """使用 Playwright 无头浏览器 + 代理""" with sync_playwright() as p: # 启动浏览器,配置代理 browser = p.chromium.launch( headless=True, # 无头模式 proxy={"server": proxy_server} ) context = browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" ) page = context.new_page() try: page.goto(url, timeout=30000) # 等待页面加载完成(模拟人类等待) page.wait_for_load_state("networkidle") # 获取页面内容 content = page.content() print(f"成功获取页面,长度: {len(content)} 字符") return content except Exception as e: print(f"抓取失败: {e}") return None finally: browser.close()# 测试(需要先安装 Playwright: pip install playwright && playwright install)scrape_with_browser_and_proxy("https://httpbin.org/ip", "http://123.45.67.89:8080")这个代码展示了如何用无头浏览器模拟真实用户,配合代理爬取动态内容。但注意:这种方法的资源消耗更大,速度也更慢,适合对付那些“硬骨头”网站。## 总结与避坑指南通过以上内容,你应该明白了:用了代理还被封,不是代理的错,而是你的策略太简单。以下是核心总结:1. 不要只依赖代理:代理只是 IP 层面的伪装,你还需要模拟请求头、Cookie、行为模式等。2. 代理质量决定下限:免费代理容易被封,建议使用付费代理服务或自建代理池。3. 频率控制是关键:无论用什么代理,高频率请求都会暴露你。4. 高级场景用浏览器自动化:对于动态网站或强反爬虫,requests 不够用,可以考虑 Playwright 或 Selenium。5. 日志和监控很重要:记录每个代理的成功率,及时剔除失效代理。最后,记住爬虫的核心原则——尊重网站的 robots.txt 和使用条款。写代码是为了学习,不是为了搞破坏。希望这篇文章能帮你避开那些坑,写出更稳定、更优雅的爬虫。如果你还有其他问题,欢迎在评论区留言,一起交流!



