ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

(必收藏) Python私藏项目实操分享:用TaoToken统一Key通道爬取QQ音乐评论,带你解析别人的内心世界

(必收藏) Python私藏项目实操分享:用TaoToken统一Key通道爬取QQ音乐评论,带你解析别人的内心世界 1. 从零拆解 QQ 音乐评论接口Python 爬取 QQ 音乐评论到底难在哪很多人第一次听到「Python 爬取 QQ 音乐评论」这个需求脑子里浮现的画面是打开网页、右键查看源代码、复制评论。真动手才发现评论根本不在 HTML 里翻页还越翻越乱。我当初也是这么被坑进来的后来才搞明白QQ 音乐评论走的是 Ajax 异步接口页面只是个壳数据全靠一个fcg_global_comment_h5.fcg接口吐出来。先说清楚这个项目能做什么、适合谁。它能帮你把某首歌下面的评论、昵称、点赞数、时间抓下来存进 MySQL再做词频和情感倾向统计最后你会得到一张「大家在评论区到底在聊什么」的画像。适合已经会一点 Python 基础语法、想练手真实接口爬虫的人也适合做数据分析、想拿真实中文语料练 NLP 的同学。它不适合完全零基础、连requests都没装过的人因为中间涉及签名参数、分页游标、编码转换这些坑。核心难点有三个。第一是请求参数里的动态字段。接口不是给个page1就完事它有一个lasthotcommentid值是上一页最后一条评论的 ID你必须把上一页的尾巴喂给下一页否则拿到的永远是同一批数据。第二是返回格式是 JSONP外面裹了一层jsoncallback4823183319594757(...)直接json.loads会报错得先切片。第三是编码接口outCharset写的是GB2312但实际返回里混着 UTF-8 内容处理不好就是一堆乱码。我试过直接按页数硬翻结果发现「最后一页」是假的——热评里明明有 7 月 12 号的评论翻到所谓最后一页时间却停在 7 月 16 号中间的数据像被吞了。后来才明白得从后往前翻翻到真正的数据页再往后走才能把尾巴补齐。这个细节后面排障章节会细讲。除了爬取本身还有一个现实问题这类项目往往不止调一个接口。你可能还想接一个大模型做评论情感分析、关键词抽取或者把抓到的文本丢给模型做摘要。这时候如果每个服务都单独管一套 Key、单独配额度维护起来非常痛苦。所以这篇会把「统一 Key 通道」这件事一起讲清楚让爬虫和模型调用走同一套凭证管理省得你到处贴 Key。下面按「环境准备 → 接口参数 → 分页抓取 → 入库 → 词频统计 → 排障」的顺序走每一步都给可复制的代码和参数你跟着敲就能跑通。2. TaoToken 统一 Key 通道前置准备把爬虫和模型调用收进一个入口在正式写爬虫之前先把「Key 管理」这件事解决掉。原因很实际你这个项目大概率不会只爬评论就结束。抓完评论你很可能想接一个大模型做情感分类或者做关键词提取。如果爬虫用一套配置、模型调用又用另一套配置代码里到处是硬编码的 Key换一次环境就要改十几个地方。TaoToken 在这里扮演的角色是一个统一的 API 调用入口。你可以把它理解成一个「总闸」爬虫里如果需要调用模型能力模型对话、编码辅助、配额查看都从这一个入口走Key 只维护一份。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 注意 API 地址后面不加 UTM 参数直接用它做 Base URL 就行。具体要准备三样东西我把它叫做「三件套」缺一不可配置项作用取值来源Base URL所有请求的根地址https://taotoken.net/apiAPI Key身份凭证替代硬编码控制台 API Keys 页面生成Model ID指定调用哪个模型模型列表里选比如编码类、对话类生成 Key 的入口在控制台的 API Keys 页面地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。进去之后新建一个 Key复制出来存到环境变量里别直接写进代码。我习惯用.env文件加python-dotenv这样本地跑和服务器跑都不用改代码。如果你后面想用 Claude Code 这类编码工具来辅助写爬虫脚本它的接入配置也是同一套三件套文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。Claude Code 的接入方式是把 Base URL、Key、Model ID 填进它的配置文件具体路径和字段后面配置章节会给完整片段。这里要强调一点TaoToken 是统一调用入口不是让你拿它替代数据库或爬虫框架。爬虫该用requests还是requests入库该用pymysql还是pymysql它只负责把「调用外部模型能力」这件事的凭证和配额管起来。配额查看在控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 跑批量任务前先看一眼余量避免跑到一半断掉。环境准备清单pip install requests pymysql python-dotenv jiebajieba是后面做中文词频用的先装上。MySQL 本地装一个建库建表脚本下一节给。Python 版本 3.8 以上都行我用 3.10 实测没问题。.env文件长这样TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_API_KEY你的Key粘贴在这里 TAOTOKEN_MODEL_ID你的模型ID MYSQL_HOST127.0.0.1 MYSQL_USERroot MYSQL_PASSWORD你的密码 MYSQL_PORT3306 MYSQL_DBQQ_Music这样爬虫脚本和模型调用脚本都从环境变量读换机器只改.env。踩过的坑是有人把 Key 直接 commit 到 Git结果被扫到滥用。用.env加.gitignore是最低成本的防护。3. 可复制配置请求头、分页参数与 settings 片段这一节是全文最核心的可复制部分。先把请求头和参数配置写死成常量再讲分页逻辑。QQ 音乐评论接口的完整地址是https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg请求头只需要一个 User-Agent 就够别加太多花里胡哨的字段反而容易触发风控HEADERS { user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 }参数里真正会变的是三个pagenum、lasthotcommentid、jsoncallback。pagenum是页数从 0 开始lasthotcommentid是上一页最后一条评论的 IDjsoncallback实测不影响结果固定一个值就行。其余参数照抄PARAMS { g_tk: 5381, jsonpCallback: jsoncallback4823183319594757, loginUin: 0, hostUin: 0, format: jsonp, inCharset: utf8, outCharset: GB2312, notice: 0, platform: yqq, needNewCode: 0, cid: 205360772, reqtype: 2, biztype: 1, topid: 213910991, cmd: 8, needmusiccrit: 0, pagenum: 0, pagesize: 25, lasthotcommentid: , callback: jsoncallback4823183319594757, domain: qq.com, ct: 24, cv: 101010, }其中topid是歌曲 IDcid是评论分类 ID换歌的时候改topid即可。pagesize是每页条数25 是默认值别贪心调太大容易被限。建库建表脚本直接复制执行import pymysql db pymysql.connect(host127.0.0.1, userroot, password你的密码, port3306) cursor db.cursor() cursor.execute(CREATE DATABASE IF NOT EXISTS QQ_Music DEFAULT CHARACTER SET utf8mb4) db.close() db pymysql.connect(host127.0.0.1, userroot, password你的密码, port3306, dbQQ_Music) cursor db.cursor() sql CREATE TABLE IF NOT EXISTS comments ( nike VARCHAR(255) NOT NULL, comment VARCHAR(255) NOT NULL, praisenum INT NOT NULL, comment_id VARCHAR(255) NOT NULL, time VARCHAR(255) NOT NULL, PRIMARY KEY (comment_id) ) cursor.execute(sql) db.close()注意主键我改成了comment_id原方案用comment当主键一旦有两条相同内容的评论就会插入失败。用评论 ID 更稳。如果你要用 Claude Code 辅助写这个脚本它的配置文件片段如下路径按你本地实际调整{ baseUrl: https://taotoken.net/api, apiKey: 你的Key, model: 你的ModelID }Cline 的 MCP 配置同理三件套填全{ mcpServers: { taotoken: { baseUrl: https://taotoken.net/api, apiKey: 你的Key, model: 你的ModelID } } }Codex 的auth.json也是同一套逻辑Base URL、Key、Model ID 三个字段填对就行。这里不展开每个工具的完整路径核心是记住任何工具接入都是 Base URL Key Model ID 三件套缺一个就连不上。4. 分页抓取与验证从请求签名到评论入库的完整链路分页逻辑是整篇文章最容易翻车的地方。核心思路维护一个LAST_COMMENT_ID变量每抓完一页把这一页最后一条评论的 ID 更新进去下一页请求带上它。先写请求函数带重试import re import json import time import requests def get_html(url, headers, paramsNone, tries3): try: response requests.get(urlurl, headersheaders, paramsparams, timeout10) response.raise_for_status() response.encoding utf-8 return response except requests.HTTPError: print(connect failed) if tries 0: print(reconnect...) time.sleep(2) return get_html(url, headers, params, tries - 1) print(3 times failure) return None解析函数要注意 JSONP 切片。返回内容形如jsoncallback4823183319594757({...})前面有 29 个字符后面有 3 个字符);加换行所以切片是html[29:-3]def parse_html(html): content json.loads(html[29:-3]) items content[comment][commentlist] result [] for item in items: result.append({ nike: item.get(nick, ), comment: item.get(rootcommentcontent, ), praisenum: item.get(praisenum, 0), comment_id: item.get(commentid, ), time: item.get(time, ), }) return result主循环边抓边入库import pymysql URL https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg LAST_COMMENT_ID db pymysql.connect(host127.0.0.1, userroot, password你的密码, port3306, dbQQ_Music, charsetutf8mb4) cursor db.cursor() for page in range(0, 20): PARAMS[pagenum] str(page) PARAMS[lasthotcommentid] LAST_COMMENT_ID resp get_html(URL, HEADERS, PARAMS) if resp is None: break rows parse_html(resp.text) if not rows: print(no more data, stop at page, page) break for row in rows: sql (INSERT IGNORE INTO comments (nike, comment, praisenum, comment_id, time) VALUES (%s, %s, %s, %s, %s)) cursor.execute(sql, (row[nike], row[comment], row[praisenum], row[comment_id], row[time])) db.commit() LAST_COMMENT_ID rows[-1][comment_id] print(fpage {page} done, last_id{LAST_COMMENT_ID}) time.sleep(1) db.close()运行验证先跑 3 页看控制台输出的last_id是否每页都在变。如果不变说明lasthotcommentid没生效检查是不是把PARAMS里的键名写错了。入库后查一下SELECT COUNT(*) FROM comments; SELECT nike, comment, time FROM comments LIMIT 5;正常结果应该是条数在增长时间字段有值。如果comment字段是乱码检查连接是否带了charsetutf8mb4。词频统计用jiebaimport jieba from collections import Counter db pymysql.connect(host127.0.0.1, userroot, password你的密码, port3306, dbQQ_Music, charsetutf8mb4) cursor db.cursor() cursor.execute(SELECT comment FROM comments) texts [row[0] for row in cursor.fetchall()] db.close() words [] for t in texts: words.extend(jieba.lcut(t)) stop set(的 了 是 我 你 他 在 就 都 也 和 与.split()) counter Counter(w for w in words if w not in stop and len(w) 1) for word, cnt in counter.most_common(20): print(word, cnt)跑完你会看到高频词比如「青春」「回忆」「好听」这类这就是「解析别人内心世界」的入口。5. 常见报错排查401、local proxy failed、reading choices 逐个击破这一节按真实报错来。你跑上面代码时大概率会遇到下面几个。报错一json.decoder.JSONDecodeError: Expecting value: line 1 column 1原因几乎都是 JSONP 切片位置不对。不同时间接口返回的前缀长度可能变。稳妥做法是用正则提取括号里的内容import re m re.search(r\((\{.*\})\), html, re.S) content json.loads(m.group(1))报错二pymysql.err.IntegrityError: Duplicate entry主键冲突。如果你沿用原方案用comment当主键相同评论会撞。改成comment_id主键或者插入时用INSERT IGNORE。报错三requests.exceptions.ProxyError: local proxy failed这个报错通常是你本地环境变量里配了代理但代理不可用。检查HTTP_PROXY、HTTPS_PROXY环境变量临时清掉unset HTTP_PROXY unset HTTPS_PROXY代码里也可以显式禁用代理session requests.Session() session.trust_env False resp session.get(URL, headersHEADERS, paramsPARAMS)报错四调用模型接口时401 Unauthorized这是 Key 的问题。检查三件套是否齐全Base URL 是不是https://taotoken.net/apiKey 有没有多余空格Model ID 是否填对。401 基本都是凭证没带上或带错。可以在控制台 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 重新生成一个 Key 对比测试。报错五reading choices相关报错这类报错一般出现在模型返回结构解析时说明你按错误的字段路径取数据。先打印完整响应体确认字段名再改取值路径。别猜字段名。报错六翻页拿到重复数据回到开头那个坑直接点「最后一页」拿不到真实数据得从后往前翻。解决办法是记录已入库的comment_id集合插入前判断是否已存在重复就跳过。同时把pagenum递增和lasthotcommentid更新绑定在一起两者必须同步变。排障顺序建议先确认单页请求能返回数据 → 再确认切片解析正确 → 再确认入库无冲突 → 最后才开分页循环。别一上来就跑 20 页出错都不知道哪一步挂的。6. 把爬虫和模型调用接进统一通道下一步怎么走评论抓下来只是原料真正有意思的是拿它做分析。你可以把抓到的评论文本批量丢给模型做情感分类或者做主题聚类。这时候统一 Key 通道的价值就体现出来了爬虫脚本和模型调用脚本共用一套.env不用在多个平台之间来回切换凭证。模型对话入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 你可以先在里面试几条评论看模型对中文情感判断的效果再决定要不要批量跑。如果只是偶尔分析用对话页手动试就行如果要长期跑批量任务建议走 Coding Plan配额和调用更稳定地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 里面有完整的请求示例和字段说明。API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 跑批量前先去控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_campaignrewrite 看一眼配额余量。最后给一个实用技巧把爬虫的LAST_COMMENT_ID持久化到数据库或文件里中断后能从上次的位置继续不用从头再爬。这个改动很小但能省你很多重复劳动。
返回列表