Huginn實現自動經過slack推送豆瓣高分電影

博客搬遷至https://blog.wangjiegulu.comcss

RSS訂閱:https://blog.wangjiegulu.com/feed.xmlhtml

原文連接https://blog.wangjiegulu.com/2018/04/03/huginn_douban_high_score_movies_and_slack/ios

Huginn實現自動經過slack推送豆瓣高分電影

若是還沒有安裝 Huginn,能夠參考這裏git

想象下如下場景:每當有正在上映的電影在豆瓣上的評分超過7.8分,則 huginn 自動編輯一條信息並經過 Slack (固然也能夠用 telegram 等app)通知到我電腦或者手機上。收到信息後,點擊不喜歡忽略,或者點擊購票按鈕直接進入到購票頁面。甚至 Huginn 能夠結合 Google Calendar 查詢你這幾天的行程安排,推送高分電影信息的同時給你選擇一個比較合適觀看電影的時間點,購買好電影票後,huginn 又自動幫你把日程事件寫入到 Google Calendar 中,並設置提醒。是否是很酷?!github

Huginn 就如你的貼心管家,按照你的意願自動幫你完成不少事情。web

咱們先來實現 每當有正在上映的電影在豆瓣上的評分超過7.8分,則給我推送 Slack 信息 這一部分需求。chrome

最後達到的效果以下:json


手機端效果

PC端效果

建立 Agents

首先進入 Huginn 首頁(默認localhost:3000),左上角進入 Scenariosapi

個人理解:Scenario 表明一種場景,通常會包含多個 agent,一個 agent 表示進行一次事件的處理或者變換。拿咱們如今的例子來講,自動經過slack推送豆瓣高分電影 這一整個就是一個 Scenario,可是這個 Scenario 會有不少的 agents 組成,好比:網絡

  • 有一個 agent 是用來從豆瓣網頁獲取當前上映中的全部電影和它們的分數等信息;
  • 一個 agent 是用來從第一個 agent 裏面拿到的全部電影進行過濾,過濾的標準就是 score > 7.8
  • 還有一個 agent 是用來把過濾後的電影經過 slack 推送到咱們手機上。

看着跟 RxJava 的觀察者模式是否是很像?第一個從豆瓣頁面拉取數據的過程就像是 Observable,而後其它的 agent 就像不少的 operator 用來把數據進行轉換和變化,最終通知到 subscriber,這裏的 subscriber 就是咱們本身。咱們經過 huginn 訂閱了 豆瓣高分電影,就是這麼簡單。

點擊左下角的 New Scenario 建立一個名爲 douban_high_score_movie 的 Scenario。

建立獲取數據 agent

第一個 agent 用來從豆瓣官網獲取全部正在上映的電影

douban_high_score_movie 的 Scenario 中點擊 + New Agent 來建立第一個 Agent。

如上圖,你須要去決定你要建立的 agent 的類型(這裏是目前 Huginn 支持的全部的類型)。

咱們經過輸入 "web" 來進行過濾選擇 Website Agent

上圖,左邊是咱們須要去配置的地方;右邊是每一個設置對應的說明。

  • Name:給這個 agent 取個名字,咱們這裏取名爲 step1_get_douban_playing_movies,表示這個 agent 是 douban_high_score_movie 這個 Scenario 的第一步,是用來從豆瓣獲取當前正在上映的全部電影。
  • Schedule:表示調度週期,表示在何時自動執行這個 agent,好比 Every 1d 表示每一天執行一次、Every 2h 表示每2小時執行一次、8pm 表示天天下午8點執行等等;這裏咱們選擇 3pm,天天下午3點執行一次。
  • Keep events:表示事件保留的時間;好比咱們從豆瓣上獲取到全部上映的電影,每一部電影信息都是一個 event,Huginn會把這些 event 保留在本地,你能夠經過這個參數來設置這些 events 在本地保留多少時間,超過這個時間,Huginn會把數據清除。咱們這裏設置1小時(爲何只設置爲1小時,下面咱們會再討論)。
  • Sources:表示這個 agent 處理的數據來源是哪一個 agent。咱們如今建立的 agent 是第一個 agent,是從豆瓣網站上獲取正在上映的全部電影,因此不須要從其餘 agent 傳遞數據(也就是上面說的 events)過來,因此這個留空。
  • Receivers:表示這個 agent 處理完數據以後把這些數據傳入到哪一個 agent。仍是用 RxJava 作類比,由於每一個 agnet 都有可能只是整個觀察者模式中的一個操做符,用來轉化數據,數據轉化完以後,可能還須要其餘 agent 把這些數據作進一步的轉化。
  • Scenarios:表示這個 agent 是數據哪一個 Scenario 的。
  • Options:這個很是關鍵,就是經過這個配置文件(JSON)來進行網絡請求和豆瓣電影數據解析相關的操做的,這個咱們重點講下。

