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

TwitterからTwitterAPIを使わずにスクレイピングしてみる

自分はまだTwitterのアカウントを持ってませんが、Twitterから情報を取り出してみたくなったので前時代的な方法でやってみた。
Google App Engine(Python)を使ってみました。
html解析はBeautifulSoupというライブラリを使うと便利なのですが、色々と面倒なので今回は正規表現で無理やり抽出しました。
これくらいはJavascriptだけでも出来そうですが、Googleの有り余る資源を有効活用させてもらうということで・・・。

サンプルURL

http://voidy21.appspot.com/twit_status 以下にあります!

使い方

GETメソッドで

  • callback : コールバック関数名
  • twitter_id : twitterのアカウント名
  • status_num: 発言のステータスid

を指定する
例えばhttp://twitter.com/zenra_bot/status/3605531004なら

http://voidy21.appspot.com/twit_status?callback=hogehoge&twitter_id=zenra_bot&status_num=3605531004

と指定します。
結果はJSON(P)で返ってきます。

  • date : アバウトな日付
  • entry : 発言
  • image : プロファイル画像のURL

何に使えるのか?

そんなに使い道は無いです/(^o^)\
自分はAjax用(JSONP)に使いました
下の画像のような感じで(掲示板にTwitterのアドレスが貼られた場合)非同期でTwitterから情報を取得できます!
あと地味に皆さんのプロファイル画像のファイル名が取得できる点も思わぬ利点・・・!
f:id:voidy21:20090829030647p:image

サーバ側のソース(Google App Engine / Python)

# -*- coding: utf-8 -*-
import wsgiref.handlers
import cgi
import re
import urllib2
from django.utils import simplejson
from google.appengine.ext import webapp
from google.appengine.api import urlfetch

class GetTwitterStatus(webapp.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'application/json'
    self.response.headers['charset'] = 'UTF-8'

    callback = cgi.escape(self.request.get('callback'))
    twitter_id = cgi.escape(self.request.get('twitter_id'))
    status_num = cgi.escape(self.request.get('status_num'))
    url = "http://twitter.com/%s/status/%s" % (twitter_id, status_num)
    html = urlfetch.fetch(url).content
    entry = self.getTwitterEntry(html, twitter_id)
    self.response.out.write("%s(%s)" % (callback,
        simplejson.dumps(entry, ensure_ascii=False)))

  def getTwitterEntry(self, html, twitter_id):
    parser_entry = re.compile("""<span class="entry-content">(.*?)</span>""",re.S)   #20090831追加:改行を正規表現でも文字列とみなすようにしないとダメ
    parser_date = re.compile("""<span class="published">(.*?)</span>""")
    parser_image = re.compile("""<a href="http://twitter.com/%s" class=".*" hreflang=".*">"""
        """<img alt=".*" .* src="(.*)" style=".*" .*></a>""" % twitter_id )
    entry = self.encodeURI(parser_entry.search(html).group(1))
    date = self.encodeURI(parser_date.search(html).group(1))
    image = self.encodeURI(parser_image.search(html).group(1))
    return {
        "entry":entry,
        "date":date,
        "image":image,
    }

  def encodeURI(self, url_string):    #JavascriptのdecodeURIと対応が取れる形
    return urllib2.quote(url_string, safe='!#$&\'()*+,-./:;=?@_~')

application = webapp.WSGIApplication([
  ('/twit_status', GetTwitterStatus),
], debug=False)

def main():
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
  main()

わかったこと

  • non-greedy 指定子というのがあって、*?とか書くと最短の正規表現だけにマッチ出来るようになるらしい
  • _multiprocessingが無いとか言われて動かなかったのでhttp://d.hatena.ne.jp/tmatsuu/20090818/1250606215を参考に(SDK)/google/appengine/tools/dev_appserver.pyに_multiprocessingを追加すると動くようになりました。感謝です!
  • Twitterアカウントは持っていた方がマッシュアップしやすいと思います!