kondoumh のブログ

- とあるソフトウェアエンジニアのめったに更新されないブログ -

Tumblr で自分の全投稿の reblog / like 数を把握する

Web で面白そうな記事を見つけた場合、読むのに時間かかりそうなのは Pocket に保存しますが、すぐ読めそうなのはざっと読んで記事内の Tweet アイコンから Twitter に流すことが増えています。

昔は Twitter よりも Tumblr を好んで使っていたので記事内のハイライト的なパラグラフを選んで quote して Tumblr に放流してました。最近は quote の頻度は下がっており、たまに Dashboard を見に行ってポツポツと5, 6個 reblog して閉じるということが多いです*1

reblog.kondoumh.com

Tumblr に quote を放流してると、たまに reblog されまくることがあります。フォロワーの多い人に reblog され、さらに quote over100notes jp などハブアカウントに捕捉されると数が伸びます。reblog にしろ quote にしろ、オリジナルの記事を書いたわけではないので twitter の retweet とは全然別物ですが、自分が放った quote に反応があるとそれはそれで嬉しかったりします。ただ、自分のアーカイブを遡っても、notes(reblog や like) の数はあまり把握できないため、過去にどんな投稿の notes が多かったか振り返ることは簡単にできません。

以前、ストック情報サイトを tumblr のセカンドブログとして構築した時に、Tumblr API をちょっと触ってました。

blog.kondoumh.com

www.tumblr.com

ドキュメントを眺めていると notes_count など反応数も取れそうなので、HTML + JavaScript の簡易な環境でデータ取得を試してみました。確認したのは、Chrome 63.0.3239.132 です。

あらかじめ以下で API Key を取得しておきます。

https://www.tumblr.com/oauth/apps

API の URL、対象の Blog の識別子(ドメイン)、API Key をリクエスト URL 構築用に宣言します。

baseurl = "http://api.tumblr.com/v2/blog/";
domain = "your.tumblr.identifer"
api_key = "yourapikey";

投稿数を取得するには、info メソッドを利用します。

https://api.tumblr.com/v2/blog/your.tumblr.identifer/info

Blog の識別子をパスパラメータ、API Key をクエリパラメータとして指定します。 response を JSON 形式で取得すると、キー 'blog' で取得できるオブジェクトから以下のような情報が得られます。

フィールド 説明
title Blog のタイトル
posts 投稿数
name Blog の短縮名
updated 最近の投稿日時
: :

'posts' フィールドに Blog 投稿数が格納されています。

fetch API で投稿数を取得する例です。

async function getPostCount() {
    var count;
    await fetch(`${baseurl}${domain}/info?api_key=${api_key}`).then(response => response.json()).then(json => {
        count = json['response']['blog']['posts'];
    });
    return parseInt(count);
}

投稿に関する情報は、posts メソッドを使用して取得します。

https://api.tumblr.com/v2/blog/your.tumblr.identifer/posts

パスパラメータに Blog 識別子と投稿タイプ (type : text / photo / quote / link ..etc.) を指定します (投稿タイプは省略可能)。クエリパラメータとして API Key の他に reblog_infonotes_info という bool 値を指定する必要があります。一度に取得できる投稿情報は20件なので、取得開始位置を表すクエリパラメータ offset を指定して繰り返し取得します。投稿は投稿日時の降順で取得できます。

クエリパラメータ 説明
reblog_info reblog 情報を取得するか指定
notes_info notes(reblog や like) 情報を取得するか指定
offset 投稿の取得開始位置

reblog_info を指定すると reblog 情報として、reblogged_root_name が取れます。これが実はオリジナルの投稿者 (blog 短縮名)で、この値が取得できない場合、それは自分の投稿ということになります*2notes_info を指定すると投稿に対する反応 (reblog や like) 数 note_count を取得できます。

