news 2026/10/7 17:18:36

卡淘图片批量采集实战:从抓包到Requests下载全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
卡淘图片批量采集实战:从抓包到Requests下载全流程

平时喜欢研究爬虫的朋友,应该不少人都遇到过类似需求:看到某个收藏品平台上的图片挺好,想批量保存下来整理成资料。今天就拿卡淘平台举个例子,把从抓包到采集图片的完整链路走一遍。卡淘是专门做球星卡、收藏卡交易的平台,页面和APP里展示的卡片图清晰度高、信息密度大,很适合用来练习抓包和图片采集。这篇文章会从抓包工具配置讲起,一直写到 Requests 脚本保存图片,中间还会穿插我踩过的几个坑,适合有一定 Python 基础、想搞懂动态请求和图片下载原理的同学。

标题里看起来简单,可真做起来有几个地方会卡人:抓包工具配好了但看不到请求,接口找到了但图片地址拼不出来,图片能访问但代码下载时 403。这些问题我一个个拆开说。

1. 为什么选“抓包+采集图片”这套方案

1.1 抓包才是万能的入口

很多初学者习惯直接在网页上按 F12,去 Elements 里找<img src>,然后拿 requests 去抓 HTML。这个思路在小网站可以,但遇到卡淘这种动态加载的站点很容易翻车。页面上的图片不是一开始就写在 HTML 里的,而是网页加载完以后,JavaScript 再去调接口,拿到 JSON 数据,把图片地址动态渲染出来的。你直接 requests 那个 HTML,得到的只是一堆空壳 div,图片地址一个都看不见。

APP 就更不用说了,你根本没法打开开发者工具去“审查元素”,唯一能看到网络请求的方式就是抓包。抓包工具相当于一个中间人代理,所有请求都会经过它,你在工具里能看到客户端每次请求了哪个 URL、带了什么参数、服务器返回了什么内容。这个能力很关键,因为它让你绕开了“页面长什么样”,直接看到“数据从哪来”。用生活类比的话,网页是成品菜,抓包是进后厨,你能看到厨师放了什么料、开多大火,自然就知道菜是怎么做的。

所以我做图片采集类项目时,第一步永远是抓包,而不是急着写爬虫代码。先把接口理清楚,代码只是重复发送请求而已,难度会降一截。

1.2 卡淘平台的页面和数据特点

卡淘平台定位是球星卡、收藏卡交易,核心内容是卡片图片、价格、卖家信息。这类平台有个普遍特点:图片多、详情字段多,但接口设计相对规整。卡片列表一般是一个 JSON 接口,每一条记录里包含了卡片 ID、标题、价格、缩略图地址、详情图地址。而且图片通常放在 CDN 或对象存储上,地址会有比较明显的域名和路径规则。

另外,卡淘的图片加载是懒加载模式,你滚动页面时才请求后面的图片。这个特点决定了你不能只抓 HTML,因为 HTML 里只有前几屏的图片,后面全是接口二次触发出来的。只有把列表接口整个抓下来,按页码拿到所有数据,才能完整采集。

还要注意一点,卡淘的网页端和 APP 端接口可能不一样。网页端是 AJAX 请求,APP 端可能是 JSON 接口,两者的字段结构也有差异。我建议入门阶段先抓网页端,因为网页端请求头简单,没有 APP 那么多加密参数,适合先跑通流程。

1.3 工具选型:Fiddler、Charles、Requests 怎么配合

抓包工具我常用两个:Windows 上用 Fiddler,Mac 上用 Charles,两者本质都是中间人代理,只是界面风格不同。Fiddler 偏工具型,Charles 偏图形化,但核心功能都一样,都能看到完整的请求和响应,也都能导出 HAR 文件。

工具角色定位:

工具用途
Fiddler / Charles抓包、分析接口、查看响应结构
Fiddler 的 Copy as cURL把接口请求直接复制成 curl 命令,方便转换到 Python
Python Requests根据抓包得到的接口编写批量采集脚本
json 模块 / XPath从 JSON 或 HTML 中提取图片地址

