RSS 리더는 그만두고 Google Apps Script에서 chatwork에 뉴스를 흘려 보았습니다.

이 기사는 NIFTY Advent Calendar 2017의 12일째 기사입니다.

폐사 엔지니어를 위해 chatwork에 IT 관련 뉴스를 주워 왔습니다만, 이번 달 퇴직한 엔지니어로부터 도움이 되었다고 처음으로 말하기도 했으므로, 특히 드문 이야기도 아니지만 써 보는 것에 했습니다.

개요


  • Google Alert에 수집하고 싶은 정보의 키워드를 등록하여 RSS feed로 출력시킨다
  • Google Apps Script로 출력 된 RSS Feed를 정기적으로로드합니다
  • Feed를 위에서 순서대로 확인하고 chatwork에 마지막으로 게시 한 기사의 URL과 다른 (= 새로운) 경우 chatwork의 API를 사용하여 뉴스 채널에 게시합니다.

    RSS Feed를 제공하지 않는 곳이 늘어나거나 Google Alert로 픽업되는 사이트가 그다지 심하지 않았던 것도 있어 Feed는 기본적으로 Google Alert만으로 하고 있습니다. (하부 등은 그대로 사용하고 있습니다만)

    Google Alert 등록



    굳이 설명하지는 않습니다만, Google Alert에서도 google의 검색 옵션을 그대로 사용할 수 있으므로, 불필요한 정보를 주워 오면 적절히 조정하도록 하고 있습니다. (참고: 웹 검색의 정확성 향상 )
    IT와 상관없습니다만, 당사 모회사의 정보로 서포트하고 있는 스포츠 클럽이나 구인 정보 이외의 것을 줍는데 이하와 같은 설정을 하고 있거나 합니다.

    "노지마 -"노지마 스텔라"- "노지마 엔지니어링"- "노지마 사가미하라 라이즈"-site:townwork.net -site: w w. f 로마. 작은 m -site: www.nikkansports.com "

    Google Apps Script 구현



    Feed 로드, 분석 및 chatwork에 대한 게시물은 익숙한 Google Apps Script로 작성되었습니다. Feed URL 및 게시자 채널 목록은 수정하기 쉽게 Google 스프레드시트에 작성되었습니다.
    chatwork의 token, Google 스프레드시트의 ID, 마지막으로 확인한 기사의 URL은 스크립트 속성에 넣습니다.

    ga2cw.gs
    function GoogleAlert2Chatwork(channelId, feedUrl){
      var properties = PropertiesService.getScriptProperties().getProperties();
    
      this.feedUrl = feedUrl;  
      this.channelId = channelId;
      eval("this.lastChecked = properties.rid" + this.channelId + "_lastChecked;");
    }
    
    GoogleAlert2Chatwork.prototype = {
      constructor: GoogleAlert2Chatwork,
      postMessage: function(message) {
        if (message != ''){
          var payload = {
            'body' : message
          };
    
          var options = {
            'method'  : 'post',
            'headers' : {'X-ChatWorkToken' : properties.token},
            'payload' : payload
          };
    
          UrlFetchApp.fetch('https://api.chatwork.com/v2/rooms/' + this.channelId + '/messages', options);
        }
      },
      parseFeed: function() {
        var atomNS = XmlService.getNamespace('http://www.w3.org/2005/Atom');
        var document = XmlService.parse(UrlFetchApp.fetch(this.feedUrl).getContentText());
        var entry = document.getRootElement().getChildren('entry', atomNS);
    
        var items = new Array();   
        for(var i in entry){
          var item = {
            'title'   : entry[i].getChild('title',atomNS).getText().replace(/<("[^"]*"|'[^']*'|[^'">])*>/g,''),
            'link'    : decodeURIComponent(entry[i].getChild('link',atomNS).getAttribute('href').getValue().match(/&url=(.*)&ct=ga/)[1]),
            'summary' : entry[i].getChild('content',atomNS).getText().replace(/<("[^"]*"|'[^']*'|[^'">])*>/g,'').replace(/&nbsp;|&raquo;|and more/g,' '),
            'time'    : Utilities.formatDate(new Date(entry[i].getChild('updated',atomNS).getText()
                        .replace('T',' ').replace('Z',' GMT').replace(/-/g,'/')), 'JST', "yyyy-MM-dd HH:mm:ss")
          };
    
          items.push(item);
          if(i == 0){
            eval("PropertiesService.getScriptProperties().setProperty('rid" + this.channelId + "_lastChecked', item['link']);");
          }
        }
    
        return items;
      }
    };
    

    main.gs
    function run(){
      var spreadSheet = SpreadsheetApp.openById(PropertiesService.getScriptProperties().getProperty('feedListSheetId'));
      range = spreadSheet.getActiveSheet().getRange(1, 1, 10, 2); // セルの取得範囲は適当に決め打ち
      var feedList = range.getValues();
    
      // 1つ目のセルにchatworkのchannel id、2つ目にFeed URL 
      for(var i = 0; i < feedList.length; i++){
        if(feedList[i][0]  == '' || feedList[i][1] == ''){
          break;
        }
    
        var ga2c = new GoogleAlert2Chatwork(feedList[i][0],feedList[i][1]);  
        var entries = ga2c.parseFeed();
    
        // 新着だけを投稿
        var messages = '';
        for(var e in entries) {
          if(entries[e].link == ga2c.lastChecked) {
            break;
          }else{
            messages = '[info][title]' + entries[e].title + '\n['+ entries[e].time + '][/title]' + entries[e].link + '[hr]' + entries[e].summary + '[/info]';
            ga2c.postMessage(messages);
          }
        }
      }
    }
    

    parseFeed에 타이틀 등에서 불필요한 태그를 제거하는 처리가 엉망으로 들어가 있습니다만, 기본적으로는 Feed로부터 title, url, content, updated를 꺼내, chatwork의 API를 사용해 투고하는 것만 큼 간단합니다 내용입니다.

    기사에 대한 댓글을 같은 채널에 쓰면 채워지기 때문에 chatwork의 발언을 클립보드에 복사하는 기능을 사용하여 팀의 채널에 복사하기도 합니다.

    이 외에도 TECH PLAY의 공부회의 정보나 PR TIMES의 보도자료를 스크래핑으로 주워 흘리기도 하고 있습니다. (GAS에서 스크래핑은 고생하기 쉽기 때문에 Google Cloud functions 및 AWS Lambda를 사용하는 것이 좋습니다.)

    집계하고 어때?



    chatwork/slack/stride 무엇이든 좋다고 생각합니다만, 채팅 기능이 있는 툴에 집약하면 공유하거나, 토론하는 것이 편해, 취약성의 이야기 등 중요한 정보의 공유가 늘어난 것 같은 생각이 하고 있습니다.

    다음은 RSS 리더의 무렵부터 해결하고 있지 않은 「픽업 오는 정보가 많아서 읽어내는 문제」를 해결하는 구조를 생각하고 싶은 곳입니다.
  • 좋은 웹페이지 즐겨찾기