投稿情報を取得する関数のコード例です。引数には type (投稿タイプ:空文字だと全タイプを取得)、offsetminCount (反応数の閾値) を指定するようにしています。簡便のため取得したデータはその場で CSV としてレンダリングしてます。

function fetchPosts(type, offset, minCount = 0) {
    fetch(`${baseurl}${domain}/posts/${type}?notes_info=true&reblog_info=true&offset=${offset}&api_key=${api_key}`)
        .then(response => response.json()).then(json => {
            $("#offset").html(`offset:${offset}`);
            $.each(json['response']['posts'], function() {
                if (!this['reblogged_root_name'] && parseInt(this['note_count']) >= minCount) {
                    $("#posts").append(`${idLink(this['id'])},${this['date']},${this['type']},${this['slug']},${this['note_count']}<br />`);
                }
            });
        });
}

メインの処理では、投稿数取得のコールバックでループを回して全投稿分の処理を行います。1回の呼び出しごとに 500ms のスリープを入れています。

$(function() {
    getPostCount().then(count => {
        var offset = 0;
        while (offset <= count) {
            fetchPosts('', offset, 3);
            offset += 20;
            sleep(500);
        }
    });
})

僕は 2008 年頃から Tumblr を始めていて、2017年1月6日時点で投稿総数 6562 件でした(ほとんどがフォローしている人の投稿の reblog です)。測定してませんが全件分処理するのに体感で3分程度でした。

reblog じゃない自分が投稿した中で、3件以上反応があったものをタイプ別に集計すると以下のようになりました。

type post
link 7
photo 36
quote 126
text 5
video 4

やはり quote が母数も多いし、数が多かったです。上位結果は以下のようになりました。

quote:

post_url date note_count
http://reblog.kondoumh.com/post/116903557247 2015-04-20 2072
http://reblog.kondoumh.com/post/128707132367 2015-09-09 901
http://reblog.kondoumh.com/post/101674369492 2014-11-03 797
http://reblog.kondoumh.com/post/100990796202 2014-10-26 567
http://reblog.kondoumh.com/post/125576816117 2015-08-01 337
http://reblog.kondoumh.com/post/113365328582 2015-03-11 304
http://reblog.kondoumh.com/post/92392064267 2014-07-21 224
http://reblog.kondoumh.com/post/78287627384 2014-03-02 209
http://reblog.kondoumh.com/post/59828448393 2013-08-31 168
http://reblog.kondoumh.com/post/86791028732 2014-05-25 112
http://reblog.kondoumh.com/post/39637473249 2013-01-04 101

photo:

post_url date note_count
http://reblog.kondoumh.com/post/126011762237 2015-08-06 110
http://reblog.kondoumh.com/post/105334116637 2014-12-16 107
http://reblog.kondoumh.com/post/165475223402 2017-09-18 74
http://reblog.kondoumh.com/post/62335157286 2013-09-26 74
http://reblog.kondoumh.com/post/153985233752 2016-12-03 71
http://reblog.kondoumh.com/post/62874741172 2013-10-02 61
http://reblog.kondoumh.com/post/119751530162 2015-05-24 59
http://reblog.kondoumh.com/post/96782854287 2014-09-06 56

photo は天体ものが多い感じでした。

(5/6 追記)

ブラウザで動かしてたのを Node.js の CLI コマンドにしました。 最初 6700件ほどの処理を async await で同期的に書いたら、約20分かかりました。やはりある程度同時実行しないと時間かかります。定期実行して集計値のページ生成するなどの用途などでは AWS Lambda のようなサーバーレス構成には載せられない処理時間です。

ということで、フェッチ処理を並列化して、Promise.all() で待ち合わせるようにしたところ、15秒前後になりました。20件ずつなので、最大30多重ぐらいいく可能性があります。Tumblr API これぐらいなら平気で結果返してくれました。

github.com

*1:Twitter でもほぼ RTer と化していますが。

*2:投稿の 'author' が使えればいいのですがなぜか取れないので API Document には載ってない非公式な方法でしのぎました。