把这些工具串起来就是完整流程:先抓包确认接口,再用 curl 转代码,最后写循环批量下载。这套流程不只适用于卡淘,其他动态网站、APP 甚至小程序,都能用同样的套路。记住:工具只是辅助,核心是你要能看懂接口、找到图片地址的变化规律。

2. 抓包环节:找到图片接口是关键

2.1 配置抓包环境(Fiddler / Charles 手机与 PC)

很多人在抓包第一步就栽了:工具开着,APP 完全没网,或者全是 CONNECT 请求,看不到实际内容。原因通常是 HTTPS 证书没配好。现在绝大多数接口都是 HTTPS,如果你不做中间人解密,抓包工具只能看到域名,看不到路径和参数。

Fiddler 配置流程我过一遍:

  1. 打开 Fiddler,菜单栏找到 Tools > Options > HTTPS,勾选 Decrypt HTTPS traffic。
  2. 如果提示安装证书,直接同意,并选择“受信任的根证书颁发机构”。
  3. 手机和电脑连同一个 WiFi,查看电脑的局域网 IP(命令行 ipconfig)。
  4. 手机 WiFi 设置里打开 HTTP 代理,填写电脑 IP 和端口 8888。
  5. 手机浏览器访问http://电脑IP:8888,在页面里点 FiddlerRoot certificate 下载证书。
  6. 安装证书后,进入手机的系统证书信任设置,把刚刚安装的证书开启完全信任。Android 9 以上和 iOS 都需要这一步,否则 HTTPS 请求依然看不到内容。

这里有个细节:Android 7 之后,很多 APP 默认不信任用户证书,即使安装证书也可能抓不到包。轻量解决方案是用 Charles 配合手机上的“安装到系统证书”操作,或者直接用抓包工具自带的模拟器。如果你的目标就是卡淘网页版,直接在电脑上用浏览器打开卡淘,然后让 Fiddler 作为系统代理也可以,比手机配置简单,适合入门。

Charles 的配置逻辑一样,区别是默认端口为 8888,证书下载地址是http://charlesproxy.com/getssl。手机和电脑在同一个局域网的前提下,设置代理后访问这个地址下载证书即可。

2.2 卡淘接口的分析思路

配置好抓包工具后,先在电脑浏览器里打开卡淘的卡片列表页,随便往下滚动几屏。这时回到 Fiddler 里,你会看到密密麻麻的请求。不要慌,先按“Filter”或者按域名过滤,把图片 CDN 域名排除掉,只看主站接口。

我习惯按这几个步骤筛:

  • 看请求类型:找GET请求,大部分列表数据都是 GET。
  • 看响应类型:找后缀带.json或者Content-Type: application/json的请求。
  • 看请求路径:路径里包含list、search、card、goods这类关键词的优先看。
  • 在 Fiddler 右侧选中请求,点击“JSON”选项卡预览响应,如果能看到imageUrl、imgList这些字段,那就是目标接口。

定位到目标接口后,右键复制Copy as cURL,先保存到文本文件里。这个操作在后续构造 Python 请求时会非常省力,因为 curl 命令里包含了全部请求头、Cookie 和参数,你只需要稍作转换就能变成 requests 代码。

2.3 从响应数据里定位图片真实地址

拿到接口响应后,通常是一长串嵌套 JSON。举个例子,接口返回结构可能是:

{ "code": 0, "data": { "page": 1, "list": [ { "goodsId": "12345", "title": "2023 Panini Prizm Card", "cover": "https://img.katao-example.com/12345.jpg?x-oss-process=image/resize,w_300" } ] } }

