前两天刷抖音,突然想看看自己一年到底刷了多少条视频——但抖音不给你导出数据啊,正好最近在学Go,那就自己动手写个工具呗,这篇文章就是记录我怎么用Go语言,把一年365天的抖音观看记录(假设你能导出JSON)变成有用的分析报告,别指望一步到位,咱们边写边想,就像你真的在电脑前折腾一样。
为什么选Go而不是Python?
说实话,Python处理这种小数据量更顺手,但Go有几个点特别吸引我:
- 编译成单个可执行文件——拷到任何机器都能跑,不装环境
- 并发处理——如果数据量大(比如几十万条记录),Go的goroutine能快好几倍
- 标准库强大——
encoding/json、net/http、sort这些,写分析工具够用了
我的数据长这样(抖音的“我的收藏”导出,或者你自己抓的接口数据):
[
{
"id": "738291018394",: "如何用Go写并发爬虫",
"author": "码农翻身",
"category": "编程",
"duration": 185,
"watchTime": "2024-03-15T21:34:00",
"liked": true,
"commentCount": 328
}
]
第一步:定义数据结构
写代码第一件事不是写逻辑,是定义数据结构,这决定了后面所有代码怎么走。
type DouyinVideo struct {
ID string `json:"id"` string `json:"title"`
Author string `json:"author"`
Category string `json:"category"`
Duration int `json:"duration"` // 秒
WatchTime time.Time `json:"watchTime"`
Liked bool `json:"liked"`
CommentCount int `json:"commentCount"`
}
这里有个小坑:抖音返回的时间是"2024-03-15T21:34:00",Go的time.Time能直接解析,但字段标签必须写对。
第二步:读取和解析数据
假设你有douyin_2024.json这个文件(没有?那就自己写个假数据测试)。
func loadData(filename string) ([]DouyinVideo, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
var videos []DouyinVideo
err = json.Unmarshal(data, &videos)
if err != nil {
return nil, err
}
return videos, nil
}
这段代码看起来简单,但实际跑起来你会发现几个问题,比如空数据——文件是而不是null,Go会报错,解决办法是先检查长度。
第三步:核心分析——按天统计观看时长
最想知道的肯定是:我一年哪天刷得最多?