注意:以上沒提到的配置能夠留空

Options 配置

Options 配置其實就是一個 JSON 文件。Website Agent 的 Options 主要的元素有以下:

  • url:網站地址,表示我須要從哪一個網站獲取數據,如今咱們是從豆瓣,因此須要輸入豆瓣正在上映的網址,這裏咱們輸入 https://movie.douban.com/cinema/nowplaying/hangzhou/,固然最後一個地點能夠根據你的常駐地點作相應的修改。
  • type:數據解析的類型,支持的類型有 xmlhtmljsontext 四種,當前豆瓣網址返回的固然是 html 了,因此這裏咱們填寫 html。若是其餘場景,好比 調用第三方開放的 api,返回的類型可能就是 json 或者 xml了。
  • mode:表示獲取數據的模式,咱們這裏選擇 on_change
    • on_change:在數據有更改時纔會獲取做爲 events。
    • merge:把新數據和輸入的數據進行合併。
    • all:獲取全部數據。
  • extract:用來配置(JSON)從這個網站解析出真正咱們想要的數據。若是 typehtml,則每一個數據經過 css 選擇器或者 xpath 來解析出真正的數據。

注意: on_change 這個設置在咱們如今的場景下其實用處不大,這個下面咱們會再討論

最後的 options 以下:

{
  "expected_update_period_in_days": "2",
  "url": "https://movie.douban.com/cinema/nowplaying/hangzhou/",
  "type": "html",
  "mode": "on_change",
  "extract": {
    "title": {
      "css": "li[@data-category='nowplaying']",
      "value": "@data-title"
    },
    "score": {
      "css": "li[@data-category='nowplaying']",
      "value": "@data-score"
    },
    "star": {
      "css": "li[@data-category='nowplaying']",
      "value": "@data-star"
    },
    "release": {
      "css": "li[@data-category='nowplaying']",
      "value": "@data-release"
    },
    "region": {
      "css": "li[@data-category='nowplaying']",
      "value": "@data-region"
    },
    "actors": {
      "css": "li[@data-category='nowplaying']",
      "value": "@data-actors"
    },
    "director": {
      "css": "li[@data-category='nowplaying']",
      "value": "@data-director"
    },
    "detail_url": {
      "css": "li[@data-category='nowplaying']/ul/li/a[@data-psource='poster']",
      "value": "@href"
    },
    "image_url": {
      "css": "li[@data-category='nowplaying']/ul/li/a[@data-psource='poster']/img",
      "value": "@src"
    }
  }
}

以上能夠看出,咱們從豆瓣的每部電影中獲取瞭如下信息:

  • title:電影名字
  • score:電影分數,滿分10分
  • star:電影分數,滿分50分
  • release:上映日期
  • region:地區
  • actors:演員
  • director:導演
  • detail_url:詳細 url
  • image_url:電影封面

注意:獲取具體 xpath 比較簡單的方法:經過 chrome 右鍵的 inspect 來複制拿到。

以上配置完畢後,點擊下面的 Dry Run,應該就會出現如下頁面

最後進行保存。第一個 agent 就建立完畢了。

同時,這個 agent 在運行的過程當中會生成如下 events:

建立過濾 agnet

step1_get_douban_playing_movies 把全部正在上映的電影數據從豆瓣上拉取下來並解析好,生成一個個 events。而後咱們第二個 agent 就須要從這些 events 裏面進行過濾篩選出全部分數大於 7.8(具體的標準能夠本身定) 的電影。至關於 RxJava 的 filter 操做符吧。

一樣建立 agent,選擇爲 TriggerAgent,名字爲 step2_pick_high_score_movies。這是把 Sources 填寫爲第一個 agent 的名字,即 step1_get_douban_playing_movies,表示我要建立的 agent 處理的數據(events)是從 step1_get_douban_playing_movies 來的。

