最近在整理自己的抖音内容资产时,发现官方后台并没有提供完整的合集导出功能。作为一个技术从业者,我决定用Go语言写个小工具来解决这个问题。这个项目不仅能批量获取自己的抖音合集列表,还能导出每个作品的详细数据(包括标题、发布时间、播放量等),对于内容创作者进行数据分析特别有用。
市面上虽然有些第三方工具号称能实现类似功能,但要么收费昂贵,要么存在数据安全隐患。自己动手的好处是数据全程可控,还能根据需求灵活定制导出字段。整个工具开发下来不到300行代码,但解决了实际工作中的大问题。
工具采用典型的爬虫架构,分为三个核心模块:
选择Go语言主要考虑其并发性能优势,特别是在处理分页请求时,goroutine能显著提升采集效率。实测对比发现,用Python实现的相同功能需要12秒完成的任务,Go版本只需3-4秒。
go复制import (
"github.com/go-resty/resty/v2" // HTTP客户端
"github.com/tidwall/gjson" // JSON解析
"encoding/csv" // CSV导出
"os"
"sync"
)
Resty相比标准库net/http提供了更便捷的链式调用和重试机制。在采集抖音接口时,经常会遇到网络波动,设置自动重试非常必要:
go复制client := resty.New().
SetRetryCount(3).
SetRetryWaitTime(5 * time.Second)
抖音网页端的认证主要依赖cookie中的sessionid。获取方法:
sessionid值go复制headers := map[string]string{
"Cookie": "sessionid=你的值",
"User-Agent": "Mozilla/5.0",
}
重要提示:sessionid有效期约30天,过期后需要重新获取。千万不要在代码中硬编码或在GitHub泄露这个值!
抖音的合集接口是POST请求,需要构造特定参数:
go复制body := map[string]interface{}{
"cursor": 0, // 分页游标
"count": 20, // 每页数量
"type": 3, // 固定值
}
响应数据中的关键字段路径:
data.collects[].collect.iddata.collects[].collect.namedata.collects[].collect.video_count每个合集下的作品需要单独请求:
go复制detailParams := map[string]interface{}{
"collect_id": collectID,
"cursor": cursor,
"count": 30,
}
作品数据解析技巧:
gjson.Get(resp.String(), "data.videos.0.video.title").String()time.Unix(createTime, 0).Format("2006-01-02 15:04:05")采用worker pool模式控制并发度,避免被封IP:
go复制var wg sync.WaitGroup
ch := make(chan int, 5) // 并发度为5
for page := 0; page < totalPage; page++ {
ch <- 1
wg.Add(1)
go func(p int) {
defer wg.Done()
fetchPage(p)
<-ch
}(page)
}
wg.Wait()
由于抖音接口可能存在数据重复,需要在内存中维护已采集的ID集合:
go复制var (
collected sync.Map
mutex sync.Mutex
)
func isProcessed(id string) bool {
_, loaded := collected.LoadOrStore(id, true)
return loaded
}
建议包含以下字段:
csv复制合集ID,合集名称,作品ID,作品标题,发布时间,播放量,点赞数,评论数,分享数,视频链接
代码实现示例:
go复制func writeCSV(filename string, data []VideoItem) error {
file, _ := os.Create(filename)
defer file.Close()
writer := csv.NewWriter(file)
_ = writer.Write([]string{
"collect_id", "collect_name",
"video_id", "title",
"create_time", "play_count",
"digg_count", "comment_count",
"share_count", "video_url",
})
for _, item := range data {
record := []string{
item.CollectID, item.CollectName,
item.VideoID, item.Title,
item.CreateTime, strconv.Itoa(item.PlayCount),
strconv.Itoa(item.DiggCount), strconv.Itoa(item.CommentCount),
strconv.Itoa(item.ShareCount), item.VideoURL,
}
_ = writer.Write(record)
}
writer.Flush()
return nil
}
当数据量较大时(超过1万条记录):
csv.Writer的缓冲机制403 Forbidden
原因:请求频率过高或cookie失效
解决方案:
time.Sleep(time.Duration(rand.Intn(3)) * time.Second)数据字段缺失
抖音接口有时会返回不完整数据,需要做防御性编程:
go复制playCount := gjson.Get(video, "statistics.play_count")
if !playCount.Exists() {
playCount = gjson.Get(video, "stats.play_count") // 尝试备用路径
}
请求头伪装
必须设置完整的headers:
go复制client.SetHeaders(map[string]string{
"Accept": "application/json",
"Accept-Language": "zh-CN,zh;q=0.9",
"Origin": "https://www.douyin.com",
"Referer": "https://www.douyin.com/",
})
IP限制
建议:
导出的CSV可以配合Pandas进行深度分析:
python复制import pandas as pd
df = pd.read_csv('douyin_export.csv')
top_videos = df.sort_values('play_count', ascending=False).head(10)
典型分析维度:
结合crontab实现定期备份:
bash复制0 3 * * * /path/to/export_tool -o ~/douyin_backup/$(date +\%Y\%m\%d).csv
项目推荐目录结构:
code复制douyin-export/
├── main.go # 主入口
├── collector/ # 采集模块
│ ├── auth.go # 认证相关
│ ├── collect.go # 合集采集
│ └── video.go # 作品采集
├── exporter/ # 导出模块
│ └── csv.go # CSV导出
└── models/ # 数据模型
└── video.go # 结构体定义
核心模型定义示例:
go复制type VideoItem struct {
CollectID string `json:"collect_id"`
CollectName string `json:"collect_name"`
VideoID string `json:"video_id"`
Title string `json:"title"`
CreateTime string `json:"create_time"`
PlayCount int `json:"play_count"`
DiggCount int `json:"digg_count"`
CommentCount int `json:"comment_count"`
ShareCount int `json:"share_count"`
VideoURL string `json:"video_url"`
}
这个工具我已在团队内部使用半年多,稳定导出了超过3万条作品数据。最大的收获是发现了几个高播放量作品的共同特征,后续针对性生产类似内容后,平均播放量提升了40%。代码虽然简单,但数据带来的业务洞察非常宝贵。