2010年5月16日日曜日

OAuthを使ってAndroidからPythonでTwitterに投稿する

このブログ記事をはてなブックマークに追加

以前、ASE (Android Scripting Environment)を使って「AndroidからPythonでTwitterに投稿する」という記事を書いたが、来月末にTwitterのBASIC認証が廃止されるので使えなくなる。そこで、OAuthを利用するコードに書き直してみた。最近はAndroidのtwiccaがとても使いやすいのでPythonスクリプトによるTwitterへの投稿もあまりないかもしれないが、Android端末単体でOAuthを利用したTwitterの認証ができることを示す意味でも公開することにした。

まず、「コマンドラインで動作するOAuth対応TwitterクライアントをPythonで作ってみた」という記事で用意したoauth.pyとoauthtwitter.pyをAndroid機の/sdcard/ase/scripts/ディレクトリにコピーする。これはadb pushでコピーしてもいいし、SDカードに直接コピーしてもいい。oauthtwitter.pyは一部修正してあるので上述記事の該当箇所を参照して書き直して欲しい。

次に、それらのライブラリを利用して以下のようなコードを書いた。赤字で示した認証コードの部分はTwitterのサイトのOAuthクライアント登録で取得する必要がある。

tw_oauth_ase.py

#!/usr/bin/env python # -*- coding: utf-8 -*- import os, pickle, time, android from oauthtwitter import * CONSUMER_KEY = "CONSUMER_KEY" CONSUMER_SECRET = "CONSUMER_SECRET" KEY_FILE = "/sdcard/ase/scripts/twitter_key.dat" droid = android.Android() def twitter(): if os.path.isfile(KEY_FILE): access_token = pickle.load(file(KEY_FILE)) else: tw = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET) request_token = tw.getRequestToken() authorization_url = tw.getAuthorizationURL(request_token) droid.view(authorization_url) tw = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, request_token) time.sleep(60) oauth_verifier = droid.getInput(u"What is the PIN?", u"暗証番号を入力してください")["result"].strip() access_token = tw.getAccessTokenWithPin(oauth_verifier) pickle.dump(access_token, file(KEY_FILE, "w")) return OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, access_token) def main(): tw = twitter() post = droid.getInput(u"Tweet", u"いまどうしてる?")["result"].strip() if post: tw.PostUpdate(post.encode("utf-8")) droid.makeToast(post) if __name__ == "__main__": main()

使い方は以下の通り。一番最初の起動時だけOAuthによる認証をする必要がある。

まずはASEを起動して以下の画面で先に示したtw_oauth_ase.pyを実行する。


実行させると以下のようにブラウザが起動してTwitterのOAuth認証画面が表示される。


「許可する」を選ぶと以下の画面が表示される。


表示された暗証番号をメニューボタンから「テキストを選択してコピー」を選び、番号をコピーする。ここまでの作業を一分以内に完了させる必要がある。ただし、tw_oauth_ase.pyのtime.sleep(60)の数値(秒)を設定することで完了させるまでの時間を変更することができる。


一分後に以下のダイアログボックスが表示されるので、クリップボードにコピーした暗証番号を入力する。クリップボードから入力するにはテキストエリアを長押しすれば良い。


認証作業が完了すると以下のメッセージ入力ダイアログボックスが表示される。


入力したメッセージがAndroid画面に表示され、Twitterに投稿される。次以降の起動時には最初から上記のダイアログボックスが表示され、認証作業の必要はない。

追記(2010/5/16):

twitter.pyは日本語だと140文字の半分ほどでツイートできなくなってしまうので、文字コードをutf-8、len(status)len(status.decode("utf-8"))に変更してバイトコンパイル、Android端末の/sdcard/ase/extras/にコピーして使っている。

続きを読む...

2010年5月12日水曜日

C++0xでYコンビネータ

このブログ記事をはてなブックマークに追加

stackoverflow.comFixed point combinators in C++ (C++による不動点結合子)に載っていたC++とboostで書かれたYコンビネータ(Y combinator)のサンプルコードをC++0xを使って書き直してみた。C++0xだと標準ライブラリだけでこれだけ簡潔に書ける。

#include <iostream> #include <functional> using namespace std; // Y-combinator for the int type function<int(int)> y(function<int(function<int(int)>, int)> f) { return bind(f, bind(&y, f), placeholders::_1); } int main() { // Y-combinator compatible factorial auto fact = [](function<int(int)> f, int v){ return v == 0 ? 1 : v * f(v - 1); }; auto factorial = y(fact); cout << factorial(5) << endl; return 0; }

続きを読む...

2010年5月6日木曜日

一行でテキストに含まれるURLをすべて短縮URLに変換するPythonスクリプト

このブログ記事をはてなブックマークに追加

テキストに含まれるURLをすべてbit.lyの短縮URLに変換するPythonワンライナーを書いた。使用しているモジュールはre、urllib、urllib2、simplejson。コードに一行追加するだけだし、Twitterなどのメッセージを処理するのに便利だと思う。

