用Go语言给QQ机器人加个‘眼睛’:手把手教你抓取Pixiv每日热榜并自动发图

张开发
2026/6/23 11:49:03 15 分钟阅读
用Go语言给QQ机器人加个‘眼睛’:手把手教你抓取Pixiv每日热榜并自动发图
用Go语言构建智能QQ机器人Pixiv热榜抓取与自动化推送实战在数字内容爆炸的时代如何高效获取优质视觉内容成为许多社群运营者和内容爱好者的痛点。想象一下当你的QQ群成员只需输入简单指令就能即时获取Pixiv平台当日最热门的插画作品——这种自动化体验不仅能提升社群活跃度还能成为技术爱好者展示能力的绝佳项目。本文将带你用Go语言打造这样一个有眼睛的QQ机器人重点解决三个核心问题如何模拟移动端行为与Pixiv API交互、如何设计稳定的数据抓取流程以及如何优雅地将内容集成到QQ机器人框架中。1. 逆向工程解密Pixiv移动端API1.1 理解Pixiv的认证机制Pixiv对API访问有着严格的认证要求特别是针对非官方客户端的请求。通过分析Android客户端的行为我们发现其认证流程主要依赖以下几个关键要素OAuth 2.0令牌通过用户名密码获取的access_token设备指纹X-Client-Hash和X-Client-Time组成的签名请求头伪装完整模拟官方客户端的headersfunc generateClientHash() (string, string) { currentTime : time.Now().Format(2006-01-02T15:04:0508:00) hashInput : currentTime 28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c hash : md5.Sum([]byte(hashInput)) return hex.EncodeToString(hash[:]), currentTime }1.2 构建可靠的HTTP客户端考虑到Pixiv对频繁请求的限制我们需要一个具备以下特性的HTTP客户端连接复用Keep-Alive保持长连接超时控制避免单次请求阻塞整个流程自动重试对临时性错误进行智能重试transport : http.Transport{ MaxIdleConns: 10, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, DialContext: (net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, } client : http.Client{ Transport: transport, Timeout: 60 * time.Second, }提示Pixiv API对请求频率有限制建议在代码中加入适当的延迟如500ms-1s between requests2. 数据抓取与处理流水线2.1 解析热榜JSON数据结构Pixiv返回的JSON数据结构复杂但规律性强我们需要定义对应的Go结构体来反序列化数据。关键字段包括illusts数组包含作品基本信息image_urls不同尺寸的图片URLnext_url分页获取的链接type IllustInfo struct { ID int json:id Title string json:title ImageURLs struct { Large string json:large Medium string json:medium SquareMedium string json:square_medium } json:image_urls Artist struct { ID int json:id Name string json:name } json:user } type RankingResponse struct { Illusts []IllustInfo json:illusts NextURL string json:next_url Contest interface{} json:contest }2.2 实现智能缓存机制为避免重复下载和API调用我们需要设计三级缓存内存缓存使用sync.Map存储近期请求结果本地文件缓存将图片保存到本地文件系统URL去重基于MD5的URL指纹判断是否已处理var imageCache sync.Map func getCacheKey(url string) string { hash : md5.Sum([]byte(url)) return hex.EncodeToString(hash[:]) } func checkCache(url string) ([]byte, bool) { key : getCacheKey(url) if val, ok : imageCache.Load(key); ok { return val.([]byte), true } return nil, false }3. QQ机器人集成实战3.1 基于go-cqhttp的机器人框架go-cqhttp是目前最稳定的QQ机器人框架之一提供了完善的API和事件处理机制。我们需要处理的主要消息类型私聊消息一对一交互群组消息群体内容分发指令解析自定义命令处理bot, err : qqbotapi.NewBotAPI(your_token, ws://127.0.0.1:6700, ) if err ! nil { log.Fatal(err) } updates : bot.ListenForWebSocket() for update : range updates { if update.Message nil { continue } if strings.HasPrefix(update.Message.Text, !pixiv) { handlePixivCommand(bot, update) } }3.2 设计用户友好的交互指令良好的交互设计能显著提升用户体验建议采用以下指令格式!pixiv hot [数量]获取指定数量的热门作品!pixiv search 关键词搜索特定标签作品!pixiv artist ID获取画师最新作品用户输入示例 !pixiv hot 5 机器人响应 【今日Pixiv热榜TOP5】 1. 作品标题 by 画师名 [图片] 2. 作品标题 by 画师名 [图片] ... 输入!pixiv detail 编号 查看详细信息4. 系统优化与错误处理4.1 构建健壮的错误恢复机制网络请求不可避免地会遇到各种异常情况我们需要为每种错误设计恢复策略错误类型可能原因恢复策略401 UnauthorizedToken过期自动刷新Token并重试429 Too Many Requests请求频率过高指数退避重试503 Service Unavailable服务器维护暂停1小时后重试网络超时连接不稳定最多重试3次func getWithRetry(url string, maxRetries int) (*http.Response, error) { var lastErr error for i : 0; i maxRetries; i { resp, err : http.Get(url) if err nil { return resp, nil } lastErr err time.Sleep(time.Second * time.Duration(math.Pow(2, float64(i)))) } return nil, lastErr }4.2 性能监控与日志记录完善的日志系统能帮助我们快速定位问题建议记录请求时间戳精确到毫秒响应状态码HTTP状态和业务状态处理耗时各环节执行时间错误详情包括堆栈信息type RequestLog struct { Timestamp time.Time json:timestamp Endpoint string json:endpoint StatusCode int json:status_code Duration int64 json:duration_ms Params string json:params,omitempty Error string json:error,omitempty } func logRequest(start time.Time, endpoint string, status int, err error) { entry : RequestLog{ Timestamp: start, Endpoint: endpoint, StatusCode: status, Duration: time.Since(start).Milliseconds(), } if err ! nil { entry.Error err.Error() } logData, _ : json.Marshal(entry) log.Println(string(logData)) }5. 进阶功能扩展5.1 实现内容过滤系统根据社群规范可能需要过滤某些类型的内容。我们可以基于以下维度构建过滤系统标签过滤屏蔽特定标签的作品画师黑名单不显示指定画师的作品AI生成检测识别并标记AI生成内容type ContentFilter struct { BlockedTags map[string]bool BlockedArtists map[int]bool } func (f *ContentFilter) CheckIllust(illust IllustInfo) bool { for _, tag : range illust.Tags { if f.BlockedTags[tag.Name] { return false } } return !f.BlockedArtists[illust.Artist.ID] }5.2 添加用户偏好记忆通过记录用户历史行为可以提供个性化推荐收藏统计记录用户点赞的作品类型浏览历史分析用户查看的作品特征反馈机制允许用户标记喜欢或不感兴趣type UserPreference struct { UserID int64 FavTags map[string]int // 标签及其权重 FavArtists map[int]int // 画师及其权重 LastUpdated time.Time } func (up *UserPreference) UpdateFromInteraction(illust IllustInfo, action string) { switch action { case like: for _, tag : range illust.Tags { up.FavTags[tag.Name] 1 } up.FavArtists[illust.Artist.ID] 1 case dislike: // 相应减少权重 } up.LastUpdated time.Now() }在实现过程中我发现最耗时的部分不是核心功能的开发而是各种边缘情况的处理。比如Pixiv API返回的数据结构有时会有微妙的变化或者QQ机器人框架在某些网络环境下会出现连接不稳定的情况。这些实际经验让我明白一个健壮的系统不仅要有正确的核心逻辑更需要完善的错误处理和监控机制。

更多文章