unoh.github.com

Pythonで携帯の機種判別をする

Tue Aug 14 03:12:02 -0700 2007

こんにちは、chihiroです。今回はPythonでモバイルサイトを開発する場合に便利なライブラリ、WSGIUserAgentMobileを紹介します。これはUserAgentからキャリアや端末情報を取得するためのライブラリです。

Google Code WSGIUserAgentMobile
http://code.google.com/p/wsgiuseragentmobile/

これは基本的にはPHPのPEAR::Net_UserAgent_Mobile、さらに元を辿ればPerlのHTTP-MobileAgentを、僕がPythonに移植したものですが、いくつか独自のメソッドやプロパティを追加しています。インストールから、基本的な使い方、Djangoで使用する場合の例をご紹介します。

インストール

諸般の事情によりまだPython Package Indexに登録していないので、開発レポジトリから直接インストールして下さい。

レポジトリからチェックアウトしてからインストールする場合、次のようにします。

$ svn checkout http://wsgiuseragentmobile.googlecode.com/svn/trunk/ uamobile
$ cd uamobile
$ python setup.py install

または、easy_installを使って直接レポジトリからインストールすることもできます。

$ easy_install http://wsgiuseragentmobile.googlecode.com/svn/trunk/

簡単な使い方

デバイスの判定を行うには、uamobileモジュールのdetect関数を使います。detectに与える引数は辞書型オブジェクトです。

>>> from uamobile import detect
>>> detect({'HTTP_USER_AGENT':'KDDI-SA31 UP.Browser/6.2.0.6.3.129 (GUI) MMP/2.0'})
<EZwebUserAgent "KDDI-SA31 UP.Browser/6.2.0.6.3.129 (GUI) MMP/2.0">

detect関数には、少なくともHTTP_USER_AGENTというキーと値だけは与えなくてはなりません。さもないと、当然ながらUserAgentの判定ができないので、detect関数はNonMobileオブジェクトを返します。

>>> detect({})
<NonMobileUserAgent "">

よく使うメソッド・プロパティ

carrier, short_carrierでキャリア名、キャリア名の頭文字を取得できます。

>>> dev = detect({'HTTP_USER_AGENT':'KDDI-SA31 UP.Browser/6.2.0.6.3.129 (GUI) MMP/2.0'})
>>> dev.carrier
'EZweb'
>>> dev.short_carrier
'E'

PHP版、Perl版との違いとしては、ライブラリ内部での用語・表現に、VodafoneではなくSoftBank、AirHではなくWILLCOMという語を使用している点があります。

>>> dev = detect({'HTTP_USER_AGENT':'Vodafone/1.0/V904SH/SHJ003 Browser/VF-NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1'})
>>> dev.carrier
'SoftBank'
>>> dev.short_carrier
'S'
>>> dev = detect({'HTTP_USER_AGENT':'Mozilla/3.0(WILLCOM;SANYO/WX310SA/2;1/1/C128) NetFront/3.3'})
<WillcomUserAgent "Mozilla/3.0(WILLCOM;SANYO/WX310SA/2;1/1/C128) NetFront/3.3">
>>> dev.carrier
'WILLCOM'
>>> dev.short_carrier
'W'

キャリアを判定するメソッドとして、is_docomo(), is_ezweb(), is_softbank(), is_willcom(), is_nonmobile()があります。それぞれ、DoCoMo端末、au端末、SoftBank端末、WILLCOM端末、それ以外のときにTrueを返します。

>>> dev = u.detect({'HTTP_USER_AGENT':'DoCoMo/2.0 N904i(c100;TB;W30H20)'})
>>> dev.is_docomo()
True
>>> dev.is_ezweb()
False
>>> dev.is_softbank()
False
>>> dev.is_willcom()
False
>>> dev.is_nonmobile()
False
>>>

serialnumberプロパティから、DoCoMo端末ならばFOMA製造番号、au端末ならばサブスクライバID、SoftBank端末ならば製造番号を取得できます。