这个cover字段就是缩略图地址,注意地址尾部可能带处理参数,比如?x-oss-process=image/resize,w_300。这种参数会导致你拿到的不是原图,图片尺寸被压缩过。想拿原图的话,可以先把问号后面的部分去掉再请求。但有些 CDN 会校验参数,去掉后可能返回超大图,或者干脆 403,这时候需要自己实测一下。

有的接口里图片不是一个地址,而是一个数组,比如imgList,里面包含多张高清图。这时要用循环提取,不要只取cover,否则你会丢掉详情页里的高清图。

图片地址如果只写了路径没写域名,比如/group1/M00/AA/123.jpg,那还需要在前面拼接主域名。具体域名从哪里找?很简单,在响应里搜索http,看看其他字段是不是都指向同一个域名,把那个域名取出来拼上去。

3. 爬虫代码实战:从接口到图片文件

3.1 构造请求与关键参数

抓包搞定接口后,就可以写 Python 代码了。这里我强烈建议先用抓包工具里复制出的 cURL 来验证接口,直接在终端跑一遍 curl,确认返回数据无误后,再转换成 requests 代码。

举个例子,你复制出来的 curl 大概长这样:

curl 'https://api.katao-example.com/card/list?page=1&size=20' \ -H 'User-Agent: Mozilla/5.0 ...' \ -H 'Referer: https://www.katao-example.com/' \ -H 'Cookie: session_id=abc123'

转换成 Python:

import requests headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...", "Referer": "https://www.katao-example.com/", "Cookie": "session_id=abc123" } url = "https://api.katao-example.com/card/list" params = { "page": 1, "size": 20 } resp = requests.get(url, headers=headers, params=params, timeout=10) print(resp.status_code) print(resp.text[:500])

这里有两个重点。第一,headers里的Referer和User-Agent尽量不要省略,很多图片接口和列表接口都会校验这两个字段,少了可能拿不到数据。第二,建议用requests.Session()而不是裸的requests.get(),因为 session 会自动保存 Cookie,后续请求同一个域名的图片时,Cookie 也能带过去,减少 403 概率。

还有一个小细节:如果响应内容有乱码,先别急着改 encoding,看一下resp.apparent_encoding或者响应头里的charset。大多数 JSON 接口是 UTF-8,直接用resp.json()没问题,但如果是网页 HTML 响应,可能是 GBK,就需要按实际编码转换。

3.2 解析 JSON 并提取图片 URL

拿到 JSON 后,解析本身就是一层层地取字段。用resp.json()得到字典,然后按结构取值:

data = resp.json() card_list = data["data"]["list"] for item in card_list: goods_id = item["goodsId"] cover_url = item["cover"] img_list = item.get("imgList", []) or [] # 只处理有效的图片地址 all_imgs = [cover_url] + img_list for img_url in all_imgs: if not img_url.startswith("http"): img_url = "https://img.katao-example.com" + img_url print(goods_id, img_url)

这一步逻辑不复杂,但容易踩字段不存在的坑。很多卡片可能没有imgList,直接item["imgList"]会 KeyError。用.get()加默认值是最稳妥的写法拉。另外,列表里某些商品可能下架了,cover字段是空字符串,也要跳过。

实际项目里我不会只打印,而是写一个生成器函数,专门负责翻页并提取所有图片地址。

def fetch_all_image_urls(max_page=10): session = requests.Session() session.headers.update(headers) seen = set() for page in range(1, max_page + 1): resp = session.get( url, params={"page": page, "size": 20}, timeout=10 ) if resp.status_code != 200: continue data = resp.json() card_list = data.get("data", {}).get("list", []) if not card_list: break for item in card_list: cover = item.get("cover", "") img_list = item.get("imgList", []) or [] for img_url in [cover] + img_list: if img_url and img_url not in seen: seen.add(img_url) yield img_url # 控制请求节奏 time.sleep(0.8)

注意我用了seen集合去重,因为翻页时可能同一张图出现多次(比如热门卡片被推荐到多个页面)。去重能大大减少重复下载,节省时间。

3.3 下载保存与并发优化

