Python
api
python2.7
mastodon
マストドン

pythonからMastodon APIを使ってフォロワー・フォローを取得する方法

はじめに

マストドンの管理ツール「MASTMAN(マストマン)」を開発してるときにミスったAPIの使い方を紹介します。

Docs

APIの使い方は、以下のように割とシンプルな感じ(のはずだった...)

GET /api/v1/accounts/:id/followers

Query parameters:
max_id : Get a list of followers with ID less than this value
since_id : Get a list of followers with ID greater than this value
limit : Maximum number of followers to get (Default 40, Max 80)

参考:Getting an account's followers

僕のフォロワー数

da7e85c5357d395b78c6a383b770be3b.png

41件です!

ダメなフォロワーの取得

以下のコードはフォロワーIDの最初の10件を取得して、その中から一番小さいIDを取得して次にそのIDよりも小さい10件をとっての繰り返しを行っている。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import urllib2
import urllib
import json
import re

access_token = 'xxxxx'

def get_followers(user_id, max_id=None):
    # デフォルトのlimitは40だけど、失敗例がわかりやすいので今回は10で!
    limit_num = 10
    url = "https://mstdn.jp/api/v1/accounts/%d/followers" %(user_id)

    param = []
    param.append(('limit', limit_num))
    if max_id:
        param.append(('max_id', max_id))
    url += "?" + urllib.urlencode( param )

    request = urllib2.Request(url)
    auth_header = 'Bearer %s' %(access_token)
    request.add_header('Authorization', auth_header)
    res = urllib2.urlopen(request)
    res_list = json.loads(res.read())

    # 結果がlimit_num(今回は10件)だったら次の10件を取得...
    if len(res_list) == limit_num:
        next_max_id = min(map(lambda x: x.get('id'), res_list))
        res_list.extend(get_followers(user_id, max_id=next_max_id))
    return res_list

def main():
    # toitechのID
    my_user_id = 96368
    res = get_followers(my_user_id)
    # 結果のアイテム数
    print len(res)
    # 結果のユニークなID数
    print len(set(map(lambda x: x.get('id'), res)))


if __name__ == '__main__':
    main()

これを実行すると、、、なんと10件しかとれない!!!

$ python get_follower.py
10
10

正しいフォロワーの取得

もう一度、Docsをちゃんと見てみると以下のような注意書きが...

Note: max_id and since_id for next and previous pages are provided in the Link header. It is not possible to use the id of the returned objects to construct your own URLs, because the results are sorted by an internal key.

帰ってきた結果のIDをsince_idとかmax_idとかに指定するのは違うらしい。
headerを見ろと。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import urllib2
import urllib
import json
import re

access_token = 'xxxxx'

def get_followers(user_id, max_id=None):
    # デフォルトのlimitは40だけど、失敗例がわかりやすいので今回は10で!
    limit_num = 10
    url = "https://mstdn.jp/api/v1/accounts/%d/followers" %(user_id)

    param = []
    param.append(('limit', limit_num))
    if max_id:
        param.append(('max_id', max_id))
    url += "?" + urllib.urlencode( param )

    request = urllib2.Request(url)
    auth_header = 'Bearer %s' %(access_token)
    request.add_header('Authorization', auth_header)
    res = urllib2.urlopen(request)
    res_list = json.loads(res.read())

    # 結果がlimit_num(今回は10件)だったら次の10件を取得...
    if len(res_list) == limit_num:
        link_str = res.info().getheaders("link")[0]
        next_max_id = re.search("max_id=(\d+)>", link_str).group(1)
        res_list.extend(get_followers(user_id, max_id=next_max_id))
    return res_list


def main():
    # toitechのID
    my_user_id = 96368
    res = get_followers(my_user_id)
    # 結果のアイテム数
    print len(res)
    # 結果のユニークなID数
    print len(set(map(lambda x: x.get('id'), res)))


if __name__ == '__main__':
    main()

これを実行すると...ちゃんと41件になっている!めでたしめでたし。

$ python get_follower.py
41
41

まとめ

忙しくてもドキュメントはちゃんと読もう

いいわけ

以下のようなstatus(トゥート)の取得は、前者(ダメなフォロワーの取得)と同じやり方でもいける!トゥートは新しいものほどトゥートIDが大きいが、フォロワーは最近フォローされた人ほどユーザーIDが大きいとは限らないからそうなってるんでしょうね。

GET /api/v1/accounts/:id/statuses

宣伝

マストドンの管理ツール「MASTMAN(マストマン)」絶賛開発中、みんなも使ってみてね!