Pythonでmixiのプロフィール画像を変更する

あけましておめでとうございます。
早起きしてPython書き初めしたのでご報告です。


今年はmixiプロフィール画像を日ごとに変更したいと思った。mixiはプロフィール用画像を複数設定できて、その中から一枚をメインの画像にする。APIとか分からないので mechanize でやれば良いやって思ったのだけど、やってみたら少しハマったのでメモ。

とりあえず成果物

https://gist.github.com/1545546


使い方

    print "login"
    m = MixiProfileImage( EMAIL_ADDRESS, PASSWORD )
    
    print "delete current profile image"
    images = m.filter(level="1")
    for k, v in images.iteritems():
        m.delete(v)

    print "add new profile image"
    image = m.add( FILE_PATH , level="1", is_main="y")

他には 公開範囲、メイン画像どうかの 変更 と 絞り込み ができる。
mechanize なので mixi の仕様が変わったら使えなくなる。 

日替わりプロフィールに使える画像たち(参考)

http://www.mcdonalds.co.jp/menu/regular/index.html
http://www.akindo-sushiro.co.jp/menu/item.php
http://www.abysse.co.jp/world/flag/index.html
http://hanshintigers.jp/data/player/2012/index.html#pitcher

同じカテゴリーの画像だと日替わりアイコンにしても混乱させないはず。

仕組み

mechanizeで操作している。


画像の追加はファイルをPOSTで送信するだけなので簡単。

# self.client = mechanize.Browser()
self.client.select_form(nr=0)
self.client["level"] = [level]
    
self.client.add_file(open(path), "image/jpeg", path)
self.client.set_all_readonly(False)
self.client.submit()


画像の削除でハマった。
実際にブラウザで操作すると分かるのだけど、マウスでの操作が何段階かある。それらはJavaScriptで制御されていて最終的にajaxでリクエストを投げている(動きから判断した)。なので、mechanizeでその操作をそっくりなぞってみようとしたら、mechanizeはJavaScriptの動作は再現されない。そこで最終的に投げられるajaxのリクエストを調べて真似た。


以下やったこと

  • chrome developer tools を開く(Control+Alt+i)

使い方はこの記事が参考になる

Google ChromeJavaScriptデバッガの進化がすごい - 0xFF
http://d.hatena.ne.jp/os0x/20110422/1303468821

  • Scriptsタグの XHR Breakpoints の Any XHR のチェックを ON
  • 画像削除の一連の動作を普通にマウスでする
  • protorype-effects-なんとかファイルの途中でブレーク
  • ソースの下部にある{}をクリックすると、933行目で止まっている
this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous);
if (this.options.asynchronous) {
    this.respondToReadyState.bind(this).defer(1)
}
this.transport.onreadystatechange = this.onStateChange.bind(this);
this.setRequestHeaders();
this.body = this.method == "post" ? (this.options.postBody || D) : null;
this.transport.send(this.body); // <- break
  • 上記ソース1行目の this.url に 最終行 this.body を POST で送信しているのが分かる
  • this.url には secret っていうキーみたいなのがある
  • とりあえず普通にHTMLソースを調べると secret っぽいキーがあったのでそれを利用する
RPC_URL = "/system/rpc.json?auth_type=postkey&secret=%s" % secret
params = '{"jsonrpc": "2.0", "method": "jp.mixi.profileimage.deleteEntry", "params": {"image_name": "%s"}, "id": 0}' % image_name

self.client.open(url, params)
  • できた!!!