圆海博客-探寻心灵的宁静

您现在的位置是:首页 > 博客 > 正文

博客

爬虫设置代理服务器使用方法!批量采集中的并发控制与日志记录

2026-09-19 08:46:44博客
做数据采集的朋友大多遇到过这样的场景:脚本刚跑得正欢,目标网站突然返回 403 或弹出验证码,任务被迫中断。问题的根源往往不是代码写得不好,而是同一个 IP 在短时间内请求太频……

做数据采集的朋友大多遇到过这样的场景:脚本刚跑得正欢,目标网站突然返回 403 或弹出验证码,任务被迫中断。问题的根源往往不是代码写得不好,而是同一个 IP 在短时间内请求太频繁。这时候,给爬虫设置代理服务器就成了刚需。但光有代理还不够——批量采集时如果并发不加控制、日志不做记录,再大的代理池也扛不住乱来的请求。这篇文章就把代理设置、并发控制、日志记录这三件事一次讲清楚。

一、爬虫为什么必须用代理服务器?

目标网站的反爬机制大多围绕 IP 展开:同一个 IP 短时间内请求次数过多、访问节奏过于规律,就会触发封禁。而你本机的出口 IP 只有一个,一旦被封,整个采集任务就瘫痪了。

代理服务器的作用,是在你和目标网站之间加一个”中转站”:请求先发给代理,由代理代替你去访问目标网站,再把结果传回来。配合 IP 轮换,每次请求换一个出口,目标网站看到的就是成百上千个”不同的访客”,封禁风险自然大幅下降。

当然,代理的质量直接决定采集效果。响应慢、可用率低的代理会让爬虫大量超时重试,反而更容易暴露。所以选代理时重点看三点:可用率、响应速度、IP 池规模

二、代理服务器设置方法:从原理到代码

以 Python 的 requests 库为例,设置代理只需要一个字典参数:

import requests

proxies = {
    "http": "http://用户名:密码@代理地址:端口",
    "https": "http://用户名:密码@代理地址:端口"
}

resp = requests.get(
    "https://目标网站.com/api/data",
    proxies=proxies,
    timeout=10
)
print(resp.status_code)

几个关键点要注意:

1. 带认证的代理写法。商业代理通常需要用户名密码认证,格式是 协议://用户名:密码@地址:端口。如果密码里包含 @、: 等特殊字符,需要先做 URL 编码。

2. 超时必须设置。不带 timeout 的请求一旦遇到劣质代理会无限挂起,拖垮整个采集流程,建议超时控制在 5~10 秒。

3. 用 Session 复用连接。批量采集时,requests.Session 可以复用 TCP 连接、减少握手开销,还能统一管理代理和请求头:

import requests

session = requests.Session()
session.proxies = {
    "http": "http://用户名:密码@代理地址:端口",
    "https": "http://用户名:密码@代理地址:端口"
}
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
})

resp = session.get("https://目标网站.com", timeout=10)

4. 搭建本地代理池,实现自动轮换。实际项目中不会只用一个代理,而是把多个可用 IP 放进列表,每次请求前随机取一个,失败就换下一个:

import random
import requests

# 代理列表(实际项目中从代理服务商控制台动态获取)
proxy_pool = [
    "http://用户名:密码@代理1:端口",
    "http://用户名:密码@代理2:端口",
    "http://用户名:密码@代理3:端口",
]

def get_with_proxy(url):
    for _ in range(3):  # 最多重试3次
        proxy = random.choice(proxy_pool)
        try:
            resp = requests.get(
                url,
                proxies={"http": proxy, "https": proxy},
                timeout=10
            )
            if resp.status_code == 200:
                return resp
        except requests.RequestException:
            continue
    return None

三、批量采集中的并发控制

代理解决了”IP 被封”的问题,但并发不加控制依然会把采集搞砸:开几百个线程同时狂发请求,目标网站会把你整个代理段的 IP 一起拉黑。并发控制的核心思路只有一句话——让请求节奏看起来像正常用户

1. 信号量限流:控制同时在途的请求数

最简单有效的手段是限制”同时在途”的请求数量。Python 异步方案里,用 Semaphore 一行代码就能实现:

import asyncio
import aiohttp

SEM = asyncio.Semaphore(10)  # 最多同时10个请求在途

async def fetch(session, url, proxy):
    async with SEM:  # 超出数量的请求会在这里排队等待
        try:
            async with session.get(url, proxy=proxy, timeout=10) as resp:
                text = await resp.text()
                return resp.status, text
        except Exception:
            return None, None

async def main(urls):
    proxy = "http://用户名:密码@代理地址:端口"
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, u, proxy) for u in urls]
        results = await asyncio.gather(*tasks)
        return results

asyncio.run(main(url_list))

2. 动态调速:根据响应情况自动调整节奏

固定并发并不总是最优解。更聪明的做法是动态调整:当成功率下降、开始出现验证码时,自动降低并发、拉长请求间隔;一切正常时再逐步恢复速度。这套机制类似 TCP 的拥塞控制思想,能显著延长代理 IP 的存活时间。