图片地址收集好后,进入下载环节。最简单的下载代码长这样:

def download_image(img_url, save_path): headers_for_img = { "User-Agent": headers["User-Agent"], "Referer": "https://www.katao-example.com/" } resp = requests.get(img_url, headers=headers_for_img, timeout=15) if resp.status_code == 200: with open(save_path, "wb") as f: f.write(resp.content) else: print(f"下载失败: {img_url} -> {resp.status_code}")

但直接一把梭下载几千张图片会非常慢,而且容易触发反爬。建议用线程池加一点并发,但不要太大。

import os from concurrent.futures import ThreadPoolExecutor import time save_dir = "katao_images" os.makedirs(save_dir, exist_ok=True) def download_one(img_url): # 用图片地址的哈希做文件名,避免特殊字符问题 file_name = str(hash(img_url)) + ".jpg" save_path = os.path.join(save_dir, file_name) if os.path.exists(save_path): return try: download_image(img_url, save_path) except Exception as e: print(f"异常: {img_url}, {e}") time.sleep(0.3) with ThreadPoolExecutor(max_workers=5) as pool: pool.map(download_one, all_image_urls)

max_workers=5是我实测比较稳的值,既能加速下载,又不会对服务器造成太大压力。如果你想要更完整的文件名,可以用goodsId + 序号来命名。但需要先把业务 ID 传进函数,逻辑上稍微复杂一点,不过能避免 hash 命名导致后续找不到对应卡片的问题。

3.4 反爬应对与频率控制

采集图片这件事,难点不在“下载”,而在“别被封”。卡淘接口虽然不会像大厂一样有复杂风控,但请求频率一旦过高,照样会返回 403 或者验证码。

我常用的几招:

  • 每次请求之间加随机延迟,用time.sleep(random.uniform(0.5, 1.5)),不要固定延时。
  • 同一个 Session 复用,减少握手次数。
  • 控制并发数,5 个线程足够,不要在 ThreadPoolExecutor 里开 50 个。
  • 设置重试机制。比如requests的urllib3 Retry或者简单循环,捕获超时和 5xx 状态码后自动重试 2 到 3 次。

简单重试代码:

def get_with_retry(session, url, headers, retries=3): for i in range(retries): try: resp = session.get(url, headers=headers, timeout=15) if resp.status_code in (200, 302): return resp except requests.exceptions.RequestException: pass time.sleep(1) return None

请求头不用每次换,保持稳定有时候反而比随机换更不容易被识别。很多平台风控看的是你是否像“真人”,固定 IP 固定 UA 固定频率,反而更像一个正常用户。真正容易触发风控的是没有规律的大并发和高频请求。

4. 常见问题与排查技巧实录

4.1 抓不到包的几种典型原因

抓包工具配置半天,结果 APP 或浏览器像没走代理一样,这是最常见的坑。我整理了一个速查表:

现象可能原因解决办法
APP 显示网络异常代理配置错误或端口不对检查电脑 IP 和 Fiddler 端口 8888,手机上重新设置代理
只能看到 CONNECT 请求HTTPS 证书未安装或未信任重新安装证书,iOS 还需要在“证书信任设置”里打开完全信任
请求时有时无手机和电脑不在同一网段确认连接同一个 WiFi,关掉电脑防火墙或者放行 8888 端口
浏览器打开没有代理效果系统代理未开启在 Fiddler 菜单 Tools > WinConfig 里开启 Windows 代理

还有一类情况,卡淘 APP 可能做了“禁止代理”检测,一旦检测到 WiFi 代理就拒绝连接。这种场景下,建议直接用电脑浏览器打开卡淘网页版来抓包,流程简单,而且入门阶段完全够用。

4.2 图片 403 / 防盗链怎么处理

接口能拉到数据,图片地址也能复制到浏览器直接打开,但一到代码下载就 403。这种情况十有八九是防盗链。

