百度图片爬虫:爬取海量图片数据,搭建图像识别训练集

引言

训练一个图像识别模型,最耗时的工作往往不是调参,而是"凑数据"。做猫狗分类需要几千张标注清晰的图片,做商品识别需要覆盖不同角度、光照和背景的样本,做缺陷检测甚至需要专业人员逐张标注。手动一张张下载、筛选、整理,效率极低,而且很难保证类内多样性和类间平衡。

百度图片搜索是获取这类数据最直接的入口------覆盖广、关键词灵活、返回结果中同时包含缩略图和原图地址。但把"能搜到的图"变成"能用来训练的图",中间隔着一整套工程问题:接口的分页参数怎么构造、请求被限流怎么办、下载下来的图片里有多少是重复的、模糊的、甚至是无关的?本文将从接口解析出发,完整走一遍采集 → 反爬对抗 → 高并发下载 → 训练集去重与清洗的链路,并集成站大爷隧道代理IP来应对高频采集下的IP限制。

免责声明:本文仅限技术学习与交流。爬取的图片应遵守目标网站的robots.txt协议及相关版权规定,仅用于个人学习和研究,不得用于商业用途或侵犯他人权益。

一、接口解析:acjson的分页逻辑

百度图片搜索的网页端数据并非直接嵌在HTML中,而是通过一个异步JSON接口返回。核心端点如下:

复制代码
https://image.baidu.com/search/acjson

关键参数中,word和queryWord是搜索关键词,pn是分页偏移量 ,rn是每页返回数量(通常为30)。第二页的pn=30,第三页pn=60,以此类推。此外,gsm参数是pn的十六进制表示,部分请求中会用到;tn和ipn用于标识请求来源与会话连续性。一个可直接使用的参数模板如下:

复制代码
params = {
    "tn": "resultjson_com",
    "ipn": "rj",
    "word": keyword,
    "queryWord": keyword,
    "pn": pn,
    "rn": 30,
    "gsm": format(pn, "x"),   # pn的十六进制
    "ie": "utf-8",
}

接口返回的JSON中,data是一个列表,每个元素代表一张图片。图片的真实地址优先取thumbURL ,如果为空则回退到middleURL。需要注意的是,thumbURL通常是压缩后的缩略图,分辨率对于训练集来说可能偏低;如果需要更高清的版本,可以尝试从返回结果中提取hoverURL或replaceUrl中的原图链接,但这部分字段的可用性不如thumbURL稳定。

二、反爬对抗:请求头、频率与IP三层防线

百度图片搜索的反爬是多维度叠加的,不是单一措施能解决的。

第一层:请求头完整性校验。 请求必须携带合法的User-Agent、Referer,部分场景还会检查X-Requested-With。缺少这些字段的请求会被直接拒绝或返回空数据。一个可用的基础请求头如下:

复制代码
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    "Referer": "https://image.baidu.com/",
    "X-Requested-With": "XMLHttpRequest",
}

第二层:频率限制与行为检测。 短时间内的密集请求会触发验证码或直接封禁IP,部分情况下返回503状态码。请求间隔完全固定也会被行为模型识别,因此需要在请求之间加入随机延迟 ,而不是固定的sleep(1)。

第三层:IP层面的限制。 这是训练集采集最核心的瓶颈。一个训练集动辄需要数万张图片,按每页30张计算,仅接口请求就需要数千次;再加上每张图片的下载请求,单IP在完成采集之前几乎必然触发限流。此时需要在IP层面做轮换,这正是站大爷隧道代理IP发挥作用的地方:每次请求自动从不同出口IP发出,将单IP的请求密度摊薄到安全范围内,同时避免因某个IP被标记而导致整批采集中断。站大爷隧道代理支持HTTP/HTTPS/SOCKS全协议,覆盖全国99%地域,连接成功率在长时间压力测试中稳定在99%以上,适合训练集采集这种需要持续稳定运行的任务。

三、高并发下载:线程池与流式写入

训练集采集的图片数量通常在数千到数万张量级,同步逐张下载效率过低。使用ThreadPoolExecutor并发下载是性价比最高的方案:线程数控制在5-10之间,既能显著提速,又不至于因瞬时压力过大而触发风控。

复制代码
import requests, os, random, time
from concurrent.futures import ThreadPoolExecutor, as_completed

