emahiro/b.log

Drastically Repeat Yourself !!!!

GolangではてなのRSSを取得するクライアントを作成する

仕様

  • はてなRSSのfeedのURLを登録する
  • 登録したURLでRSSを取得する
  • RSSをparseする

実装

sampleでは、はてなの「テクノロジー」のホットエントリーを使用する。 http://b.hatena.ne.jp/hotentry/it.rss

実際に叩いてみる

$ curl -i http://b.hatena.ne.jp/hotentry/it.rss
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns="http://purl.org/rss/1.0/"
 xmlns:content="http://purl.org/rss/1.0/modules/content/"
 xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
 xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:hatena="http://www.hatena.ne.jp/info/xmlns#"
 xmlns:media="http://search.yahoo.com/mrss"
>
  <channel rdf:about="http://b.hatena.ne.jp/hotentry/it">
    <title>はてなブックマーク - 人気エントリー - テクノロジー</title>
    <link>http://b.hatena.ne.jp/hotentry/it</link>
    <description>最近の人気エントリー - テクノロジー</description>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4" />
        <rdf:li rdf:resource="http://tech.mercari.com/entry/2017/12/18/deadlock" />
        <rdf:li rdf:resource="http://brevis.exblog.jp/26270824/" />
        <rdf:li rdf:resource="http://www.pfu.fujitsu.com/direct/hhkb/hhkb-option/detail_pz-kbbrg.html" />
        <rdf:li rdf:resource="http://japanese.engadget.com/2017/12/18/gif-beam-amoled-24/" />
        <rdf:li rdf:resource="https://speakerdeck.com/hihihiroro/kubernetesniru-men-sitai" />
        <rdf:li rdf:resource="http://coliss.com/articles/freebies/best-free-icons-2017.html" />
        <rdf:li rdf:resource="https://note.mu/macheri_me/n/nf2447d4a6167" />
        <rdf:li rdf:resource="http://fushiroyama.hatenablog.com/entry/2017/12/17/225544" />
        <rdf:li rdf:resource="https://tech.raksul.com/2017/12/18/raksul-platform-project/" />
        <rdf:li rdf:resource="https://qiita.com/advent-calendar/2017/ubiregi" />
        <rdf:li rdf:resource="https://www.894651.com/column/craftman_004" />
        <rdf:li rdf:resource="https://anond.hatelabo.jp/20171218212227" />
        <rdf:li rdf:resource="https://forest.watch.impress.co.jp/docs/serial/yajiuma/1097447.html" />
        <rdf:li rdf:resource="https://game.watch.impress.co.jp/docs/news/1097558.html" />
        <rdf:li rdf:resource="http://www.yukisako.xyz/entry/start_arduino" />
        <rdf:li rdf:resource="http://eng-blog.iij.ad.jp/archives/1188" />
        <rdf:li rdf:resource="https://qiita.com/bokuweb/items/1575337bef44ae82f4d3" />
        <rdf:li rdf:resource="https://fullswing.dena.com/slack/" />
        <rdf:li rdf:resource="https://developers.eure.jp/tech/primer_of_sql/" />
        <rdf:li rdf:resource="https://medium.com/@deeeet/7cf4280d435b" />
        <rdf:li rdf:resource="https://shugo.net/jit/20171215.html#p01" />
        <rdf:li rdf:resource="https://gigazine.net/news/20171218-programming-atcoder/" />
        <rdf:li rdf:resource="http://www.itmedia.co.jp/news/articles/1712/18/news100.html" />
        <rdf:li rdf:resource="http://portal.nifty.com/kiji/171218201494_1.htm" />
        <rdf:li rdf:resource="https://qiita.com/sawara125/items/67a144801e3c2f09f53a" />
        <rdf:li rdf:resource="http://twitter.com/yoppymodel/status/942592739270467584" />
        <rdf:li rdf:resource="https://japan.cnet.com/article/35112083/" />
        <rdf:li rdf:resource="https://qiita.com/karupanerura/items/e90bba7166878ece9f06" />
        <rdf:li rdf:resource="https://codezine.jp/article/detail/10591" />
      </rdf:Seq>
    </items>
  </channel>
  <item rdf:about="https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4">
    <title>仮想通貨自動取引入門 - Qiita</title>
    <link>https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4</link>
    <description>本記事は U-TOKYO AP Advent Calendar 2017 の17日目です。 はじめに 年の瀬が近づき何かと出費がかさむ季節になりましたね。財布の中も真冬です。 実は2ヶ月ほど前から年越しに備えて仮想通貨で資産運用をしています。 他の資産運用と比べたときの仮想通貨取引のメリットは「少額でも大きな利益を得るチャンスがあること」と「24時間365日取引ができること」でしょうか。 というこ...</description>
    <content:encoded>&lt;blockquote cite=&quot;https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4&quot; title=&quot;仮想通貨自動取引入門 - Qiita&quot;&gt;&lt;cite&gt;&lt;img src=&quot;http://cdn-ak.favicon.st-hatena.com/?url=https%3A%2F%2Fqiita.com%2Fshionhonda%2Fitems%2Fbd2a7aaf143eff4972c4&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4&quot;&gt;仮想通貨自動取引入門 - Qiita&lt;/a&gt;&lt;/cite&gt;&lt;p&gt;本記事は U-TOKYO AP Advent Calendar 2017 の17日目です。 はじめに 年の瀬が近づき何かと出費がかさむ季節になりましたね。財布の中も真冬です。 実は2ヶ月ほど前から年越しに備えて仮想通貨で資産運用をしています。 他の資産運用と比べたときの仮想通貨取引のメリットは「少額でも大きな利益を得るチャンスがあること」と「24時間365日取引ができること」でしょうか。 というこ...&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://b.hatena.ne.jp/entry/https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4&quot;&gt;&lt;img src=&quot;http://b.hatena.ne.jp/entry/image/https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4&quot; alt=&quot;はてなブックマーク - 仮想通貨自動取引入門 - Qiita&quot; title=&quot;はてなブックマーク - 仮想通貨自動取引入門 - Qiita&quot; border=&quot;0&quot; style=&quot;border: none&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://b.hatena.ne.jp/append?https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4&quot;&gt;&lt;img src=&quot;http://b.hatena.ne.jp/images/append.gif&quot; border=&quot;0&quot; alt=&quot;はてなブックマークに追加&quot; title=&quot;はてなブックマークに追加&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;</content:encoded>
    <dc:date>2017-12-18T16:22:14+09:00</dc:date>
    <dc:subject>テクノロジー</dc:subject>
    <hatena:bookmarkcount>120</hatena:bookmarkcount>
  </item>