>>> dev = detect({'HTTP_USER_AGENT':'DoCoMo/2.0 N904i(c100;TB;W30H20;ser333333333333333;icc8888888888888888888F)'})
>>> dev.is_docomo()
True
>>> dev.serialnumber
'333333333333333'
>>> dev = detect({'HTTP_USER_AGENT':'Vodafone/1.0/V904SH/SHJ003/SN333333333333333 Browser/VF-NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1'})
/CLDC-1.1">
>>> dev.serialnumber
333333333333333

SoftBankだけの特殊なプロパティとしてjphone_uidがあります。これはSoftBank利用者が通知設定を有効にしている場合(My SoftBank⇒各種変更手続き⇒ユーザID通知設定)に、コンテンツ提供者に通知される端末毎に一意なIDです。実際のjphone_uidは英数字(a-zA-Z0-9)からなる16桁の文字列です。

>>> dev = detect({'HTTP_USER_AGENT': 'Vodafone/1.0/V904SH/SHJ003 Browser/VF-NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1',
                 'HTTP_X_JPHONE_UID': 'xxxxxxxxxxxxxxxx' })
>>>dev.jphone_uid
'xxxxxxxxxxxxxxxx'

displayプロパティでDisplayオブジェクトを取得できます。これは端末の画面サイズにあわせて表示するコンテンツを変える場合に便利です。

>>> dev = u.detect({'HTTP_USER_AGENT':'DoCoMo/2.0 N904i(c100;TB;W30H20)'})
>>> dev.display.width
240
>>> dev.display.height
352
>>> dev.display.color
1
>>> dev.display.depth
262144

端末がCookieを利用かどうかを調べるには、supports_cookie()メソッドを使います。

>>> docomo = u.detect({'HTTP_USER_AGENT':'DoCoMo/2.0 N904i(c100;TB;W30H20)'})
>>> docomo.supports_cookie()
False
>>> au = detect({'HTTP_USER_AGENT':'KDDI-SA31 UP.Browser/6.2.0.6.3.129 (GUI) MMP/2.0'})
>>> au.supports_cookie()
True
>>> sb = detect({'HTTP_USER_AGENT':'Vodafone/1.0/V904SH/SHJ003 Browser/VF-NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1'})
>>> sb.supports_cookie()
True

応用編・Djangoで使う

Djangoで使用する場合、Middleware層に端末判定処理を追加するとよいでしょう。例えば、myprojectというプロジェクトのmyappというアプリケーションにmiddleware.pyとして、次のようなMiddlewareを用意します。

# myproject/myapp/middleware.py
from uamobile import detect, exceptions

class UserAgentMobileMiddleware(object):
    def process_request(self, request):
        try:
            request.device = detect(request.META)
        except exceptions.NoMatchingError, e:
            raise

判定に失敗した場合、NoMatchingErrorが発生します。上記のMiddlewareでは、たんに、例外を再度raiseしているだけですが、本来ならば、非モバイルブラウザとしてそのまま処理を続行するか、あるいは、エラー画面を表示するといった対応が必要でしょう。

このMiddlewareを有効にするために、settings.pyのMIDDLEWARE_CLASSESにこのクラスを追記します。

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    # 追加
    'myproject.myapp.middleware.UserAgentMobileMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.doc.XViewMiddleware',
)

後はビューやテンプレートから"request.device"のようにしてUserAgentサブクラスのインスタンスにアクセスできます。

Djangoで本格的なモバイルサイトを構築する場合には、Cookieが使えない端末のセッションIDの処理といったモバイルサイトならではの対応が必要とされますが、そのあたりのノウハウはまた機会を改めて紹介したいと思います。

まとめにかえて

このWSGIUserAgentMobileは僕が開発を担当しているgumiでも使用しています。興味がある方は、是非、携帯でhttp://gu3.jp/にアクセスしてみて下さい。

また、このライブラリはまだベータ版なのですが、バグの報告や何かご質問がありましたら、コメントやトラックバックでお知らせいただくか、下記メールアドレスに直接ご連絡いただければ幸いです。

>>> 'Y2hpaGlyb19zYWthdG9rdUB1bm9oLm5ldA=='.decode('base64')