GitHub - huginn/huginn: Create agents that monitor and act on your behalf. Your agents are standing
介绍 在北欧神话中,奥丁的肩膀上坐着两只乌鸦,一只名叫 Huginn,一只名叫 Muninn。这两只乌鸦告诉奥丁他们的所见所闻,毫无遗漏。奥丁在黎明时派出它们,它们飞遍全世界然后在晚餐之前回来汇报,因此,奥丁能知晓很多事情。在Huginn的项目主页上,作者对它有详细的介绍。我们同样可以通过Huginn创建不同的代理,通过这些代理发送HTTP请求获得相关数据,然后将获取到的数据进行处理,就可以在互联网上面收集到各类我们需要的信息了。通过Huginn我们可以比较方便的实现如下功能:
监控你关心的事项例如知乎、微博、贴吧等平台指定的信息,一旦监控到信息,邮件通知你。
监控各大购物平台商品信息,一旦发现折扣信息,邮件通知你。 支持各种形式的发送和接收 WebHooks。
抓取网页内容并且在它们发生变化时发送邮件给你。 将获得的数据进行相应的格式处理并输出,例如RSS。
跟踪天气的变化,如果监测到明天要下雨或下雪,就会发邮件提醒你。
总得来说,Huginn可以帮助我们做好两件事情,一是定制化推送或提醒,二是聚合数据。
目前我的用途:
中间踩坑还是不少的
安装 Huginn 使用 Docker 安装:
拉取镜像 hub.docker.com
启动镜像 docker run -it -p 3000:3000 -v /home/huginn/mysql-data:/var/lib/mysql huginn/huginn
支持外部 MySQL 数据库,但是作为个人使用的话只需要导出内部数据库文件做持久化就好了。 我在群晖里遇到目录权限问题,最后手动把对应目录权限设置为everyone解决的
初始用户名:admin
密码:password
概念讲解 Agent Agent 就是代理,是执行具体操作的角色。如采集网页、运行js代码、发送 webhook 等具体操作。
Scenario Scenario 就是集合,等于是文件夹,用来整理归类 Agent 方便识别。所以不用 Scenario 归类也可以。
Event Event 就是事件,Agent 之前依靠 Event 传递消息和数据。有些 Agent 可以自己产生数据(如爬取网页或解析RSS),有些 Agent 拿到传递的 Event 解析后再发出下一个 Event。
实践 首先当然是去找现成的 RSS ,这样就不用自己写网页采集了。
RSSHub订阅服务 - 胜之不易
有现成的我捡来用了
Shopify Liquid Liquid 是一种字符串模版,用于提取 Agent 传递的 Event 中的数据。
简单点来说 如果上一个 Agent 传递的 Event 是这样的
1 2 3 4 5 { "abc": { "123": "true" } }
那么 {{abc.123}}
的结果就是 true
更多的姿势可以看 Liquid 文档和 Huginn Wiki
使用 Liquid · 设置事件格式huginn/huginn Wiki (github.com)
简介 – Liquid 模板语言中文文档 | Liquid 中文网 (bootcss.com)
消息推送相关 钉钉机器人 消息链接说明 - 钉钉开放平台 (dingtalk.com)
以下是 POST Agent 的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 { "post_url" : "https://oapi.dingtalk.com/robot/send?access_token=10086" , "expected_receive_period_in_days" : "1" , "content_type" : "json" , "method" : "post" , "payload" : { "msgtype" : "actionCard" , "actionCard" : { "title" : "{{title}}" , "text" : "{{content}}" , "btnOrientation" : "1" , "btns" : [ { "title" : "有好康的" , "actionURL" : "dingtalk://dingtalkclient/page/link?url={{encodeUrl}}&pc_slide=false" } ] } } , "headers" : { } , "emit_events" : "false" , "no_merge" : "false" , "output_mode" : "clean" }
飞书机器人 自定义机器人使用指南 - 开发指南 - 开发文档 - 飞书开放平台
以下是 POST Agent 的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 { "post_url" : "https://open.feishu.cn/open-apis/bot/v2/hook/xxx" , "expected_receive_period_in_days" : "0" , "content_type" : "json" , "method" : "post" , "payload" : { "msg_type" : "post" , "content" : { "post" : { "zh_cn" : { "title" : "{{title}}" , "content" : [ [ { "tag" : "text" , "text" : "{{content}}" } , { "tag" : "a" , "text" : "\n\n> 查看详情" , "href" : "{{url}}" } ] ] } } } } , "headers" : { } , "emit_events" : "false" , "no_merge" : "true" , "output_mode" : "clean" }
iOS Bark 使用教程
以下是 POST Agent 的内容
建议使用正常的 POST,Json POST 好像有问题
1 2 3 4 5 6 7 8 9 10 { "post_url" : "https://api.day.app/ping" , "expected_receive_period_in_days" : "1" , "content_type" : "application/x-www-form-urlencoded" , "method" : "post" , "payload" : "title={{title}}&body={{body}}&group={{group}}&icon={{icon}}&isArchive={{isArchive}}&url={{url}}&sound={{sound}}" , "emit_events" : "false" , "no_merge" : "true" , "output_mode" : "clean" }
GitHub 官方也提供了一些 RSS:
仓库 releases: https://github.com/:owner/:repo/releases.atom 仓库 commits: https://github.com/:owner/:repo/commits.atom 用户动态: https://github.com/:user.atom 专属动态: https://github.com/:user.private.atom?token=:secret (登录后在仪表盘页面 (opens new window)找到 Subscribe to your news feed 字样即可) Wiki 历史: https://github.com/:owner/:repo/wiki.atom
使用 Rss Agent ,名为 Github Repo Release Atom
。
1 2 3 4 5 { "expected_update_period_in_days" : "5" , "clean" : "false" , "url" : "https://github.com/huginn/huginn/commits/master.atom" # url 支持数组,可以填入多个 RSS 源。 }
检查频率(Schedule)是 5 个小时(Every 5h),Event 传递给 Github Repo Release Atom Parser
。
数据处理 如果想从 RSS 中解析内容到 飞书机器人,还需要自行处理数据。
因为涉及到时间转换和正则匹配,所以我使用了 JavaScript Agent ,名为Github Repo Release Atom Parser
。
JS 也提供了 Huginn Event 相关的 API,在初始化的时候会有示范代码,右侧也有相应说明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 function formatDate (time, format ) { if (time == null || time == undefined || time == "" ) { return "" ; } var t = new Date (time); var len = t.getTime (); var offset = t.getTimezoneOffset () * 60000 ; var utc = len + offset; var t1 = new Date (utc + 3600000 * 8 ); var tf = function (i ) { return (i < 10 ? '0' : '' ) + i }; return format.replace (/yyyy|MM|dd|HH|mm|ss/g , function (a ) { switch (a) { case 'yyyy' : return tf (t1.getFullYear ()); break ; case 'MM' : return tf (t1.getMonth () + 1 ); break ; case 'mm' : return tf (t1.getMinutes ()); break ; case 'dd' : return tf (t1.getDate ()); break ; case 'HH' : return tf (t1.getHours ()); break ; case 'ss' : return tf (t1.getSeconds ()); break ; } }) } Agent .receive = function ( ) { var events = this .incomingEvents (); for (var i = 0 ; i < events.length ; i++) { var url = events[i].payload .url ; var regex = /^https:\/\/github\.com\/([a-zA-z]+\/[a-zA-z-_\.]+)\/.+$/ ; var res = regex.exec (url); var dateTime = formatDate (new Date (events[i].payload .last_updated ), 'yyyy-MM-dd HH:mm:ss' ); var content = events[i].payload .content .replace (/<.*?>/ig , "" ).replace (/\n\n/ig , "\n" ); this .createEvent ({ 'title' : 'Github ' + res[1 ] + ' Release' , 'content' : content, 'url' : events[i].payload .url }); } }
通过 this.createEvent
创建 Json,传递给飞书机器人 Agent,最后通过 Liquid 提取对应字段就完成了。
参考 TODO Agent介绍
discuz论坛的通用RSS订阅办法