PROXIES = {
    "http": "http://用户名:密码@tps.zdaye.com:8080",
    "https": "http://用户名:密码@tps.zdaye.com:8080",
}

def download_one(idx, url, save_dir):
    try:
        resp = requests.get(
            url,
            headers={"User-Agent": HEADERS["User-Agent"],
                     "Referer": "https://image.baidu.com/"},
            proxies=PROXIES,
            timeout=15,
            stream=True,
        )
        if resp.status_code == 200:
            ext = os.path.splitext(url.split("?")[0])[1] or ".jpg"
            if len(ext) > 5:
                ext = ".jpg"
            path = os.path.join(save_dir, f"{idx:05d}{ext}")
            with open(path, "wb") as f:
                for chunk in resp.iter_content(8192):
                    f.write(chunk)
            return path
    except Exception:
        pass
    return None

def download_parallel(urls, save_dir, workers=8):
    os.makedirs(save_dir, exist_ok=True)
    results = []
    with ThreadPoolExecutor(max_workers=workers) as executor:
        futures = {
            executor.submit(download_one, i, u, save_dir): i
            for i, u in enumerate(urls)
        }
        for future in as_completed(futures):
            r = future.result()
            if r:
                results.append(r)
    return results

使用stream=True配合iter_content分块写入,避免将整张图片加载进内存;线程池的as_completed模式可以在任意一张下载完成后立即处理,而不是等待所有任务结束。

四、训练集构建:去重、清洗与组织

把图片下载到本地只是第一步。原始采集结果中通常混有大量近似重复的图片------同一张图的不同尺寸、不同压缩质量、甚至只是加了水印的变体。如果不去重直接拿去训练,模型会在这些冗余样本上过拟合,评估指标也会失真。

4.1 感知哈希去重

pHash(感知哈希) 是目前图像训练集去重最常用的方法。它通过离散余弦变换(DCT)为每张图片生成一个64位哈希指纹,然后比较两张图片哈希值的汉明距离来判断相似程度:距离为0表示几乎完全相同,距离小于5通常视为高度相似,距离大于10则可以认为是不同图片。

使用imagededup库可以快速完成批量去重:

复制代码
from imagededup.methods import PHash

phasher = PHash()
encodings = phasher.encode_images(image_dir="raw_images")
duplicates = phasher.find_duplicates(
    encoding_map=encodings,
    max_distance_threshold=5,
)

duplicates是一个字典,键为每张图片的文件名,值为与之近重复的其他文件列表。根据这个结果删除冗余样本即可。imagededup同时支持pHash、dHash、wHash、aHash以及基于CNN的近重复检测,对于训练集场景,pHash在速度和准确率之间是较好的平衡点。

4.2 清洗与筛选

去重之后还需要做几项基础清洗:

  • 尺寸过滤:低于某个分辨率阈值的图片(如宽或高小于100像素)通常信息量不足,应剔除。

  • 格式统一:训练框架通常期望统一的RGB格式,可以批量转换为JPEG并去除透明通道。

  • 模糊检测:使用拉普拉斯算子方差判断图片清晰度,方差过低说明图片模糊,不适合作为训练样本。

  • 标签目录组织 :按关键词分目录存放,目录名即类别标签,例如dataset/cat/、dataset/dog/。这样可以直接配合ImageFolder等数据加载器使用。

五、站大爷隧道代理的集成与调优

5.1 为什么训练集采集特别依赖代理?

训练集采集的请求量与普通爬虫完全不是一个量级。假设目标是一个包含10个类别的训练集,每个类别采集2000张,总计20000张图片。按每页30张计算,接口请求约667次;加上20000次图片下载请求,总请求数超过20000次。没有任何单个IP能够在不触发限流的情况下完成这个量级的请求。

站大爷隧道代理的每请求自动切换IP能力,将这两万多次请求分散到大量不同的出口IP上,使每个IP的请求量保持在极低水平。同时,代理层自带IP质量检测,自动淘汰低效节点,避免因个别IP失效导致下载任务反复失败。

5.2 集成方式

在requests中集成站大爷隧道代理有两种方式。直接使用URL内嵌认证:

复制代码
PROXIES = {
    "http": "http://用户名:密码@tps.zdaye.com:8080",
    "https": "http://用户名:密码@tps.zdaye.com:8080",
}