func analyzeByDay(videos []DouyinVideo) map[string]time.Duration {
daily := make(map[string]time.Duration)
for _, v := range videos {
day := v.WatchTime.Format("2006-01-02") // 只取日期部分
daily[day] += time.Duration(v.Duration) * time.Second
}
return daily
}
这个"2006-01-02"是Go的独特日期格式,不是随便写的——它恰好是Go语言诞生的时间(2006年1月2日),刚学的时候老记不住,现在肌肉记忆了。
然后排序输出前10天:
type dayStat struct {
Day string
Hours float64
}
func topDays(daily map[string]time.Duration, n int) []dayStat {
stats := make([]dayStat, 0, len(daily))
for day, d := range daily {
stats = append(stats, dayStat{Day: day, Hours: d.Hours()})
}
sort.Slice(stats, func(i, j int) bool {
return stats[i].Hours > stats[j].Hours
})
if len(stats) > n {
stats = stats[:n]
}
return stats
}
等等,这里有个逻辑漏洞——daily里每天的时长类型是time.Duration,但排序后转成float64的小时数,精度会丢一点,不过对于分析来说够了。
第四步:分类统计——你最沉迷哪个领域?
func categoryAnalysis(videos []DouyinVideo) map[string]int {
cat := make(map[string]int)
for _, v := range videos {
if v.Category != "" {
cat[v.Category]++
}
}
return cat
}
这个简单,但统计“观看时长”比“视频数量”更合理——因为有些视频30秒,有些30分钟,改一下:
func categoryAnalysis(videos []DouyinVideo) map[string]time.Duration {
cat := make(map[string]time.Duration)
for _, v := range videos {
cat[v.Category] += time.Duration(v.Duration) * time.Second
}
return cat
}
第五步:生成可视化报告
光有数据不行,得让结果好看,我用柱状图字符画——不用装第三方库,纯控制台输出。
func printBarChart(title string, data map[string]float64, maxWidth int) {
fmt.Printf("\n=== %s ===\n", title)
// 找出最大值用于归一化
var maxVal float64
for _, v := range data {
if v > maxVal {
maxVal = v
}
}
if maxVal == 0 {
return
}
// 按值排序,从大到小
keys := make([]string, 0, len(data))
for k := range data {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return data[keys[i]] > data[keys[j]]
})
for _, k := range keys {
barLen := int(data[k] / maxVal * float64(maxWidth))
fmt.Printf("%-15s |%s %.1f\n", k, strings.Repeat("█", barLen), data[k])
}
}
输出长这样:
=== 观看时长TOP类别 ===
编程 |█████████████████████████ 78.5
美食 |██████████████ 32.1
健身 |████████ 18.7
搞笑 |█████ 11.3
第六步:并发优化——当你有一年数据时
如果数据量像标题说的“365天”,每天可能200+条,总共7万+条,单线程解析没问题,但如果做复杂统计(比如按小时分布),并发更快。
func analyzeConcurrent(videos []DouyinVideo) {
var wg sync.WaitGroup
hourCount := make([]int, 24)
var mu sync.Mutex
for _, v := range videos {
wg.Add(1)
go func(v DouyinVideo) {
defer wg.Done()
hour := v.WatchTime.Hour()
mu.Lock()
hourCount[hour]++
mu.Unlock()
}(v)
}
wg.Wait()
// hourCount[22] 就是晚上10点刷的视频数
}
但这里有个隐患——goroutine启动太多(7万个),调度开销反而大,更好的做法是用worker pool(固定N个goroutine处理channel里的任务)。
func analyzeWorkerPool(videos []DouyinVideo, workers int) []int {
tasks := make(chan DouyinVideo)
results := make(chan int, 24)
var wg sync.WaitGroup
hourCount := make([]int, 24)
// 启动workers
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for v := range tasks {
results <- v.WatchTime.Hour()
}
}()
}
// 发送任务
go func() {
for _, v := range videos {
tasks <- v
}
close(tasks)
}()
// 收集结果
go func() {
wg.Wait()
close(results)
}()
for hour := range results {
hourCount[hour]++
}
return hourCount
}
别急着复制——这个代码有竞态条件,results channel的接收没加锁,实际跑的时候得加mutex或者不用channel直接原子操作,我在这上面翻过车。
第七步:导出结果到CSV
最后一步,把统计结果存成CSV,方便Excel里做图。
func exportToCSV(filename string, daily map[string]time.Duration) error {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
w := csv.NewWriter(f)
defer w.Flush()
w.Write([]string{"日期", "观看时长(小时)"})
for day, d := range daily {
w.Write([]string{day, fmt.Sprintf("%.2f", d.Hours())})
}
return nil
}
注意:csv.Writer的Write方法有长度限制,如果一行超过65535个字符会出错(Go标准库的已知问题),不过我们的数据不会那么胖。
测试很重要——用假数据验证
写代码没人一次就对,我生成了随机假数据来测试:
func generateMockData(count int) []DouyinVideo {
cats := []string{"编程", "美食", "健身", "搞笑", "旅行"}
videos := make([]DouyinVideo, count)
for i := 0; i < count; i++ {
videos[i] = DouyinVideo{
ID: fmt.Sprintf("v%d", i),
Title: "测试视频" + strconv.Itoa(i),
Author: "作者" + strconv.Itoa(rand.Intn(5)),
Category: cats[rand.Intn(len(cats))],
Duration: rand.Intn(240) + 10, // 10~250秒
WatchTime: time.Now().AddDate(0, 0, -rand.Intn(365)), // 最近365天
Liked: rand.Intn(2) == 0,
}
}
return videos
}
然后跑一遍,看输出是否合理。
优化方向——还有啥可做的?
目前这个工具能跑,但距离“完整”还差很远,我列几个可以考虑的点:
- 缓存中间结果——每次跑都重新解析JSON太慢,用
gob或CSV存中间态 - Web界面——用
net/http起个本地服务,浏览器里交互式查看 - 时间序列分析——连续7天观看时长下降了吗?”,需要统计窗口函数
- 用户行为序列——用
顺序模式挖掘看你自己刷视频的路径(虽然有点自恋)
踩过的坑
写这个工具过程中,我实际遇到的几个坑:
time.Parse的布局字符串——必须用"2006-01-02 15:04:05"而不是"YYYY-MM-DD ...",我第一次用了后者,解析全错。- JSON字段大小写——抖音返回的是
"watch_time"(下划线),而Go结构体用WatchTime,需要写json:"watch_time",不写就绑不上。 sort.Slice是原地排序——会改变原切片顺序,记得先copy。map的遍历顺序是随机的——输出报告前得先排序,不然每次结果不一样。
现在工具能跑,结果也挺有意思——我发现自己每周二晚上刷视频时长是其他日子的1.8倍,可能是因为那天项目例会后特别累。
其实我本想做更多(比如预测明天刷多久),但先这样吧——工具能帮你看清行为模式,就已经很有价值了,剩下的,等以后有兴致再写,用Go的好处就是,哪天想扩展,编译一下就能部署到任何地方跑,你可能会遇到自己那365天的数据,然后发现——原来我一年看了130小时的猫视频。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://hljbesthome.com/keji/2183.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《用Go语言写一个365天抖音视频分析器,从数据采集到可视化的完整实践》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:前两天刷抖音,突然想看看自己一年到底刷了多少条视频——但抖音不给你导出数据啊,正好最近在学Go,那就自己动手写个工具呗,这篇文章就是记录...