抖音评论数据整理工具:本地评论清洗、统计与导出教程

简介: 本文用一个纯本地的 Python 小工具,演示如何把已经导出保存的评论数据做一次完整整理:读取 JSON、清洗表情与链接、统计点赞与回复分布、抽取高频词,并导出可直接用表格软件打开的 CSV 明细和一份文字摘要。全程不涉及网络请求,适合做内容复盘、选题分析和运营周报。

源码地址:http://pan15.com/s/2eppp3pzhdd?password=qcwj#41695_760001685159_23f951d5_lite_protocol.json%E8%AE%BF%E9%97%AE%E7%A0%81%EF%BC%9Aqcwj
访问码:qcwj

本文用一个纯本地的 Python 小脚本,把已经保存到本地的评论数据做一次完整整理:读取 JSON、清洗文本、统计点赞与回复、抽取高频词,最后导出 CSV 明细和一份文字摘要。脚本不发起任何网络请求,只处理磁盘上已有的数据文件,适合做内容复盘、选题分析和运营周报。

一、先说数据来源

评论数据的获取环节请走正规渠道:平台开放接口、创作者后台的导出功能,或者人工整理。拿到数据之后落成本地文件,再交给下面的脚本处理,这样职责是分开的:采集归采集,处理归处理。脚本里没有登录、签名、翻页请求之类的逻辑,这也是使用任何第三方工具时值得留意的一点。

二、输入文件的字段约定

脚本默认读取同目录下的 comments.json,支持两种结构:

  1. 顶层直接是数组;
  2. 顶层是对象,评论列表放在 comments 字段里。

每条评论会用到这些字段:cid、text、nickname、like_count、reply_count、create_time、video_id。缺失字段会自动补默认值,如果你的导出文件字段名不一样,改 load_comments 里的取值即可,不需要动其他部分。

三、完整代码

# -*- coding: utf-8 -*-
"""
抖音评论数据整理工具(本地数据处理示例)

用途:
    读取已经保存到本地的评论数据 comments.json,做清洗与统计,
    导出可直接用表格软件打开的 CSV 明细,以及一份文字版摘要。

说明:
    本示例只读取本地文件,不包含网络请求、登录、签名、翻页等采集逻辑。
    数据来源请使用平台开放接口或官方导出功能,并遵守相应服务条款。
"""

import csv
import json
import os
import re
from collections import Counter

INPUT_FILE = "comments.json"
CSV_OUTPUT = "comments_clean.csv"
SUMMARY_OUTPUT = "summary.txt"
TOP_N = 10

# ---------- 步骤 0:准备示例输入,保证脚本可以直接运行 ----------
DEMO_COMMENTS = [
    {
   
        "cid": "1001",
        "text": "这个教程讲得真清楚,收藏了![赞]",
        "nickname": "阿强",
        "like_count": 128,
        "reply_count": 3,
        "create_time": "2024-05-01 10:20:31",
        "video_id": "7300000000000000001",
    },
    {
   
        "cid": "1002",
        "text": "请问背景音乐叫什么名字?https://example.com/a",
        "nickname": "小满",
        "like_count": 76,
        "reply_count": 12,
        "create_time": "2024-05-01 11:02:05",
        "video_id": "7300000000000000001",
    },
    {
   
        "cid": "1003",
        "text": "已经跟着做了一遍,效果不错[比心]",
        "nickname": "老李",
        "like_count": 54,
        "reply_count": 1,
        "create_time": "2024-05-01 12:41:17",
        "video_id": "7300000000000000001",
    },
    {
   
        "cid": "1004",
        "text": "第三步那里有点卡住了,能不能再讲细一点",
        "nickname": "Nina",
        "like_count": 31,
        "reply_count": 5,
        "create_time": "2024-05-02 09:15:44",
        "video_id": "7300000000000000002",
    },
    {
   
        "cid": "1005",
        "text": "@老李 我也卡在第三步,后来把参数调小就好了",
        "nickname": "阿强",
        "like_count": 22,
        "reply_count": 2,
        "create_time": "2024-05-02 09:30:10",
        "video_id": "7300000000000000002",
    },
    {
   
        "cid": "1006",
        "text": "哈哈哈哈这个演示太真实了",
        "nickname": "小满",
        "like_count": 18,
        "reply_count": 0,
        "create_time": "2024-05-02 10:05:59",
        "video_id": "7300000000000000002",
    },
]


def ensure_input_file():
    """没有输入文件时写一份示例数据,方便第一次运行。"""
    if os.path.exists(INPUT_FILE):
        return False
    with open(INPUT_FILE, "w", encoding="utf-8") as f:
        json.dump(DEMO_COMMENTS, f, ensure_ascii=False, indent=2)
    return True