防盗链的原理其实很简单:网站检查 HTTPReferer字段,如果不是来自自己的域名,服务器就拒绝返回图片资源。你的浏览器能打开,是因为它会自动带上卡淘的页面地址作为 Referer,而 Python 默认是不带 Referer 的。

处理方式:

img_headers = { "User-Agent": "Mozilla/5.0 ...", "Referer": "https://www.katao-example.com/" }

在下载图片的请求中主动加上Referer,指向图片所在页面的域名,一般就能解决。如果加了 Referer 还是 403,再看一下图片地址是不是 302 跳转到另一个域名,跳转后的域名可能要求不同的 Referer 规则。这就不太好一概而论,需要实际抓包看响应头。

4.3 动态参数 / 签名问题

有时候列表接口里会出现sign、ts、nonce这类参数。这类参数一看就知道是签名校验,目的就是防止有人直接构造请求。遇到这种情况,先不要头铁去逆向 JS,先看是不是真的必须带。

有些平台的签名参数是可选的,你手动把 URL 里的签名删掉,照样能返回数据。有些平台则是必带的,不带签名直接 401。区分方法很简单:构造一个不带签名的请求试试,返回正常就说明校验形同虚设;返回错误就说明需要处理签名。

如果必须带签名,入门阶段最省力的方式是“复用真实请求”。什么意思?就是你在卡淘网页上正常操作,抓包工具会拿到一个带着真实sign的完整 URL,你把这个 URL 存下来直接请求,短期内有缓存时间,可以用来小规模采集。但这种方式的局限很明显:签名会过期,而且你没法随意翻页。真要突破签名,需要去看前端 JS 里怎么生成参数,属于另一个更深的主题,这里不展开。

4.4 容易踩的坑:编码、路径、去重

编码问题不只在网页里有,JSON 接口偶尔也会遇到。如果使用resp.json()抛异常,可以先打印resp.text看看是不是被转义了。一般在响应头里会有charset=utf-8,但有些老接口是gbk,可以采用resp.content.decode("utf-8", errors="ignore")兜底。

路径问题主要在 Windows 上踩。图片地址里如果包含?、/、:,这些字符不能直接作为文件名。所以我在上面代码里用了hash(img_url)作为文件名,就是避免这个坑。你也可以用goodsId作为文件名,但要注意 goodsId 可能是字符串也可能带空格,先做一次strip()。

去重问题的核心是避免重复下载。我建议在生成图片地址阶段就去重,用set()收集所有 URL,而不是下载阶段再判断。下载阶段判断os.path.exists虽然也可以,但多几次磁盘访问,影响效率。更好的做法是在代码里维护一个已经成功下载的 URL 列表,进程重启后还能继续跑。

5. 合规与个人经验(结尾)

5.1 关于数据使用,必须先说清楚

采集图片这件事,自己研究技术没问题,但用的时候要克制。卡淘平台的图片属于平台用户和平台方,版权归属不一定你下载了就属于你。批量抓取别人平台的资源,无论目的是整理资料还是二次发布,都可能违反平台用户协议,甚至涉及版权问题。

我写这篇内容的初衷是拆解“抓包 + 动态接口分析”这套通用技能。你在学习时可以把卡淘当成练习对象,但不要大规模、长时间、高频率地采集,更不要用采集到的图片去做商业用途。真实项目里如果需要卡淘数据,建议先找官方开放接口,或者和平台方沟通合作,这才是正道。

5.2 我的一些实操心得

做了这么多采集项目,图片类采集最值得记住的一句话是:先找接口,再写代码。很多人急着写爬虫,结果被反爬卡得怀疑人生,回头发现只是没找对数据源。抓包工具就是你找数据源的地图,多用几遍就会形成本能反应。

具体到卡淘这类平台,我个人的经验是:先用网页端抓包跑通整个流程,再考虑 APP 端。网页端请求头简单,没有 app 层的加解密,入门效率高。跑通后再去抓 APP 端会容易很多,因为你已经知道要关注哪些字段、哪个接口是核心。

