安装 huginn
网上关于如何安装 huginn 的文章太多了, 这里不做介绍, 我自己使用的是 huginn 的 docker 安装方式, docker-compose.yml 如下
version: '2' services: mysql: image: mysql:5.7 volumes: - /data/docker/huginn/mysql:/var/lib/mysql ports: - 3310:3306 environment: MYSQL_ROOT_PASSWORD: <mysql_root_password> MYSQL_DATABASE: huginn MYSQL_USER: huginn MYSQL_PASSWORD: <mysql_password> restart: always huginn: image: huginn/huginn restart: always environment: HUGINN_DATABASE_NAME: huginn HUGINN_DATABASE_USERNAME: huginn HUGINN_DATABASE_PASSWORD: <mysql_password> INTENTIONALLY_SLEEP: 10 PORT: 3000 MYSQL_PORT_3306_TCP_ADDR: mysql MYSQL_PORT_3306_TCP_PORT: 3306 ports: - 3000:3000 links: - mysql
启动后, 配置 nginx 使用 ssl 时发现, 每次登录总是跳转到首页, 变为未登录状态, 解决方式是参考 nginx-ssl, 添加必要的 proxy_set_header
:
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Frame-Options SAMEORIGIN;
安装完成后, 通过默认用户名密码 admin / password
即可登录.
配置 huginn
huginn 中的几个关键术语解释一下:
- Agent
代理, 简单理解就是一个操作, 比如发送消息, 解析网页等等.
- Scenarios
场景, 场景由多个 agent 组成, 通过 agent 构建一个有向图.
- Event
事件, 即 agent 的执行的中间结果, 前一步的 agent 将处理后的信息以 event 的形式抛出去, 由下一步的 agent 去接着处理. 这里就涉及到 agent 中的两个概念, sources 和 receivers, 分别定义的是当前 agent 的前置和后置 agent.
以当前我们的任务为例. 我们要收集信息的页面为 https://maoyan.com/films:
可以看到, 我们能从这个页面获取到最新电影的 中文名称/缩略图/分数, 我们第一步就是要解析这个页面, 获取最基本的信息, 第二步去每部电影的详情页去获取电影的详细信息(介绍, 时间等等), 第三步将获取的信息格式化为 slack message 进行发送.
这里, 我们先创建一个名为 movie 的 Scenarios.
step 1
通过查看页面元素, 我们不难去定位每一个字段
我们新建一个 agent, 类型为 Website Agent, 这个 agent 用于处理页面元素.
{ "expected_update_period_in_days": "2", "url": "https://maoyan.com/films?showType=1&sortId=1", "type": "html", "mode": "on_change", "extract": { "url": { "xpath": "//div[@class="movie-item"]/a/@href", "value": "." }, "poster": { "xpath": "//div[@class="movie-poster"]/img[1]/@src", "value": "." }, "title": { "xpath": "//div[@class="channel-detail movie-item-title"]/@title", "value": "." }, "score": { "xpath": "//div[@class="channel-detail channel-detail-orange"]", "value": "string(.)" } } }
通过点击 Dry Run
可以进行测试. 我们看到可以拉取到的数据如下:
[ { "url": "/films/1217651", "poster": "//ms0.meituan.net/mywww/image/loading_2.e3d934bf.png", "title": "小公主艾薇拉与神秘王国", "score": "4.8" } ]
这个数组中的每个 {} 都将是一个 event 向外发布.
step 2
这里我们再创建一个 agent, url 使用上一步给出的 url 进行拼接.
另外还有一个细节是, 这里的 mode 为 merge
, 意思是, 将上一步的 event 带过了的字段和当前 event 进行合并, 往下一步传.
{ "expected_update_period_in_days": "2", "url": "https://maoyan.com{{url}}", "type": "html", "mode": "merge", "extract": { "titleCn": { "css": ".movie-brief-container .name", "value": "normalize-space(.)" }, "titleEn": { "css": ".movie-brief-container .ename", "value": "normalize-space(.)" }, "cover": { "css": ".avatar-shadow .avatar", "value": "@src" }, "ellipsis": { "css": ".movie-brief-container ul", "value": "normalize-space(.)" }, "description": { "css": ".tab-desc .dra", "value": "normalize-space(.)" } } }
点击 Dry Run
, 在 Event to Send 中填入一个上一步的 event. 如:
{ "url": "/films/1213193", "poster": "//ms0.meituan.net/mywww/image/loading_2.e3d934bf.png", "title": "猫与桃花源", "score": "8.5" }
可以看到我们获取到了更详细的影片信息
[ { "url": "/films/1213193", "poster": "//ms0.meituan.net/mywww/image/loading_2.e3d934bf.png", "title": "猫与桃花源", "score": "8.5", "titleCn": "猫与桃花源", "titleEn": "Cats and Peachtopia", "cover": "http://p0.meituan.net/movie/aadd3c954b697c16455e56f35f12c4be336103.jpg@464w_644h_1e_1c", "ellipsis": "动画,冒险,家庭 中国大陆 / 105分钟 2018-04-05大陆上映", "description": "一只常常在窗台发呆的家猫毯子(李宇峰 配音),一直以来和儿子斗篷(杨砚铎 配音)安逸地生活在城市的一座高楼公寓中。有一天毯子不得不和斗篷分别踏上冒险旅程,去寻找传说中的猫的桃花源。与此同时,毯子必须面对心中一段不愿提起的往事,或许这也是毯子害怕外面的世界,不愿意离开家的重要原因......" } ]
step 3
先要为 slack 创建一个 app, 用于接受消息. Create New App.
为这个 app 创建一个 incoming_webhook. 格式应该是
https://hooks.slack.com/services/XXXXXXXXXX/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxxxx
关于发送 slack, 虽然 huginn 提供了一个 slack agent, 但使用起来仅仅发送最简单的 message 可以使用, 无法构建复杂的格式. 我们改用 post agent.
{ "post_url": "<slack incoming webhook>", "expected_receive_period_in_days": "1", "content_type": "json", "method": "post", "payload": { "username": "猫眼电影", "icon_url": "https://img3.doubanio.com/pics/douban-icons/favicon_48x48.png", "attachments": [ { "fallback": "{{ titleCn }} is online NOW!!", "mrkdwn_in": [ "text", "pretext" ], "color": "#36a64f", "pretext": "Hi~ Dan. There is a new movie.", "title": "{{titleCn}}", "title_link": "https://maoyan.com{{url}}", "text": "{{ ellipsis }}", "fields": [ { "title": "Alias", "value": "{{ titleEn }} ", "short": true }, { "title": "Score", "value": "{{ score }}", "short": true }, { "title": "Description", "value": "{{ description }}", "short": false } ], "image_url": "{{ cover }}", "thumb_url": "{{ poster }}", "footer": "猫眼电影", "footer_icon": "http://www.xz7.com/dir/UploadPic/2014-11/2014111011382236405.jpg" } ] }, "headers": { "Content-Type": "application/json" }, "emit_events": "false", "no_merge": "false", "output_mode": "clean" }
显示效果如下:
关于 slack 的消息格式, 不是本文的重点, 具体可以参考这里 An introduction to messages.
原文链接:https://www.shanhh.com/huginn_for_maoyan_movie/