# ---------- 步骤 1:读取并规范化字段 ----------
def load_comments(path):
    with open(path, "r", encoding="utf-8") as f:
        data = json.load(f)

    # 兼容两种结构:顶层数组,或 {"comments": [...]}
    if isinstance(data, dict):
        data = data.get("comments", [])

    records = []
    for item in data:
        records.append({
   
            "cid": str(item.get("cid", "")),
            "text": str(item.get("text", "")),
            "nickname": str(item.get("nickname", "")),
            "like_count": int(item.get("like_count", 0) or 0),
            "reply_count": int(item.get("reply_count", 0) or 0),
            "create_time": str(item.get("create_time", "")),
            "video_id": str(item.get("video_id", "")),
        })
    return records


# ---------- 步骤 2:文本清洗 ----------
URL_RE = re.compile(r"https?://\S+|www\.\S+")
AT_RE = re.compile(r"@[^\s@]+")
BRACKET_RE = re.compile(r"\[[^\[\]]{1,8}\]")
EMOJI_RE = re.compile(
    "[\U0001F300-\U0001FAFF\U00002600-\U000027BF\U0001F1E6-\U0001F1FF]"
)
SPACE_RE = re.compile(r"\s+")


def clean_text(text):
    """去掉链接、@、表情占位符和多余空白,保留正文。"""
    text = URL_RE.sub(" ", text)
    text = AT_RE.sub(" ", text)
    text = BRACKET_RE.sub(" ", text)
    text = EMOJI_RE.sub(" ", text)
    text = SPACE_RE.sub(" ", text)
    return text.strip()


# ---------- 步骤 3:分词(有 jieba 就用,没有就退化处理) ----------
try:
    import jieba

    def tokenize(text):
        return [w.strip() for w in jieba.lcut(text) if len(w.strip()) > 1]

except ImportError:
    def tokenize(text):
        """没有 jieba 时用双字滑窗 + 英文单词,做粗粒度词频统计。"""
        tokens = []
        for seg in re.findall(r"[\u4e00-\u9fa5]+", text):
            if len(seg) < 2:
                continue
            tokens.extend(seg[i:i + 2] for i in range(len(seg) - 1))
        tokens.extend(re.findall(r"[A-Za-z]{2,}", text))
        return tokens


STOPWORDS = {
   
    "这个", "那个", "什么", "怎么", "可以", "就是", "真的", "感觉",
    "我们", "你们", "他们", "自己", "一下", "一个", "还是", "已经",
    "哈哈", "哈哈哈", "the", "and",
}


def keyword_counter(records, top_n=TOP_N):
    counter = Counter()
    for r in records:
        text = r.get("clean_text") or r["text"]
        for word in tokenize(text):
            if word in STOPWORDS:
                continue
            counter[word] += 1
    return counter.most_common(top_n)


# ---------- 步骤 4:汇总统计 ----------
def summarize(records):
    total = len(records)
    total_like = sum(r["like_count"] for r in records)
    total_reply = sum(r["reply_count"] for r in records)
    avg_like = round(total_like / total, 2) if total else 0
    hot = sorted(records, key=lambda r: r["like_count"], reverse=True)[:TOP_N]

    lines = [
        "评论总数: %d" % total,
        "点赞总数: %d" % total_like,
        "回复总数: %d" % total_reply,
        "平均点赞: %s" % avg_like,
        "",
        "高频词 Top %d:" % TOP_N,
    ]
    lines += ["  %s x%d" % (w, c) for w, c in keyword_counter(records)]
    lines += ["", "点赞最高评论 Top %d:" % TOP_N]
    for r in hot:
        lines.append("  [%d赞] %s: %s" % (r["like_count"], r["nickname"], r["text"]))
    return "\n".join(lines)


