2行_copy_4

はてブを見る時間を減らすために、人気エントリから少しだけ Slack に自動ポストすることにした

社内では意外と「はてブの人気エントリ」な記事を割りと普通に知ってる前提での会話みたいなものが見えるようなそんなような雰囲気をすこし感じていて、おお、なるほど、未だ情報収集の現役だったか、なんていう気持ちが芽生えつつ、情報格差は減らしたいなと思って自分もちょこちょこ見るようにしてたんですけど、しょっちゅう眺めてるとそれはそれで仕事の時間が減ってしまってこりゃイカンなという気分が高まりはじめ(普通に面白いんで頻繁に見てしまうんだなこれが!)、なんかうまく効率化したいなと思ってシステムを構築しました。

システムとかどうでもいいんで簡単にやりたい

これ以降の流れを読むの興味ないし簡単にやりたいしって人なら、Slack で RSS フィードを読み込ませるのが手っ取り早い。Slack で以下のコマンドを打つと、ホットエントリがどんどん流れてきます。簡単!

/feed subscribe http://b.hatena.ne.jp/hotentry.rss

んで、システムってなにを作ったの?

自分がどんなものを作ったのかというと

毎日 8 時と 12 時に人気エントリトップ数件分の内容を Slack にポスト

これだけ。これだけで「作業中なのにいつのまにか b.hatena.ne.jp を開いてた…俺はなにをしているんだ…」みたいなのはなくなりました。ヤッタネ!

だいたいこんな感じで流れてきます。

画像1

システム構成

Google App Script(GAS)を使っています。GAS で、はてなの RSS フィードを取得してごにょごにょいじってから Slack へ。

GAS の使い方は、この辺のサイトが参考になりそう。

スクリプトのコードは以下。自分の場合は IT と暮らしカテゴリと、あと家計簿的な話題が気になるのでそういった検索結果からも取得してます。だいぶ雑ですんません。

main.gs

var feeds = [
 [ 'http://b.hatena.ne.jp/hotentry.rss', 2 ],
 [ 'https://b.hatena.ne.jp/hotentry/it.rss', 2 ],
 [ 'https://b.hatena.ne.jp/hotentry/life.rss', 1 ],
 [ 'https://b.hatena.ne.jp/search/text?q=%E5%AE%B6%E8%A8%88%E7%B0%BF&sort=popular&date_begin='+ d(-7) +'&date_end=' + d(0) + '&mode=rss', 1 ]
 ];


function d(num) {
 var date = new Date();
 date.setDate(date.getDate() + num);
 return "" + date.getFullYear() + "-" + (date.getMonth()+ 1) + "-" + date.getDate();
}

function main() {
 for(var i = 0 ; i < feeds.length; i ++) {
   updateFeed(feeds[i][0], feeds[i][1]); 
 }
}

function updateFeed(feedURL, max) {
 var items  = getRSSFeed(feedURL);
 var result = parseRSS(items, max);

 for(var i = 0 ; i < result.length; i ++) {
   post_slack('room-kyosuke', 'hateb', ':hatebu:', result[i]);
 }
}

function getRSSFeed(feedURL) {
 // フィードを取得
 var response = UrlFetchApp.fetch(feedURL);
 
 // XMLをパース
 var xml = XmlService.parse(response.getContentText());
 
 // DOM要素を取得
 var root = xml.getRootElement();
 var rss = XmlService.getNamespace('http://purl.org/rss/1.0/');
 var items = root.getChildren('item', rss);
 return items
}

function filtered(items) {
 return items;
}

function parseRSS(items, max) {
 var result = [];
 var rss = XmlService.getNamespace('http://purl.org/rss/1.0/');
 var hatena = XmlService.getNamespace('hatena', 'http://www.hatena.ne.jp/info/xmlns#');
 var dc = XmlService.getNamespace('http://purl.org/dc/elements/1.1/');
 
 for(var i = 0; i < items.length; i++) {
   var title = items[i].getChild("title", rss).getText();
   var description = items[i].getChild("description", rss).getText();
   var url = items[i].getChild("link", rss).getText();
   var date = items[i].getChild("date", dc).getText();
   var comment = items[i].getChild("bookmarkCommentListPageUrl", hatena).getText();
   var count = items[i].getChild("bookmarkcount", hatena).getText();
   var imageurl = items[i].getChild("imageurl", hatena);
   var thumb_url = imageurl ? imageurl.getText() : null;

   //タイトルの文字数が多かったら適当な文字数で切り詰め
   if(title.length > 120) {
     title = title.substring(0, 119) + '…';
   }
   
   if(!isDuplicatedURL(url)) {
     attachment = {
           "fallback": "Required plain-text summary of the attachment.",
           "color": "#00a6e4",
           "title": title,
           "title_link": url,
           "text": description + "...\n<" + comment + "|" + count +" users>",
           "thumb_url": thumb_url,
			"footer": "hateb",
           "footer_icon": "https://b.hatena.ne.jp/favicon.ico",
           "ts": parseInt(new Date(date) / 1000)
     };
     result.push(attachment);
     insertNewURL(url, title);
     if(result.length == max) break;
   }
 }
 return result;
}

slack.gs

var SLACK_TOKEN = YOUR_TOKEN;
var SLACK_HOOK_URL = YOUR_HOOK_URL;
var SLACK_NAME = 'RSS';

function post_slack(channel, slack_name, icon, attachment) {
 var payload = {
   'channel' : channel,
   'username' : slack_name,
   'icon_emoji' : icon,
   'attachments' : [attachment]
 }
 
 var options = {
   'method' : 'POST',
   'payload' : JSON.stringify(payload)
 }
 var response = UrlFetchApp.fetch(SLACK_HOOK_URL, options);
 var content = response.getContentText('UTF-8');
}

Slack のトークンとか Webhook URL とか、もう取り方忘れてしまった。こういうところからいけそうでしょうか?

duplicate.gs

function isDuplicatedURL(url) {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("log");
 var values = sheet.getRange(2, 2, sheet.getLastRow()).getValues();
 for(var i = 0; i <= values.length; i ++) {
   if(values[i] == url) return true;
 }
 return false;
}

function insertNewURL(url, title) {
 var date = new Date();
 
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("log");
 sheet.insertRowBefore(2);
 
 var cell = sheet.getRange("A2:C2");
 cell.setValues([[
   date,
   url,
   title
   ]]);
 
 var fcell = sheet.getRange("A2:A2");
 fcell.setNumberFormats([[
   "yyyy/mm/dd(ddd) HH時"
 ]]);
}

いいなと思ったら応援しよう!