読者です 読者をやめる 読者になる 読者になる

kivantium活動日記

プログラムを使っていろいろやります

PythonからGNU Socialを使う

先日Twitterに障害が発生した際に「Twitterが落ちてつぶやけない」というつぶやきができなくて非常に苦しい思いをしました。
また、Twitter社の収益が怪しく買収交渉も失敗したという噂も流れています。
なんにせよTwitterがなくてもつぶやきを続行できる代替サービスが必要です。

現在有力な代替サービスだと思っているのはGNU Socialです。
開発元がGNUなのでもちろんソースが公開されているため自分でサーバーを立てることもできますが、既存のサーバーにアカウントを作る方が簡単です。

サーバーにはいろいろあるようですが、見た範囲で有力そうなのは

でした。

サーバーが違ってもフォローはできますが、若干手順が面倒なので見たい人がいるサーバーを選ぶといいでしょう。
kivantiumを含め、僕の周囲の日本人はなぜかFreezePeachに集まっています。

UIはほとんどTwitterと変わらず、ブラウザから使う分には少し重いと感じるくらいで使用感は同じなのですが、致命的なことにまともなクライアントソフトが存在しません。
無いなら作るのが活動日記の基本姿勢なのでやっていこうと思います。

TwidereというAndroidアプリが対応しているようです。ログイン画面で右上に表示されるAPIを編集のアイコンをタップし、URL形式にhttps://freezepeach.xyz/api/を指定して認証タイプをBasicにすればTwitterと同じように使えました。
その他のクライアント情報


必要な情報を取得して、PythonからHello, worldするところまで書いたので記録しておきます。

追記:
pygnusocialというライブラリがあるそうです

未検証ですが、これを使えばもっと簡単にGNU Socialを使えそうです。

GNU SocialのAPI

APIのドキュメントはhttps://freezepeach.xyz/doc/apiにあります。
(簡単のため例は全てFreezePeachの場合を書きますが、他のサーバーでもドメインだけ書き換えれば同様のはずです。)

AtomPubとTwitter-compatible APIの2種類があるようですが、いままでの経験があって使い慣れているTwitter-compatible APIを使うことにします。

アプリの登録

アプリのOAuth認証に使うConsumer keyとConsumer secretが必要なのでアプリを登録します。
登録にはそのサーバーのアカウントが必要です。

登録はhttps://freezepeach.xyz/settings/oauthappsにあるRegister a new applicationから行えます。
Type of applicationはDesktop、Default access for this applicationはread-writeにします。

登録が終わったら作成したアプリのページに行くとConsumer keyとConsumer secretを取得できます。
f:id:kivantium:20161110150837p:plain:w600

Access TokenとAccess Token Secretの取得

アプリを動かすためにはConsumer key, Consumer secretのほかにAccess TokenとAccess Token Secretが必要です。
Pythonから取得する方法を示します。

必要なライブラリのインストール

sudo pip install requests_oauthlib

コード(参考: OAuth 1 Workflow — Requests-OAuthlib 0.7.0 documentation

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

import requests
from requests_oauthlib import OAuth1Session
from requests_oauthlib import OAuth1
from urlparse import parse_qs

# アプリのページから取得したkey, secretを入力
client_key    = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

request_token_url = 'https://freezepeach.xyz/api/oauth/request_token'
authorization_url = 'https://freezepeach.xyz/api/oauth/authorize'
access_token_url = 'https://freezepeach.xyz/api/oauth/access_token'

oauth = OAuth1Session(client_key, client_secret, callback_uri='oob')
fetch_response = oauth.fetch_request_token(request_token_url)
resource_owner_key = fetch_response.get('oauth_token')
resource_owner_secret = fetch_response.get('oauth_token_secret')
authorization_url = oauth.authorization_url(authorization_url)

print authorization_url

verifier = raw_input('PIN: ')
oauth = OAuth1(client_key,
               client_secret=client_secret,
               resource_owner_key=resource_owner_key,
               resource_owner_secret=resource_owner_secret,
               verifier=verifier)
r = requests.post(url=access_token_url, auth=oauth)
credentials = parse_qs(r.content)
access_token = credentials.get('oauth_token')[0]
access_token_secret = credentials.get('oauth_token_secret')[0]
print "Access Token:", access_token
print "Access Token Secret:", access_token_secret

このコードを端末から実行するとhttps://freezepeach.xyz/api/oauth/authorize?oauth_token=xxxxxのようなURLが表示されるので、そのURLにブラウザからアクセスします。
f:id:kivantium:20161110151817p:plain:w600

ALLOWを押すとPINコードが表示されます。

f:id:kivantium:20161110151853p:plain:w600

PythonのプロンプトにこのPINを入力するとAccess TokenとAccess Token Secretが表示されます。

Hello, world!

ここまでで得た情報を使ってHello, world!するコードは以下の通りです(参考: Python で Twitter API にアクセス - Qiita

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

from requests_oauthlib import OAuth1Session

consumer_key        = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
consumer_secret     = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
access_token        = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
access_token_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

# ツイート投稿用のURL
url = "https://freezepeach.xyz/api/statuses/update.json"

# ツイート本文
params = {"status": "Hello, World!"}

# OAuth認証で POST method で投稿
twitter = OAuth1Session(consumer_key, consumer_secret, access_token, access_token_secret)
req = twitter.post(url, params = params)

# レスポンスを確認
if req.status_code == 200:
    print ("OK")
else:
    print ("Error: %d" % req.status_code)

APITwitter互換なので他のAPIも参考ページと同じように動きます。