# ---------- 步骤 5:导出 CSV ----------
def export_csv(records, path):
    fields = [
        "cid", "nickname", "text", "clean_text",
        "like_count", "reply_count", "create_time", "video_id",
    ]
    with open(path, "w", encoding="utf-8-sig", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        for r in records:
            row = dict(r)
            row["clean_text"] = clean_text(r["text"])
            writer.writerow({
   k: row.get(k, "") for k in fields})


def main():
    if ensure_input_file():
        print("未找到 %s,已生成示例数据。" % INPUT_FILE)

    records = load_comments(INPUT_FILE)
    print("读取评论 %d 条" % len(records))

    # 先统一算好清洗结果,后面的统计和导出都复用
    for r in records:
        r["clean_text"] = clean_text(r["text"])

    export_csv(records, CSV_OUTPUT)
    print("已导出明细: %s" % CSV_OUTPUT)

    report = summarize(records)
    with open(SUMMARY_OUTPUT, "w", encoding="utf-8") as f:
        f.write(report + "\n")

    print("已导出统计: %s" % SUMMARY_OUTPUT)
    print("-" * 40)
    print(report)


if __name__ == "__main__":
    main()

四、运行与输出

把文件保存为 douyin_comment_cleaner.py,然后执行:

python douyin_comment_cleaner.py

脚本会依次做四件事:

  1. 检查 comments.json 是否存在,不存在就写一份示例数据,保证第一次运行就有结果;
  2. 读取并规范化每条评论的字段;
  3. 清洗文本后导出 comments_clean.csv,编码用 utf-8-sig,Excel 直接双击打开不会乱码;
  4. 生成 summary.txt,包含评论总数、点赞总数、回复总数、平均点赞、高频词 Top 10,以及点赞最高的若干条评论。

控制台也会把这份摘要打印一遍,方便快速看一眼结果。

五、几个常见的改法

换输入输出路径。 改文件顶部的 INPUT_FILE、CSV_OUTPUT、SUMMARY_OUTPUT 三个常量即可,比如改成按日期命名的文件,方便多次运行保留历史。

改 Top 数量。 调整 TOP_N,高频词和热门评论的条数会一起变。

过滤噪声词。 中文没有天然的空格分词,STOPWORDS 里先把「这个」「就是」这类高频虚词挡掉,剩下的词才有参考价值。跑完一轮看到新的噪声词,直接往里加就行。

只看某段时间。 在 load_comments 之后加一个过滤,比如保留 create_time >= "2024-05-01" and create_time < "2024-05-08" 的记录。因为时间是 YYYY-MM-DD HH:MM:SS 这种定长字符串,直接比较大小就是按时间排序。

让词频更准。 执行 pip install jieba。脚本检测到 jieba 会自动切换成真实分词;没装的时候用双字滑窗兜底,结果会偏碎,但做粗筛够用。

按视频分组。 用 itertools.groupby 或一个字典按 video_id 聚合,就能比较同一账号下不同视频的评论热度差异。

六、还能继续做什么

清洗后的 clean_text 可以直接接情感分析,算出正负评价的比例;也可以按昵称统计活跃评论者,看看谁是铁粉;如果评论里带有 @ 关系,还能拉出一张简单的互动网络。数据量再大一些时,把列表换成 pandas 或者写进 SQLite 查询会省事很多。

最后提醒一句:评论数据会涉及个人信息,内部复盘用就够了,不要对外二次分发,也不要拿去训练会公开发布的模型。

相关文章
|
2天前
|
云安全 人工智能 运维
当攻击全面Agent化,你的安全防御能否跟上AI Speed?
多起客户侧AK泄露事件应急的真实观察
1199 1
|
25天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
9587 32
|
11天前
|
存储 人工智能 并行计算
大模型本地部署终端选型方法论:以 Qwen3.8-27B 为例的四档分层完整流程
本文提出一套大模型本地部署终端选型方法论:定约束、定档位、定框架、定参数四步决策法,配合入门、主力、质量、无损四档分层模型。以 Qwen3.8-27B 实测数据为例,逐环节解读显存、带宽、存储、散热、系统、预算等要素,给出面向不同预算的优选方案、决策自查清单与市场观察框架。文末前瞻 AI 笔记本的 CPU+GPU 与统一内存两条路线,论证四步决策法在新品类上的延续性。
|
10天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型深度拆解:原理解读、实战测评与保姆级落地教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为**System One Model(系统一模型)**,对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
787 1
|
6天前
|
人工智能 JSON 自然语言处理
2026 年 Jev 决策模型全解析:核心原理拆解,性能实战测评与落地部署教程
有一款特殊AI模型在开发者圈子刷屏,它摒弃传统大模型擅长的对话聊天能力,专注做高速结构化决策,它就是TypeSafe AI推出的Jev模型。该模型由ChatGPT共同发明人Diogo Almeida主导研发,定位为System One Model(系统一模型),对标人类大脑快速直觉判断的思维模式,在响应延迟、调用成本、结构化输出稳定性上相比传统生成式大模型有着巨大差异。本文会完整拆解Jev底层原理、三大核心原语能力、适用业务场景,同时提供可直接运行的curl、Python代码示例,并且结合多组实测数据,客观分析模型优势与能力边界,帮助普通开发者和AI应用从业者快速上手落地。
522 0
|
23天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
2605 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
7天前
|
存储 人工智能 自然语言处理
千问办公官网入口链接在哪?2026年最新QwenWork测评、千问办公怎么样?一文看懂
千问办公(QwenWork)是阿里云推出的AI智能办公平台,提供网页端和阿里云官网双入口。支持PPT/Word/Excel生成、多模态处理、网页全栈搭建、钉钉深度集成等6大核心能力。个人版免费可用,高级版198元/月;企业版198元/人/月。新用户注册即赠2000积分。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务
1013 0
|
17天前
|
Windows
【保姆级】.NET Framework 3.5离线安装教程(2026最新实测)
.NET Framework 3.5是微软经典运行库,专为兼容老软件、老游戏设计。Win7自带,Win10/11需手动启用(在线或离线安装)。它与4.x系列并存不冲突,缺它会导致“找不到组件”报错。本文详解两种安装方式及常见问题解决,小白也能轻松上手。(239字)
2205 0

热门文章

最新文章