3. 失败重试:指数退避 + 更换 IP

请求失败后不要立刻原样重试。正确姿势是指数退避——第一次等 1 秒、第二次等 2 秒、第三次等 4 秒,并且在重试时顺手换一个代理 IP,避免用同一个 IP 反复撞墙。

三种并发方案怎么选?看这张表:

并发方式 适用场景 资源占用 实现难度
多线程 中小规模、几十个并发 中等
多进程 CPU 密集的解析任务
异步 IO 大规模批量采集

经验值参考:普通网页采集,单 IP 并发控制在 3~5,请求间隔 1~3 秒随机化;配合代理池轮换,整体并发可以随 IP 数量线性扩展。具体数值要根据目标网站的承受能力慢慢试探,宁可慢一点,也不要一上来就全速冲刺。

四、日志记录:让采集过程可追溯

批量采集一旦跑起来就是几小时甚至几天,没有日志,出了问题你只能两眼一抹黑:是代理失效了?被反爬拦截了?还是代码本身有 bug?完善的日志是排查问题的唯一线索

每条请求日志建议至少记录五个字段:时间戳(精确到秒或毫秒)、目标 URL(方便定位失败页面)、所用代理 IP(追踪是哪个 IP 出了问题)、HTTP 状态码(快速判断请求成败)、响应耗时(评估代理速度)。

用 Python 标准库 logging 就够用:

import time
import logging

logging.basicConfig(
    filename="crawler.log",
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)
logger = logging.getLogger("crawler")

def fetch_with_log(session, url, proxy):
    start = time.time()
    try:
        resp = session.get(url, proxies=proxy, timeout=10)
        cost = round(time.time() - start, 2)
        logger.info(f"{url} | 代理:{proxy} | 状态:{resp.status_code} | 耗时:{cost}s")
        return resp
    except Exception as e:
        cost = round(time.time() - start, 2)
        logger.error(f"{url} | 代理:{proxy} | 异常:{type(e).__name__} | 耗时:{cost}s")
        return None

再分享三个进阶技巧:

1. 日志分级。INFO 记录正常请求,WARNING 记录状态码异常(如 403、429),ERROR 记录超时和连接失败。排查问题时先过滤 ERROR 和 WARNING,效率翻倍。

2. 按天切割日志文件。用 TimedRotatingFileHandler 避免单个日志文件无限膨胀:

from logging.handlers import TimedRotatingFileHandler

handler = TimedRotatingFileHandler(
    "crawler.log", when="midnight", backupCount=7
)
logger.addHandler(handler)

3. 定期统计日志。每天跑完后统计成功率、平均耗时、各代理 IP 的失败次数,把表现差的 IP 从代理池里剔除。日志不只是排错工具,更是代理质量优化的数据来源

五、代理选型:为什么推荐光络云

方法讲完了,再聊聊代理资源本身。自建代理池维护成本高、IP 质量参差不齐,对大多数团队来说,直接接入专业的代理服务更划算。

光络云定位为全球网络基础设施及数据服务商,产品覆盖国内和海外,提供动态住宅代理、静态长效代理、隧道网关等多种代理形态,IP 资源量充足、可用率高,配合本文讲的轮换策略和并发控制,可以支撑大规模批量采集稳定运行。在光络云控制台获取代理地址和认证信息后,填入上文代码即可直接使用,接入方式与示例完全兼容。

需要提醒的是:光络云的代理 IP 需要客户自身具备海外网络环境才能使用(TikTok 专线除外),接入前请先确认自己的网络环境符合要求。

常见问题

Q: 设置了代理还是被封,是什么原因?
常见原因有三个:一是并发太高,单 IP 请求频率超出正常范围;二是请求头不完整,比如缺少 User-Agent 或 Referer,一眼就被识别为脚本;三是代理本身质量差,用的是已被大量滥用、早已被目标网站标记的 IP。建议先降低并发、补全请求头,再更换质量更高的代理源。

Q: 并发数设置多少比较合适?
没有标准答案,取决于目标网站的承受能力和代理质量。保守起点:单 IP 并发 3~5,请求间隔 1~3 秒随机。观察日志中的成功率和状态码,如果出现大量 429 或 403,说明太快了,往下调;如果长期稳定,可以逐步往上加。

Q: 使用光络云的代理 IP 有什么前提条件?
光络云的代理 IP 需要客户自身具备海外网络环境才能使用(TikTok 专线除外)。如果你的服务器或本地环境不在海外,请先确认网络条件,或咨询官方了解适合的接入方案。

Q: 日志文件太大,怎么管理?
使用 TimedRotatingFileHandler 按天切割日志,并设置 backupCount 只保留最近若干天的文件;同时关闭 DEBUG 级别日志,只保留 INFO 以上级别,可以减少 80% 以上的日志量。长期运行的项目,建议把日志接入集中式存储,方便按代理 IP、状态码做聚合分析。