而後重點仍是在 Options 中

  • keep_event:表示是否把我從 step1_get_douban_playing_movies 這個 agent 收到的 events 原封不動地再傳給下一個 agent(下一個 agent 咱們還沒建立),咱們設置爲 true。由於下一個 agent 咱們是用來把數據經過 slack 發送到給咱們本身的,那確定須要第一個 agent 中獲取到的例如電影名字、分數等信息。
  • rules:表示咱們過濾的規則,能夠多個,具體下面說。
  • must_match:表示 rules 中我必需要知足幾個規則,若是是1,則意味着 rules 中全部的規則是或關係(只要知足 rules 中的1個規則便可);默認不填寫的話是必需要知足 rules 中全部的規則。,由於咱們這裏只須要知足一個分數大於7.8就能夠,因此能夠不填寫。

最後 Options 的配置以下:

{
  "expected_receive_period_in_days": "2",
  "keep_event": "true",
  "rules": [
    {
      "type": "field>=value",
      "value": "7.8",
      "path": "$.score"
    }
  ],
  "message": "Looks like your pattern matched in '{{value}}'!"
}

如上,在 rules 中添加一個規則,type 表示匹配規則,field>=value

  • field: 經過下面 path 從 events 匹配出來的數據,這裏是 $.score,因此表示的是電影的分數;
  • value:表示下面 json 的 value 字段的值,這裏爲 7.8

經過簡單的表達式 field>=value 來設定匹配規則:電影分數 >= 7.8分。

至此,第二個 agent 建立完畢。

你一樣能夠經過下面的 Dry Run 來進行測試,測試時由於有 Sources,須要你構造一些假數據做爲輸入來運行。

建立去重 agnet

step2_pick_high_score_movies用來把 step1_get_douban_playing_movies 中從豆瓣官網獲取的電影信息進行高分的過濾(分數>=7.8)。

咱們還須要建立一個去重的 agent,來避免重複給咱們本身推送高分電影(由於咱們如今獲取的頻率是天天進行獲取檢測,可是電影總不多是每部電影只上映一天吧,次日獲取的時候確定有第一天獲取的數據)。

這裏你們可能會有個問題,由於咱們在配置第一個 agent 的時候,已經把 mode 已經設置爲 on_change 了,爲何仍是會有重複數據呢?由於這裏的電影信息中,有諸如 分數 這類的數據,這些數據是隨時可能會有變化的,雖然是同一個電影,可是分數從 8.1 上升到 8.2,那 Huginn 也會認爲知足了 on_change 條件,因此會形成重複推送。因此,咱們還須要單獨作去重處理。

注意: 以前提到過 on_change 等設置在第一個 agent 其實用處不大,一樣也是因爲上面說的緣由,咱們也不知道一樣的電影何時分數會發生變化,就算用了 on_change,也可能會把以前獲取過的數據拿到。因此第一個 agent 的 keep_event 設置的時間比較短,由於這些 events 提供給 on_change 匹配意義不大,因此仍是節省空間,設置短一點。

建立 agent,type 選擇 DeDuplicationAgent,名字取爲 step2_1_deduplication_high_score_moviesSources 填寫爲上一個 agent 的名字,即 step2_pick_high_score_movies

注意:這裏 keep_event 設置了90天,由於一旦通過咱們這個 agent 去重後,events 假設保留1小時,那下一天我再去獲取全部上映的電影並高分過濾後,由於昨天的數據(events)已經被清空了,因此就沒辦法作比較去重了,因此會致使重複數據。因此這裏保存時間應該要>=電影上映的時長,因此這裏設置爲90天,即3個月左右。

DeDuplicationAgent 的 Options 填寫就比較簡單了

  • Property:填寫你要去重依據的字段,咱們這裏根據電影名字來去重,也就是 title
  • Lookback:表示去重的時候跟以前的多少條歷史 events 作比較,同一時期一塊兒上映的電影應該不會超過100部,因此設置爲100了。

建立 slack 通知的 agent

Huginn 自帶有一個 SlackAgent,用來發送 slack 消息。

它使用了 incoming-webhooks 來實現消息的發送。

可是爲了有更多的可玩性,咱們這裏選擇,本身建立一個 slack app,而後經過它的 open api 實現。

所以,咱們須要建立一個 PostAgent。可是在此以前咱們先來配置好 Slack 環境。

配置 Slack 環境

安裝 Slack:https://slack.com

建立本身的 workspace(單首創建一個本身私有的,注意不要使用公司、團隊的 workspace),好比個人是 https://wangjie.slack.com

在本身私有的 workspace 中建立一個私有的 channel:#huginn-movie

這個 channel 就是用來接收高分電影的數據了,固然你也可使用 #general

而後咱們建立一個本身的 app,用來發送電影信息。進入 https://api.slack.com/

