1. 资料
1.1. 第三方包
- github.com/PuerkitoBio/goquery
- github.com/go-redis/redis
beego 框架定时任务包
1.2 接口
百度新闻: 美剧关键字
钉钉群 BOT 文档
2. 初始化项目变量
- package main
- import (
- "fmt"
- "log"
- "github.com/PuerkitoBio/goquery"
- "github.com/go-redis/redis"
- "net/http"
- "bytes"
- "github.com/astaxie/beego/toolbox"
- )
- var (
- redisClient *redis.Client //redis 缓存
- // 钉钉群机器人 webhook 地址
- dingdingURL = "https://oapi.dingtalk.com/robot/send?access_token=dingding_talk_group_bot_webhook_token"
- // 百度新闻搜索关键字 URL
- baiduNewsUrlWithSearchKeyword = "http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=物联网"
- )
- const (
- newsFeed = "news_feed"// 爬取到的百度新闻 redis key
- newsPost = "news_post"// 已发送的百度新闻 redis key
- newsList = "iot_news" // 储存了的百度新闻 redis key
- )
- // 实例化 redis 缓存
- func init() {
- redisClient = redis.NewClient(&redis.Options{
- Addr: "127.0.0.1:6379",
- Password: "ddfrfgtre4353252", // redis password
- DB: 0, // redis 数据库 ID
- })
- }
在机器人管理页面选择自定义机器人, 输入机器人名字并选择要发送消息的群如果需要的话, 可以为机器人设置一个头像点击完成添加
点击复制按钮, 即可获得这个机器人对应的 Webhook 地址, 赋值给 dingdingURl
3 func newBot
3.1 使用 goquery 和网页元素选择器语法提取有用信息
- func newsBot() error {
- // 获取 html doc
- doc, err := goquery.NewDocument(baiduNewsUrlWithSearchKeyword)
- if err != nil {
- return nil
- }
- // 使用 redis pipelien 减少 redis 连接数
- pipe := redisClient.Pipeline()
- // 使用 selector xpath 语法获取有用信息
- // 储存新闻到 redis 中 newsList
- // 储存新闻 ur 到 redis-set 建 newfeed 为以后是用 sdiff 找出没有发送的新闻
- doc.Find("div.result").Each(func(i int, s *goquery.Selection) {
- // For each item found, get the band and title
- URL, _ := s.Find("h3 > a").Attr("href")
- Source := s.Find("p.c-author").Text()
- Title := s.Find("h3 > a").Text()
- markdown := fmt.Sprintf("- [%s](%s) _%s_", Title, URL, Source)
- pipe.HSet(newsList, URL, markdown)
- pipe.SAdd(newsFeed, URL)
- })
- // 执行 redis pipeline
- pipe.Exec()
3.2 排除以发送的新闻, 拼接 markdown 字符串
- // 使用 redis sdiff 找出没有发送的新闻 url
- unSendNewsUrls: =redisClient.SDiff(newsFeed, newsPost).Val()
- // 新闻按 dingding 文档 markdonw 规范拼接
- content: =""
- for _,
- url: =range unSendNewsUrls {
- md: =redisClient.HGet(newsList, url).Val() content = content + "\n" + md
- // 记录已发送新闻的 url 地址
- pipe.SAdd(newsPost, url)
- }
- pipe.Exec()
3.3 调用钉钉群机器人接口
- // 如果有未发送新闻 请求钉钉 webhook
- if content != "" {
- formt := `
- {
- "msgtype": "markdown",
- "markdown": {
- "title":"IOT 每日新闻",
- "text": "%s"
- }
- }`
- body := fmt.Sprintf(formt, content)
- jsonValue := []byte(body)
- // 发送消息到钉钉群使用 webhook
- //xiang 见钉钉文档 https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.karFPe&treeId=257&articleId=105735&docType=1
- resp, err := http.Post(dingdingURL, "application/json", bytes.NewBuffer(jsonValue))
- if (err != nil) {
- return err
- }
- log.Println(resp)
- }
- return nil
- }
func newBot 函数完成
4. 设置定时任务
- func main() {
- // 销毁 redisClient
- defer redisClient.Close()
- // 创建定时任务
- // 每天 8 点 13 点 18 点 自动执行爬虫和机器人
- //
- dingdingNewBot := toolbox.NewTask("dingding-news-bot", "0 0 8,13,18 * * *", newsBot)
- //dingdingNewBot := toolbox.NewTask("dingding-news-bot", "0 40 */1 * * *", newsBot)
- //err := dingdingNewBot.Run()
- // 检测定时任务
- // if err != nil {
- // log.Fatal(err)
- // }
- // 添加定时任务
- toolbox.AddTask("dingding-news-bot", dingdingNewBot)
- // 启动定时任务
- toolbox.StartTask()
- defer toolbox.StopTask()
- select {}
- }
spec 格式是参照
5 编译运行
最终完整代码 main.go
- go build main.go
- nohup ./main &
最终效果
来源: https://segmentfault.com/a/1190000013241676