另外,抓包得到的 HAR 文件建议保存下来。不要只存在 Fiddler 里,可以右键导出为 HAR 文件。以后想重新写解析逻辑,直接用 HAR 文件里的记录就能还原接口,比重新抓包方便得多。我自己遇到接口字段变动时,第一反应就是翻旧 HAR 对比差异。

最后分享一个小技巧:批量采集前一定要先用 1 页数据跑通全流程。比如先请求第 1 页,只下载 5 张图试试水,确认文件名、路径、下载成功率都符合预期,再去循环所有页面。我就是吃过“下载到一半才发现图片全是缩略图”的亏,当时 5000 多张图白下了,白白浪费将近一个小时。这个小步骤只要花两分钟,能省下后面一大半调试时间,值得养成习惯。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 17:18:15

Playwright安装失败排查指南:从impeccable误输到浏览器启动全链路解析

1. 项目概述&#xff1a;一个被误读的“完美”工具名&#xff0c;背后藏着开发者日常最痛的 CLI 体验断点 最近在多个技术社区和内部协作群中&#xff0c;频繁看到 impeccable 这个词被当作命令、工具名甚至包名反复提及——有人在问“impeccable 如何使用”&#xff0c;有人…

作者头像 李华
网站建设 2026/10/7 17:18:07

GTA4低配优化指南:FusionFix与DXVK提升帧数画质

1. 为什么十几年后还有人折腾GTA4的画质与性能如果你在2024年还愿意打开GTA4&#xff0c;大概率不是因为它的画面有多惊艳&#xff0c;而是因为那座自由城承载了太多记忆。但问题也很现实&#xff1a;这游戏是2008年的产物&#xff0c;PC版移植质量放在当年都算灾难级&#xff…

作者头像 李华
网站建设 2026/10/7 17:17:58

marketingskills实战:用Claude Code和AI agents打通SEO与CRO工作流

1. 从“marketingskills”说起&#xff1a;一个被低估的增长工具箱第一次看到“marketingskills”这个词&#xff0c;是在一个做独立站的朋友群里。有人甩了个链接&#xff0c;说“这套东西把SEO和CRO的活儿全串起来了”。点进去一看&#xff0c;不是什么新工具&#xff0c;而是…

作者头像 李华
网站建设 2026/10/7 17:17:31

智慧电厂建设指南:从数据采集到AI应用的工业互联网平台架构解析

简介&#xff1a;华为智慧电厂解决方案完整文档&#xff0c;面向电力行业信息化规划人员、电厂技术骨干及关注能源数字化转型的从业者。方案聚焦智能发电与产业融合&#xff0c;阐述利用大数据、云计算、物联网、AI等技术实现生产过程自主优化与设备智能运维&#xff0c;提升电…

作者头像 李华
网站建设 2026/10/7 17:17:30

三菱伺服扭矩控制实战:从原理到FX3U/STM32精准调参

1. 为什么扭矩控制是伺服系统里最“硬核”的基本功在工厂产线调试现场&#xff0c;我见过太多工程师对着伺服驱动器面板反复按F1-F8&#xff0c;屏幕闪来闪去却始终调不出稳定输出——不是速度忽快忽慢&#xff0c;就是负载一加重就报警停机。后来发现&#xff0c;问题根源往往…

作者头像 李华
网站建设 2026/10/7 17:17:27

Caveman调试实战:用最朴素的日志输出破解线上Bug排障难题

先说个可能有点冒犯的观点&#xff1a;我在线上环境排查诡异Bug的时候&#xff0c;第一反应永远是先把调试器和各种监控面板放到一边&#xff0c;老老实实加三行打印日志。这个习惯被不少同事吐槽过&#xff0c;他们说这是“Caveman Debugging”&#xff0c;穴居人调试法&#…

作者头像 李华