點擊 Start Building

  • App Name:能夠隨意填寫
  • Development Slack Workspace:選擇你剛剛建立的私有的 workspace

Add features and functionality 中點擊 Permissions 進入權限配置。

Scope 中添加以下權限:

添加完以上全部權限後,點擊保存,而後從新打開 Permissions,點擊下面按鈕安裝咱們的這個 app 到 slack。


安裝完畢以後,再次進入 Permissions,拷貝 OAuth Access Token

而後,咱們就可使用咱們的 token 來訪問 slack 的 open api 了,具體文檔在這裏:https://api.slack.com/web

咱們須要的發送消息到 #huginn-movie channel 的接口文檔:
https://api.slack.com/methods/chat.postMessage

有了 api 文檔,有了 token,一切就好辦了。

由上述文檔,咱們能夠經過 post 請求,把咱們要發送的電影信息封裝到 attachments 參數中執行請求便可。

並且 attachments 參數能夠參考文檔 https://api.slack.com/docs/message-attachments 來封裝信息。

Slack 環境一切就緒,接下來,回到 Huginn。

建立 Agent 發送 Slack 消息

建立 PostAgent(注意,不是 SlackAgent),取名爲 step3_high_score_movies_to_slack_postSources 填寫爲 step2_1_deduplication_high_score_movies,由於這個 agent 須要把去重後的電影信息經過 slack 發送給咱們。

最終的 Options 配置以下:

{
  "post_url": "{% credential slack_huginn_url_post_message %}",
  "expected_receive_period_in_days": "1",
  "content_type": "json",
  "method": "post",
  "payload": {
    "channel": "huginn-movie",
    "username": "Douban Movie",
    "icon_url": "https://img3.doubanio.com/pics/douban-icons/favicon_48x48.png",
    "attachments": [
      {
        "fallback": "Required plain-text summary of the attachment.",
        "mrkdwn_in": [
          "text",
          "pretext"
        ],
        "color": "#36a64f",
        "pretext": "Hi~ <@{% credential  slack_at_user_id %}>, There is *high score* movie.",
        "author_name": "{{director}}",
        "author_link": "{{detail_url}}",
        "author_icon": "",
        "title": "《{{title}}》",
        "title_link": "{{detail_url}}",
        "text": "*Actors*: {{actors}}",
        "fields": [
          {
            "title": "Score",
            "value": "{{score}}",
            "short": true
          },
          {
            "title": "Star",
            "value": "{{star}}",
            "short": true
          },
          {
            "title": "Region",
            "value": "{{region}}",
            "short": true
          },
          {
            "title": "Release",
            "value": "{{release}}",
            "short": true
          }
        ],
        "image_url": "",
        "thumb_url": "{{image_url}}",
        "footer": "Slack",
        "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
        "ts": "{{\"now\" | date: \"%s\"}}"
      }
    ]
  },
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "{% credential slack_huginn_token %}"
  },
  "emit_events": "false",
  "no_merge": "false",
  "output_mode": "clean"
}

須要注意的是:

  • {\% credential slack_huginn_url_post_message %\}:此類的表達式爲 Liquid-interpolated,具體的值配置在 Credentials 中,能夠理解爲全局定義,在 Credentials 中配置好 key-value 以後,能夠在其它地方以諸如 {\% credential key \%} 的方式來使用,這裏不作過多介紹了。

  • 在消息中使用Slack 中的 @ 某人的功能時,須要拿到對應用戶的 ID,能夠的獲取方式能夠經過在 slack 中選中名字而後 Copy link 的方式拿到用戶連接,用戶鏈接的最後就是 ID。

保存該 Agent,至此,所需的全部的 Agent 都已經建立完畢了。

總結

整個 Scenario 的事件流程圖以下:

Huginn 還支持公開你建立的 Scenario,提供給其它人使用,以上的代碼也已經公開:

http://h.wangjiegulu.com/scenarios/8/export.json

你們能夠直接下載使用,不過須要在 Credentials 中配置以下參數:

  • slack_huginn_token:你建立的 Slack App 的 OAuth Access Token,具體方式能夠參考這裏
  • slack_at_user_id:你須要 @ 的 slack 用戶 ID,填寫你本身的,拿到你 ID 的方式能夠參考這裏
  • slack_huginn_url_post_message:填寫 https://slack.com/api/chat.postMessage 便可。

除了以上例子,Huginn 還能夠完成更多奇思妙想,限制你的只有你的想象力。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息