なぜ絞り込む必要があるか

PR Times の RSS は一日 300 件近くニュースが飛んできます。これを普通の RSS リーダに登録すると PR Times で全て埋まります。テロです。 実際 slack に登録してみたところ、1 時間おきとかに、通知が 10 件飛んできて、とてもじゃないけど見る気になりませんでした。この中から絞り込んで欲しい情報だけの RSS にしたいというのが今回の目標です。

他の絞り込みツール

こちらの記事が参考になります。この記事を読んでわかることは、PR Times やばいです。 実際にこの記事のツールを試してみましたが、PR Times がやばすぎて、zapier の上限に達したりとなかなか上手くいかなかったです。

Cloud Function で絞り込む

そこで最後の手段の自作です。

流れとしては以下のような流れで絞り込みを行ないます。

filter_rss

今回は Go 言語の、RSS をパースするツールの mmcdole/gofeed と RSS を作成する gorilla/feedsを使用しています。

コードの全体はこんな感じ

package rssfilter

import (
    "context"
    "log"
    "net/http"
    "regexp"
    "time"

    "github.com/gorilla/feeds"
    "github.com/mmcdole/gofeed"
    "github.com/pkg/errors"
)

const feedURL = "https://prtimes.jp/index.rdf"

var searchText = regexp.MustCompile(`Cloud|cloud|クラウド|IOT|DX|テクノロジー|GCP|Google`)

func FilterRss(w http.ResponseWriter, r *http.Request) {
    if err := filterRss(w, r); err != nil {
        log.Printf("[ERROR] error: %+v", err)
        w.WriteHeader(http.StatusInternalServerError)
        w.Write([]byte(err.Error()))
        return
    }
    w.WriteHeader(http.StatusOK)
}

func filterRss(w http.ResponseWriter, r *http.Request) error {
    ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second)
    defer cancel()
    fp := gofeed.NewParser()
    feed, err := fp.ParseURLWithContext(feedURL, ctx)
    if err != nil {
        return errors.Wrap(err, "get rss")
    }

    result := feeds.Feed{
        Title:       feed.Title,
        Link:        &feeds.Link{Href: feed.Link},
        Description: feed.Description,
        Items:       nil,
        Copyright:   feed.Copyright,
    }
    for _, item := range feed.Items {
        if searchText.MatchString(item.Content) || searchText.MatchString(item.Title) {
            result.Items = append(result.Items, &feeds.Item{
                Title:       item.Title,
                Link:        &feeds.Link{Href: item.Link},
                Description: item.Description,
                Created:     *item.PublishedParsed,
            })
        }
    }
    rss, err := result.ToRss()
    if err != nil {
        return errors.Wrap(err, "convert rss")
    }

    if _, err := w.Write([]byte(rss)); err != nil {
        return errors.Wrap(err, "write rss")
    }
    return nil
}

gofeed で PR Times からデータを取得してきて、そのコンテントとタイトルを正規表現で絞り込むことで、数を減らしています。 そして、絞り込んだものを、gorilla/feeds で RSS の形式に戻して、レスポンンスに書きこむことで完了です。 RSS の定義的には作成日は必要ないんですが、今回は slack の rss で使用するため作成日のフィールドも代入しています(slack は作成日で RSS の管理をしているみたい)。

この関数を適当に Cloud Function にアップロードして、発行された URL を購読の RSS として指定すれば終わりです。

gcloud functions deploy FilterRss --runtime go113 --region="asia-northeast1" --trigger-http --allow-unauthenticated

感想

もっと早く自前で書けばよかったと思うほど簡単に実装ができました。 絞り込みの内容も正規表現をいじるだけなので、とても簡単です。

今は PR Times が静かすぎるので、正規表現をいじって、いい感じの落ち所を見つけらたらいいなと考えています。