Python实战:用TaoToken统一通道解析快手个人主页无水印视频下载

发布时间:2026/10/5 17:25:46
Python实战:用TaoToken统一通道解析快手个人主页无水印视频下载 1. 快手个人主页视频抓取的真实痛点与场景拆解很多人第一次写快手个人主页视频下载脚本卡住的地方往往不是 Python 语法而是三件事接口找不准、翻页游标接不上、请求凭证散落各处。我试过把 Cookie、userId、pcursor 全写死在代码里结果换一个博主就要改一次文件跑批量任务时更是到处复制粘贴维护成本极高。这篇内容聚焦一个具体场景给定一个快手博主个人主页链接用 Python 把该主页下的视频批量解析出无水印地址并保存到本地同时把调用凭证统一交给 TaoToken 的 API 通道管理。适合已经会写基础 requests 请求、想跑通「主页链接 → 视频列表 → 无水印文件」完整链路的同学。核心检索词先明确快手个人主页视频无水印下载本质是调用快手 Web 端的 GraphQL 接口visionProfilePhotoList从返回的feeds数组里取出photo.photoUrl字段这个字段就是无水印视频直链。整个链路分四步定位接口、构造请求体、翻页拿游标、下载落盘。为什么要把凭证管理单独拎出来因为快手接口依赖登录态 Cookie而 Cookie 会过期。如果你同时还在用其他模型或 API 服务凭证一多就容易乱。TaoToken 提供统一 Key 和 API 通道把这类调用凭证集中管理脚本里只读环境变量不硬编码敏感串换机器、换账号都省事。下面按「问题场景 → 凭证前置 → 可复制配置 → 验证请求 → 报错排查 → 收尾」的顺序展开每一步都给能直接跑的代码和参数说明。你跟着做单页视频批量下载在本地稳定跑通没问题。先看接口定位。打开目标博主主页按 F12 进 Network筛选graphql下拉页面触发加载你会看到一个 POST 请求发往https://www.kuaishou.com/graphql。点开 Payload里面是 JSON 结构关键字段有四个operationName固定为visionProfilePhotoListquery是一大段 GraphQL 查询语句固定variables.page固定为profilevariables.userId是博主唯一 IDvariables.pcursor是翻页游标。userId 最好拿主页 URL 里/profile/后面那串就是比如3xteif7iwrqr7iy。pcursor 是重点第一页传空字符串接口返回的data.visionProfilePhotoList.pcursor就是下一页要用的游标。换句话说翻页是「上一页的响应喂给下一页的请求」串行依赖不能并行。请求头里必须带content-type: application/json因为这是 POST JSON不是表单。Cookie 必须是你自己登录后的完整 Cookie否则接口返回空数据或直接 401。User-Agent 建议用桌面 Chrome 的移动端 UA 有时会触发不同返回结构。把这些理清楚代码就好写了。下一节先讲 TaoToken 侧要准备什么再进入可复制配置。2. TaoToken 统一通道前置准备与凭证管理在写快手抓取脚本之前先把凭证管理这件事做干净。快手接口靠 Cookie而如果你后续还要接模型对话、代码补全或其他 API凭证会越来越多。TaoToken 的作用是把这些调用凭证收拢到一个统一通道里脚本通过环境变量读取不把敏感信息写进代码仓库。你需要准备两样东西一个 TaoToken 的 API Key以及对应的接入地址。API 基址是https://taotoken.net/api注意这个地址不带任何查询参数直接作为请求前缀使用。Key 的获取入口在控制台的 API Keys 页面登录后新建一个即可。拿到 Key 之后不要直接写进.py文件。推荐做法是写进系统环境变量或者放在项目根目录的.env文件里用python-dotenv加载。这样做的直接好处是代码可以提交到 Git凭证不会泄露换机器时只改环境变量不动代码。具体操作在项目根目录建一个.env文件内容如下。TAOTOKEN_API_KEYsk-你的实际key TAOTOKEN_BASE_URLhttps://taotoken.net/api KUAISHOU_COOKIE你的快手登录Cookie KUAISHOU_USER_ID3xteif7iwrqr7iy然后在 Python 里这样读取。import os from dotenv import load_dotenv load_dotenv() TAOTOKEN_API_KEY os.getenv(TAOTOKEN_API_KEY) TAOTOKEN_BASE_URL os.getenv(TAOTOKEN_BASE_URL) KUAISHOU_COOKIE os.getenv(KUAISHOU_COOKIE) KUAISHOU_USER_ID os.getenv(KUAISHOU_USER_ID) assert TAOTOKEN_API_KEY, 缺少 TAOTOKEN_API_KEY请检查 .env assert KUAISHOU_COOKIE, 缺少 KUAISHOU_COOKIE请检查 .env这里有个细节快手 Cookie 里包含kuaishou.server.web_st这种长串直接放.env时不要加引号否则读出来会带引号导致请求头异常。如果 Cookie 里有换行先合并成一行再放。TaoToken 的 Key 在这里的角色是「统一凭证入口」。你可以在同一个.env里管理多个服务的 Key脚本按需读取。比如后面要调模型对话验证通道是否通就用同一个TAOTOKEN_API_KEY去请求https://taotoken.net/api下的对话接口。这样一套凭证管所有不用每个服务单独记一套。如果你打算长期跑批量任务建议再准备一个 Coding Plan把编码类调用也纳入统一管理。入口在 Coding Plan 页面适合需要持续调用、跑 Agent 任务的场景。快手抓取本身不消耗模型额度但如果你在脚本里加了自动生成文件名、自动打标签这类模型调用就可以走同一个 Key。凭证准备好后先做一次连通性验证确认 Key 和基址没问题。用下面这段最小请求测试。import requests resp requests.get( f{TAOTOKEN_BASE_URL}/models, headers{Authorization: fBearer {TAOTOKEN_API_KEY}}, timeout10, ) print(resp.status_code) print(resp.text[:300])如果返回 200 且能看到模型列表说明通道正常。如果返回 401检查 Key 是否复制完整、有没有多余空格。这一步过了再进入快手接口的配置。需要提醒的是快手抓取和 TaoToken 通道是两条独立的链路前者用 Cookie 访问快手后者用 Key 访问 TaoToken。把两者放同一个.env只是为了集中管理不要混淆用途。下一节给出完整的可复制配置。3. 可复制配置请求头、GraphQL 请求体与下载脚本这一节是全文的核心给出能直接跑的完整配置。先看请求头配置再给 GraphQL 请求体的 JSON 结构最后是下载脚本。所有敏感值都从环境变量读路径和字段名与上一节保持一致。请求头部分关键是content-type和Cookie。content-type必须是application/json因为快手这个接口收的是 POST JSON。Cookie从环境变量读不要硬编码。import os import json import time import requests from dotenv import load_dotenv load_dotenv() KUAISHOU_COOKIE os.getenv(KUAISHOU_COOKIE) KUAISHOU_USER_ID os.getenv(KUAISHOU_USER_ID) HEADERS { User-Agent: ( Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 ), accept: */*, accept-language: zh-CN,zh;q0.9, content-type: application/json, Cookie: KUAISHOU_COOKIE, }GraphQL 请求体里operationName和query是固定值variables里的page固定为profileuserId从环境变量读pcursor由翻页逻辑传入。把query单独抽成常量避免每次拼字符串出错。GRAPHQL_QUERY fragment photoContent on PhotoEntity { id duration caption originCaption likeCount viewCount commentCount realLikeCount coverUrl photoUrl photoH265Url manifest manifestH265 videoResource coverUrls { url __typename } timestamp expTag animatedCoverUrl distance videoRatio liked stereoType profileUserTopPhoto musicBlocked __typename } fragment feedContent on Feed { type author { id name headerUrl following headerUrls { url __typename } __typename } photo { ...photoContent __typename } canAddComment llsid status currentPcursor tags { type name __typename } __typename } query visionProfilePhotoList($pcursor: String, $userId: String, $page: String, $webPageArea: String) { visionProfilePhotoList(pcursor: $pcursor, userId: $userId, page: $page, webPageArea: $webPageArea) { result llsid webPageArea feeds { ...feedContent __typename } hostName pcursor __typename } } def build_payload(user_id: str, pcursor: str) - dict: return { operationName: visionProfilePhotoList, variables: { page: profile, pcursor: pcursor, userId: user_id, }, query: GRAPHQL_QUERY, }注意pcursor第一页传空字符串不要传None否则 JSON 序列化后变成null接口可能不认。翻页时把上一页返回的pcursor原样传入。下载脚本部分核心逻辑是请求接口 → 解析feeds→ 取photo.photoUrl→ 下载保存 → 记录下一页游标。加time.sleep控制频率避免请求过密。import os SAVE_DIR os.path.join(os.getcwd(), kuaishou_videos) os.makedirs(SAVE_DIR, exist_okTrue) def fetch_page(user_id: str, pcursor: str) - dict: url https://www.kuaishou.com/graphql payload build_payload(user_id, pcursor) resp requests.post(url, headersHEADERS, jsonpayload, timeout15) resp.raise_for_status() return resp.json() def download_video(video_url: str, filepath: str) - bool: try: r requests.get(video_url, headersHEADERS, timeout30, streamTrue) r.raise_for_status() with open(filepath, wb) as f: for chunk in r.iter_content(chunk_size8192): if chunk: f.write(chunk) return True except Exception as e: print(f下载失败 {video_url} - {e}) return False def crawl_profile(user_id: str, max_pages: int 5): pcursor for page in range(max_pages): print(f当前第 {page 1} 页pcursor{pcursor!r}) data fetch_page(user_id, pcursor) node data.get(data, {}).get(visionProfilePhotoList) if not node: print(接口返回为空可能 Cookie 失效或 userId 错误) break feeds node.get(feeds) or [] if not feeds: print(本页无视频结束) break for idx, feed in enumerate(feeds, start1): photo feed.get(photo) or {} video_url photo.get(photoUrl) if not video_url: continue filename fpage{page 1}_{idx}.mp4 filepath os.path.join(SAVE_DIR, filename) ok download_video(video_url, filepath) print(f{filename} {保存完成 if ok else 保存失败}) pcursor node.get(pcursor) or if not pcursor: print(没有下一页游标结束) break time.sleep(2) if __name__ __main__: crawl_profile(KUAISHOU_USER_ID, max_pages5)这段代码里SAVE_DIR用os.getcwd()拼出来避免写死 Windows 路径导致换系统跑不了。文件名用page{页码}_{序号}.mp4方便对照。streamTrue配合分块写入大文件下载不会一次性占满内存。如果你想把凭证管理再规范一点可以把HEADERS里的Cookie换成从 TaoToken 通道拉取的动态值。不过快手 Cookie 和 TaoToken Key 是两套体系这里保持从.env读即可。TaoToken 的 Key 主要用于你脚本里其他模型调用比如自动生成视频标题。配置给完了下一节验证请求是否真的跑通。4. 验证请求与成功结果从响应到落盘配置写好后先别急着跑全量。分三步验证先验证接口能返回数据再验证photoUrl能取到最后验证文件能落盘。每一步都有明确的成功标志。第一步单独调fetch_page打印返回结构。用下面这段最小验证代码。if __name__ __main__: data fetch_page(KUAISHOU_USER_ID, ) node data.get(data, {}).get(visionProfilePhotoList) print(result:, node.get(result) if node else None) print(pcursor:, node.get(pcursor) if node else None) print(feeds 数量:, len(node.get(feeds) or []) if node else 0)成功的话你会看到result为1表示成功pcursor是一串数字字符串feeds 数量大于 0。如果result不是 1或者feeds为空先查 Cookie 和 userId。第二步从feeds里取第一条打印photoUrl。if __name__ __main__: data fetch_page(KUAISHOU_USER_ID, ) feeds data[data][visionProfilePhotoList][feeds] first feeds[0][photo] print(caption:, first.get(caption)) print(photoUrl:, first.get(photoUrl))photoUrl应该是一个以https://开头的直链通常带txmov2.a.kwimgs.com之类的域名。这个链接就是无水印地址。你可以把它复制到浏览器直接打开能播放就说明解析正确。第三步跑完整下载检查本地文件夹。运行crawl_profile后kuaishou_videos目录下会出现page1_1.mp4、page1_2.mp4等文件。用播放器打开确认画面无水印、音画同步。实测下来单页通常返回 20 条左右的视频翻页间隔 2 秒比较稳。如果一次跑 5 页大概 100 个视频耗时取决于网速和文件大小。下载过程中如果某个链接失败脚本会打印失败信息并继续不会中断整批任务。这里有个验证技巧把photoUrl和页面上的视频对比。快手网页端播放的视频有时带水印但photoUrl字段返回的是原始无水印版本。如果你拿到的链接播放出来还有水印检查是不是取错了字段比如误取了coverUrl或manifest里的地址。成功跑通后你可以把max_pages调大或者把userId换成其他博主。凭证都在.env里换博主只改KUAISHOU_USER_ID一行。如果你在脚本里加了 TaoToken 的模型调用比如用模型给视频自动生成描述验证方式类似先单独调一次模型接口确认返回正常再嵌入主流程。TaoToken 的模型对话入口在模型对话页面可以先用网页版试一条确认 Key 有效。验证通过后下一节讲常见报错怎么排查。5. 本篇常见错误排查401、local proxy failed、reading choices、OAuth跑快手抓取脚本时报错集中在几类。下面按真实报错信息逐条对照给出原因和修法。第一类401 Unauthorized或接口返回result: 2。这通常是 Cookie 失效。快手登录态有有效期过期后接口不再返回数据。修法是重新登录快手网页版F12 复制最新 Cookie更新.env里的KUAISHOU_COOKIE。注意复制时包含kuaishou.server.web_st和kuaishou.server.web_ph这两个关键字段缺一个都可能失败。第二类local proxy failed或连接超时。这类报错通常和网络环境有关。先确认你的网络能正常访问快手网页版浏览器能打开主页脚本才可能通。如果浏览器能开但脚本超时检查requests是否走了系统代理可以在请求里加proxies{http: None, https: None}显式禁用或者检查环境变量HTTP_PROXY。另外timeout设太短也会误报建议 15 秒以上。第三类reading choices或KeyError: choices。这个报错一般出现在你调模型接口时响应结构里没有choices字段。原因可能是请求体格式不对或者模型 ID 写错。如果你用 TaoToken 通道调模型先确认请求体里model字段是有效值再确认messages是数组格式。用下面这段最小请求排查。import requests, os from dotenv import load_dotenv load_dotenv() resp requests.post( f{os.getenv(TAOTOKEN_BASE_URL)}/chat/completions, headers{ Authorization: fBearer {os.getenv(TAOTOKEN_API_KEY)}, Content-Type: application/json, }, json{ model: gpt-4o-mini, messages: [{role: user, content: ping}], }, timeout20, ) print(resp.status_code) print(resp.text[:500])如果返回 200 且能看到choices说明通道正常。如果返回 401检查 Key。如果返回 404检查model字段。第四类OAuth相关报错比如invalid_grant或token expired。这类一般出现在你用 OAuth 方式接入某些服务时。修法是重新走授权流程拿新的 token。如果你用的是 TaoToken 的 Key 方式不涉及 OAuth遇到这类报错先确认是不是请求发到了错误的地址。第五类json.decoder.JSONDecodeError。快手接口返回的不是 JSON通常是 HTML 错误页。原因可能是 Cookie 失效被重定向到登录页或者请求头content-type写成了application/x-www-form-urlencoded。检查HEADERS里content-type是否为application/json以及requests.post用的是jsonpayload而不是datapayload。第六类下载的视频文件大小为 0 或几 KB。这通常是photoUrl取到了但下载被拒。检查下载请求是否带了Cookie和User-Agent有些 CDN 会校验 Referer。可以在下载请求头里加Referer: https://www.kuaishou.com/。排查顺序建议先看 HTTP 状态码再看响应体前 300 字符最后看本地文件。大部分问题集中在 Cookie 和请求头两处。把这两处固定好脚本稳定性会高很多。如果你在脚本里同时用了 TaoToken 通道和快手接口报错时先区分是哪条链路。快手报错看 CookieTaoToken 报错看 Key 和基址。两条链路分开验证定位更快。6. 凭证统一管理与后续扩展脚本跑通后最后收一下凭证管理这条线。快手抓取依赖 Cookie模型调用依赖 TaoToken Key两者都放在.env里通过环境变量读取。这样做的好处是代码干净、可迁移、不泄露敏感信息。如果你后续要扩展功能比如批量抓多个博主、自动去重、自动上传凭证管理会更重要。建议把.env按服务分组快手相关的前缀KUAISHOU_TaoToken 相关的前缀TAOTOKEN_避免命名冲突。需要长期跑编码类任务或 Agent 的话可以了解 Coding Plan把持续调用的额度统一管理。入口在 Coding Plan 页面。如果只是偶尔验证模型是否可用用模型对话页面手动试一条更直接。API Key 的创建和管理在 API Keys 页面接入细节看接入文档。快手这边的扩展方向把userId列表化循环调用crawl_profile把已下载的视频 ID 记录到本地 JSON避免重复下载把pcursor持久化支持断点续爬。这些都不难核心链路已经跑通了。最后提醒一句抓取频率别太高翻页间隔保持 2 秒以上下载也适当限速。稳定跑通比一次抓完更重要。凭证放.env代码里只读环境变量这套习惯养成了后面接什么服务都省心。