for link in sorted(re.findall(r"(http(?:s?)\:\/\/(?!bit\.ly[\/\ ])[^\/\ ]+\/?.*?)(?:[\ <>\"\{\}\|\\\^\[\]\`]|$)", msg), reverse=True): msg = (lambda x: re.sub(re.escape(x), (lambda y: str(simplejson.loads(urllib2.urlopen("http://api.bit.ly/shorten?version=2.0.1&longUrl=%s&login=BITLY_ID&apiKey=BITLY_API_KEY" % urllib.quote(y)).read())["results"][y]["shortUrl"]))(x), msg))(link)

bit.lyのAPIキーは別途取得しておく必要がある。

msg = u"ここのブログのURLはhttp://handasse.blogspot.com/ です。記事のURLはhttp://handasse.blogspot.com/2010/05/urlurlpython.html です。"

としてURLを含むメッセージを処理すると以下のように変換される。

print msg ここのブログのURLはhttp://bit.ly/PQa9F です。記事のURLはhttp://bit.ly/cVRVu6 です。

上記のコードを展開したものが以下のコード。簡単なエラー処理を追加してある。

def bitly(x): try: data = urllib2.urlopen("http://api.bit.ly/shorten?version=2.0.1&longUrl=%s&login=BITLY_ID&apiKey=BITLY_API_KEY" % urllib.quote(x)).read() return str(simplejson.loads(data)["results"][x]["shortUrl"]) except: return x replace_url = lambda x: re.sub(re.escape(x), bitly(x), msg) links = sorted(re.findall(r"(http(?:s?)\:\/\/(?!bit\.ly[\/\ ])[^\/\ ]+\/?.*?)(?:[\ <>\"\{\}\|\\\^\[\]\`]|$)", msg), reverse=True) for link in links: msg = replace_url(link)

続きを読む...

2010年5月2日日曜日

コマンドラインで動作するOAuth対応TwitterクライアントをPythonで作ってみた

このブログ記事をはてなブックマークに追加

6月末にTwitter APIのBASIC認証が終了してしまうので、OAuth対応のTwitterクライアントを作ってみることにした。とりあえず最もシンプルだと思われるコマンドラインで動作するクライアントをPythonで作成してみた。

まず、Twitterクライアントを作成する前に、TwitterのサイトでOAuthクライアントの登録を行わなくてはならない。ここで、「アプリケーーション名」、「アプリケーションの説明」、「アプリケーションのウェブサイトURL」を記入する必要がある。また、今回はPC上で実行するクライアントで読み書きを行いたかったので、「あなたの招待状」には「送信」、"Default Accdess type"には"Read & Write"を選択した。

登録を済ますと、"Application Details"のページで"Consumer key"と"Consumer secret"が与えられるので、これを作成するアプリケーションで利用する(CONSUMER_KEY, CONSUMER_SECRET)。

次にコーディングだが、できるだけ短くシンプルに作りたかったので、Python外部モジュールのtwitteroauthoauthtwitterを利用させてもらうことにした。ただ、作者のページのコードでは途中でエラーになってしまうので、 oauthtwitter.pyのOAuthApiクラスのgetAccessTokenメソッドの下に以下のgetAccessTokenWithPinメソッドを追加した。

def getAccessTokenWithPin(self, pin, url=ACCESS_TOKEN_URL): token = self._FetchUrl(url, parameters={"oauth_verifier": pin}, no_cache=True) return oauth.OAuthToken.from_string(token)

今回作成したTwitterクライアントの使い方だが、

tw.py

で最新のタイムラインを表示する。取得件数はここでは20件にしているが、ソースコード中の引数で変更することができる。Twitterへの投稿は以下のようにすれば良い。

tw.py "つぶやき"

最初の起動時に、アクセストークンを取得するための認証URLが表示される。それをブラウザで開いて表示された認証番号(PIN)を入力する必要がある。取得したアクセストークンは指定されたファイル(KEY_FILE)に保存され、次回以降はそのファイルからアクセストークンを取得する。

ソースコードを以下に示す。

tw.py

#!/usr/bin/env python # -*- coding: utf-8 -*- import sys, os, pickle from oauthtwitter import * CONSUMER_KEY = "CONSUMER_KEY" CONSUMER_SECRET = "CONSUMER_SECRET" KEY_FILE = "twitter_key.dat" def twitter(): if os.path.isfile(KEY_FILE): access_token = pickle.load(file(KEY_FILE)) else: tw = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET) request_token = tw.getRequestToken() authorization_url = tw.getAuthorizationURL(request_token) print authorization_url tw = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, request_token) oauth_verifier = raw_input("What is the PIN? ") access_token = tw.getAccessTokenWithPin(oauth_verifier) pickle.dump(access_token, file(KEY_FILE, "w")) return OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, access_token) def main(args): tw = twitter() if len(args) < 2: for status in tw.GetFriendsTimeline(count=20): print status.GetUser().GetScreenName() + ":", status.GetText().encode("cp932", "replace") else: post = " ".join(args[1:]) tw.PostUpdate(post.decode("cp932").encode("utf-8")) if __name__ == "__main__": main(sys.argv)

続きを読む...