如果服务商要求通过请求头认证,则使用Proxy-Authorization:

复制代码
import base64
auth = base64.b64encode(b"用户名:密码").decode()
headers = {
    "Proxy-Authorization": f"Basic {auth}",
    **HEADERS,
}
# 代理地址只填 host:port,不携带认证信息
PROXY_URL = "http://tps.zdaye.com:8080"

对于需要控制轮换节奏的场景,可以在用户名后拼接period参数(如用户名-period-300),表示每300秒更换一次出口IP,而不是每个请求都换。

六、常见问题与避坑指南

接口返回空data或直接报错。 首先检查请求头是否完整,尤其是Referer和X-Requested-With。其次降低请求频率,加入1-2秒的随机延迟。如果仍然为空,可能是当前IP段被标记,切换隧道代理的出口地域后重试。

下载的图片质量偏低。 thumbURL是缩略图字段,分辨率有限。如果训练任务对清晰度要求较高,可以尝试提取replaceUrl中的原图链接,但需要对该字段为空的情况做回退处理。更稳妥的做法是在采集阶段同时保存thumbURL和hoverURL,后期按需选用。

去重阈值怎么定? pHash汉明距离阈值设为5是一个较保守的选择,会保留视觉上略有差异的图片,适合需要多样性的训练集。如果目标是剔除所有"看起来差不多"的图,可以适当降低到3甚至2,但可能丢失一些真实的不同样本。

采集规模与合规边界。 训练集采集应控制在个人学习研究所必需的范围内。百度图片搜索的结果版权归属复杂,采集的图片不得用于商业模型训练或对外分发。合理控制采集量、遵守robots.txt、不绕过登录和付费内容,是这类项目能够持续进行的前提。

七、总结

从百度图片构建图像识别训练集,核心链路可以概括为四个环节:

环节 关键做法
接口采集 acjson接口,pn控制分页偏移,rn=30,解析thumbURL
反爬对抗 完整请求头 + 随机延迟 + 站大爷隧道代理轮换IP
高并发下载 ThreadPoolExecutor(5-10线程)+ stream=True流式写入
训练集构建 pHash去重(汉明距离阈值5)+ 尺寸/清晰度清洗 + 按类别归档

百度图片能解决"数据从哪来"的问题,但决定训练集质量的,是去重和清洗环节。一个经过pHash去重、尺寸过滤和清晰度筛选的5000张数据集,往往比未经处理的20000张原始采集更有训练价值。配合站大爷隧道代理的稳定IP轮换,可以把采集链路从"跑一半被封"变成可持续运行的工程流程,让数据准备不再是模型训练的前置瓶颈。

相关推荐
SEO_juper2 小时前
AI 爬虫 robots.txt 检查工具:你的站是不是把 AI 挡在门外了
开发语言·人工智能·爬虫·python·外贸独立站
Data-Miner2 小时前
DeepSeek 对百度搜索的冲击有多大?当搜索被 AI 重写,数据分析行业正在被悄悄改写
人工智能·百度·数据分析
OnlineProxy3 小时前
Python 高负载异步爬虫优化指南:深挖 httpx 与 aiohttp 的性能极限
爬虫·python·httpx
SEO_juper20 小时前
hreflang 审计工具:外贸多语言站谷歌SEO的隐性杀手
开发语言·人工智能·爬虫·python·seo
深蓝电商API1 天前
Firecrawl、ScrapeGraphAI:AI爬虫框架横评
人工智能·爬虫·firecrawl·scrapegraphai
空堂与归1 天前
百度开源 LoopVL:1B 循环视觉模型省 260 倍数据
人工智能·百度·ai·开源
小花皮猪1 天前
从 Prompt 到结构化 JSON:如何利用 Bright Data 快速搭建 YouTube 监测工作流?
人工智能·爬虫·agent·数据采集
云老大-阿里云国际站代理商1 天前
网站遇到恶意爬虫和CC攻击,阿里云国际站WAF与Bot管理怎么搭配
爬虫·阿里云·云计算
重生之高冷汉堡包1 天前
Perplexity爬虫怎么做?2026常见方案对比、实操教程与问题排查
大数据·网络·爬虫·安全·ai