# 略
</rdf:RDF>

I/F

RSSを取得するだけなので、クエリパラメータでURLを渡してあげようと思います。

$ curl -i -X GET http://localhost:8080/rss?url=http://b.hatena.ne.jp/hotentry/it.rss

みたいなGetのURLを叩けばいいですね。

Parseする

構造的には以下です。

channel
  title
  link
  ...
item
item

#略

rssをParseすると言っても、実態はxmlで返ってくるデータ構造をparseすることと同じ。
以前AmazonAPIで遊んだ時と同様に、 encoding/xml を使います。 前回は愚直にxmlの構造をstructに起こしましたが、xmlをparseする時は親子構造を > 使って表現してparseすることができます。

以下のようなstructを定義してrssのfeedをマッピングします。

package model

import (
    "encoding/xml"
)

type HatenaFeed struct {
    XMLName         xml.Name         `xml:"RDF"`
    Title           string           `xml:"channel>title"`
    Link            string           `xml:"channel>link"`
    Description     string           `xml:"channel>description"`
    HatenaBookmarks []HatenaBookmark `xml:"item"`
}

type HatenaBookmark struct {
    XMLName       xml.Name `xml:"item"`
    Title         string   `xml:"title"`
    Link          string   `xml:"link"`
    Description   string   `xml:"description"`
    Content       string   `xml:"content"`
    Date          string   `xml:"date"`
    Subject       string   `xml:"subject"`
    BookmarkCount int64    `xml:"bookmarkcount"`
}

これでfeedを取得したのち、レスポンスをbyte型に変換して xml.Unmarshal でparseすることで以下のような構造のオブジェクトを取得できます。

$~/e/golang-hatena-client  go run src/golang-hatena-client/main.go                                                                                 火 12/19 03:45:02 2017
&model.HatenaFeed{
  XMLName: xml.Name{
    Space: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
    Local: "RDF",
  },
  Title:           "はてなブックマーク - 人気エントリー - テクノロジー",
  Link:            "http://b.hatena.ne.jp/hotentry/it",
  Description:     "最近の人気エントリー - テクノロジー",
  HatenaBookmarks: []model.HatenaBookmark{
    model.HatenaBookmark{
      XMLName: xml.Name{
        Space: "http://purl.org/rss/1.0/",
        Local: "item",
      },
      Title:         "仮想通貨自動取引入門 - Qiita",
      Link:          "https://qiita.com/shionhonda/items/bd2a7aaf143eff4972c4",
      Description:   "本記事は U-TOKYO AP Advent Calendar 2017 の17日目です。 はじめに 年の瀬が近づき何かと出費がかさむ季節になりましたね。財布の中も真冬です。 実は2ヶ月ほど前から年越しに備えて仮想通貨で資産運用をしています。 他の資産運用と比べたときの仮想通貨取引のメリットは「少額でも大きな利益を得るチャンスがあること」と「24時間365日取引ができること」でしょうか。 というこ...",
      Content:       "",
      Date:          "2017-12-18T16:22:14+09:00",
      Subject:       "テクノロジー",
      BookmarkCount: 174,
    },
# 略

今回の実装ではクエリパラメータに入るURLははてなのURLであればなんでも入れてRSSを取得できます。

書いたコードはこちら

github.com