导出的评论明明只有几百条,脚本却数出了更多。先别急着判断文件有问题,看看自己是不是用splitlines()数的。
评论正文里可以换行。一条评论写了三行,按文本行数统计就会算成三条。逗号也一样:正文里写了个英文逗号,直接split(',')就会把同一格拆开。
下面这段 Python 用标准库csv读文件,顺便检查一级评论、回复和重复记录。不用装 pandas,也不需要把文件传到别的网站。
我是抖评岛的开发者,文中拿我们公开的样例演示。三条评论都是编写的测试数据,不是真实用户评论。
先拿一个知道答案的文件跑
导出教程里的 CSV 样例可以直接下载,不用登录。它有 18 列、3 条记录,其中两条是一级评论,一条是回复。
保存成exportdou-comments-sample.csv,再把下面的代码保存为check_comments.py:
importcsvimportsysfromcollectionsimportCounteriflen(sys.argv)!=2:raiseSystemExit('用法:python3 check_comments.py comments.csv')required={'视频ID','评论ID','根评论ID','父评论ID','层级','评论内容'}withopen(sys.argv[1],encoding='utf-8-sig',newline='')assource:reader=csv.DictReader(source)headers=reader.fieldnamesor[]missing=required-set(headers)ifmissing:raiseSystemExit('缺少必要列:'+'、'.join(sorted(missing)))rows=list(reader)ifany(Noneinroworany(valueisNoneforvalueinrow.values())forrowinrows):raiseSystemExit('存在字段数不一致的记录,请检查 CSV 格式')ifany(notrow['视频ID'].strip()ornotrow['评论ID'].strip()forrowinrows):raiseSystemExit('存在空的视频ID或评论ID')levels=Counter(row['层级'].strip()forrowinrows)ifset(levels)-{'1','2'}:raiseSystemExit('发现非 1/2 的层级值,请先核对文件定义')# 只核对单个导出任务;任务内匿名标识不适合跨任务去重。keys=[(row['视频ID'],row['评论ID'])forrowinrows]root_keys={(row['视频ID'],row['评论ID'])forrowinrowsifrow['层级'].strip()=='1'}unmatched=sum((row['视频ID'],row['根评论ID'])notinroot_keysforrowinrowsifrow['层级'].strip()=='2')print(f'列数:{len(headers)}')print(f'记录数:{len(rows)}')print(f'一级评论:{levels["1"]}')print(f'回复记录:{levels["2"]}')print(f'重复标识记录:{len(keys)-len(set(keys))}')print(f'未在本文件匹配到根评论的回复:{unmatched}')在这两个文件所在的目录运行:
python3 check_comments.py exportdou-comments-sample.csv样例的输出是:
列数:18 记录数:3 一级评论:2 回复记录:1 重复标识记录:0 未在本文件匹配到根评论的回复:0读文件时的两个参数别删。utf-8-sig能处理 UTF-8 文件开头的 BOM;newline=''让 CSV 解析器处理换行。DictReader会把表头当作列名,数据从下一条记录开始读。Python 的 csv 文档里有对应说明。
“回复数”那一列不能加进来
样例里,第一条评论的“回复数”是 2,但文件只放了一条回复记录。这个文件仍然是三条记录,不能算成五条。
要知道拿到了多少条回复,就数“层级”为 2 的记录。“回复数”是评论的互动数据,和文件实际包含的回复条数是两回事。
脚本还会看回复的“根评论ID”能不能在当前文件里找到。出现未匹配记录时,先检查是不是筛选后另存了一份文件,或者合并时漏了数据。这个数字能提醒你检查,不能单凭它断定采集失败。
去重时,也别只比较评论正文
两个人都写了“多少钱”,这可以是两条不同评论。按正文去重,会把其中一条删掉。
上面的代码用视频 ID 和评论 ID 检查重复,只适合核对同一个导出任务。抖评岛的评论标识和昵称会做任务内匿名化,换一个任务就不能据此判断是不是同一条评论、同一个人。重复采集同一视频时,先保留每个文件的来源,不要把它们拼起来就算新样本。
最后再提醒一个数量上的区别:设置“最多 500 条,包含回复”,是一级评论与回复合计最多 500 条。文件数出了 473 条,只能说明拿到的文件里有 473 条记录,不能说明视频页总共就有这么多评论,也不能说访问过 473 位观众。
换成自己的文件前,先核对列名和层级定义。这个脚本会把记录读入内存,适合单个任务的文件核对;它检查的是文件内部,不会去抖音补抓缺失评论。