メインコンテンツ | メニュー

Main Contents

2008年04月06日

日本人の平均余命と死亡率

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

日本人の平均余命と死亡率」というページを公開しました。

年齢と性別を入力すると、

  • 統計的にどれくらいの余命がありそうなのか
  • 将来のある年齢までの死亡率はどれくらいなのか

を表示します。

データは厚生労働省:日本人の平均余命 平成18年簡易生命表から抜粋しています。「平均余命」についてはこの生命表の値をそのまま、特定の年齢までの死亡率については、入力年齢での生存人口=A、将来の年齢での生存人口=Bとして、(A-B)/A で算出しています(これが本当に正しい方法なのかは調べていません)。

試しに自分の場合、30歳・男性では以下のようになります。平均余命はあと50年弱、つまり平均的には80歳近くまで生きられるようですが、75歳になるまでには1/4以上の確率で亡くなってしまうようです。85歳に至っては、生存率のほうが低い、というのが事実のようです。

seimei30.png

これは過去の実績からなる統計値なので、自分(特定の個人)の平均余命や死亡率がこの通りというわけではありません。また、将来の環境変化によっても変わってきます。それでも集団として見たときに、自分や自分と同い年の友人の4人にひとりがあと45年以内に亡くなってしまい、その10年後には今の半数以下になってしまう、という事実にはなかなか厳しいものがあります。

これまでは、自分の人生にあとどれくらいの時間が残されているのかということは考えてこなかったのですが、実際に数字を見て、残りの人生でいったい何ができるのか、何をすべきなのか、正直なところ考えさせられてしまいました。

2008年03月23日

日本語の文章校正支援ツールをリリース

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

Yahoo! Japan が提供する校正支援APIを利用して、文書校正支援ツールを作ってみました。

文章校正支援ツール

「はるか彼方に小形飛行機が見える。」という文を校正してみると、こんな感じになります。

emend_jp.png

ブログ書きのお供にどうでしょうか。

校正すべき箇所と、言い換え候補はYahooの校正支援APIからの情報をそのまま使っているのですが、実際に使ってみるとちょっと苦しいところがあるようです。

たとえば、「遙か」に対して返ってくる「言い換え候補文字列」が「●か」になっているとか、「他の」に対しては「ほかの(「たの」と読む場合は漢字表記可)」が返ってくるとかいうケースです。これらの修正候補をそのまま指摘箇所に埋め込んでしまうと、文章としてはおかしくなってしまいます。「●か」とか「(「たの」と読む場合は漢字表記可)」という部分は本来言いかえ候補の一部ではなく、指摘に関する説明事項なのですが、「本来の言い換え候補」と「説明事項」がごっちゃになって「言い換え候補」として返ってきてしまっているようです。

校正支援APIを提供している意図は、「他のプログラムに校正支援機能を付けられるように」ということだと思うのですが、どこまでが「言い換え候補」なのかよくわからない情報が返ってくる、という状態だと、「言い換え候補を横目で見ながらユーザーにその言い換え候補を手入力させる」というレベルのものしか作れないことになるのではないでしょうか。あるいはそのレベルでしか提供をしない、というのが狙いなのかもしれませんが、改善を希望したいところではあります。

プログラム内部では、校正支援APIを呼び出すために、拙作のPythonライブラリYAPIを使っています。興味があればどうぞ。今回使ったのは、今のところまだ公開していないリビジョン 0.3.1です。これもいずれ公開します。

2008年03月22日

YAPI-0.3 校正支援、ローカルサーチ、トピックスへの対応を追加

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

Yahoo! Japan の Web API を Python から利用するためのライブラリ、YAPI-0.3 をリリースします。

YAPI-0.3 をダウンロード

(YAPI-0.2はこちらから:kh.log - Yahoo! Japan の Webサービス用 Pythonライブラリ

これまでの検索(Web、画像、動画、関連検索ワード)と形態素解析サービスに加えて、新たに校正支援、ローカルサーチ、トピックスへの対応を追加しました。

APIのパラメータ詳細についてはYahoo!デベロッパーネットワークを参照してください。

以下、READMEより:

== YAPI ==

This is a module package to make use of the Web API
provided by Yahoo! Japan Developer Center.

Currently supported API:
  Search (Web, Image, Video, WebUnit)
  MAService
  KouseiService
  Topics
  LocalSearch


== Install ==

python setup.py install


== Synopsis ==

>>> from YAPI import *
>>> APPID='Your Application ID Here.'
>>>
>>> ma = MAService(APPID)
>>> d = ma.call(sentence=u'すもももももももものうち'
                output_coding='utf-8')
>>>
>>> d
<YAPI.Response.MAServiceResponse object at 0x309547f0>
>>>
>>> if not d.is_error:
>>>   for w in
>>>   d.response['ResultSet']['ma_result']['word_list']['word']:
...     print '\t'.join((w['surface'], w['reading'], w['pos']))
...
すもも  すもも  名詞
も      も      助詞
もも    もも    名詞
も      も      助詞
もも    もも    名詞
の      の      助詞
うち    うち    名詞




>>> ks = KouseiService(APPID)
>>> d = o.call(sentence=u'遙か彼方に小形飛行機が見える。',
               output_coding='utf-8')
>>>
>>> for r in d.response['ResultSet']['Result']:
>>>     print '\t'.join([str(r['StartPos']), str(r['Length']), r['Surface'],
...                      r['ShitekiWord'], r['ShitekiInfo']])
...
0       2       遙か    ●か     表外漢字あり
2       2       彼方    彼方(かなた)、かなた  用字
5       5       小形飛行機      小型飛行機      誤変換

2008年03月14日

Pythonで全角半角を正規化する方法

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

インターネット上の日本語を扱っていると、全角半角が統一されていない事による表記揺れをなんとかしたい場面に出くわします。半角で書かれた iPod も、全角で書かれたiPodも同じものとして扱いたいときや、あるいは単に見た目がきれいになるように、英数字は半角に、カタカナは全角にそろえたい、という場合です。

Python では setomitsさんによる zenhan.py を使うと、文字種ごとに全角半角を選択して変換することができ、除外文字も設定できるので便利です。ただ、そこまで柔軟でなくても良く、単に表記揺れがなくなれば良い、という場合も多いかと思います。その場合はPythonの標準ライブラリに含まれる unicodedata モジュールの normalize 関数を使うと便利です。

>>> import unicodedata
>>>
>>> s = 'フガホゲ-%*@ABC−%*@123'.decode('euc-jp')
>>> n = unicodedata.normalize('NFKC', s)
>>>
>>> print s.encode('euc-jp')
フガホゲ-%*@ABC−%*@123
>>>
>>> print n.encode('euc-jp')
フガホゲ-%*@ABC−%*@123

Unicode で定義される各文字は、等価な別表現がある場合(たとえば半角のAと全角のA)に、どの表現を標準とするべきか、という情報が付与されているそうです。normalize関数はこの情報を使って、表記を統一する処理を行います。normalize関数の第一引数に 'NFKC' を渡すことで、ガ(カ+濁点)のような複合文字が期待通りに分解・再合成されます。(詳しく知りたい方は Unicode正規化 あたりをどうぞ)

実際の変換結果を見てみると、英字、数字は半角に、カタカナは全角に正規化されることになっているようです。記号については、基本的に半角のようですが、全角マイナスと半角マイナスのように、別の文字として扱われているものもあるようです。マイナスが半角に正規化されるべきかどうかは場合によって異なると思われますが、ほとんどの用途にはこれで十分なのではないでしょうか。

2008年02月27日

Yahoo! Japan の Webサービス用 Pythonライブラリ

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

Yahoo!デベロッパーネットワーク で公開されているWebサービスの Python バインディングを書いたので公開します。

UPDATED 2008/03/22:
YAPI-0.3 がリリースされています。
kh.log - YAPI-0.3 校正支援、ローカルサーチ、トピックスへの対応を追加

ダウンロード: YAPI-0.2.tar.gz

libxml2-python 2.6.30以上が必須です。

いまのところ、検索系4種と形態素解析の5つのAPIのみの対応です。

XMLをPythonオブジェクトに変換するところで悩んでしまって、ちょっと奇妙な実装になっています。Yahoo!のAPIにはすべて、XML Schemaが用意されているのですが、これをどう生かせば良いのかがわからなかったため、独自のパージング関数を書いてしまいました。興味のある方は中をご覧ください。(そして正しい方法をご連絡ください…)

使用法は以下。

READMEより:

== YAPI ==

This is a module package to make use of the Web API
provided by Yahoo! Japan Developer Center.

Currently supported API:
  Search (Web, Image, Video, WebUnit)
  MAService


== Install ==

python setup.py install


== Synopsis ==

>>> from YAPI import *
>>> APPID='Your Application ID Here.'
>>>
>>> ma = MAService(APPID)
>>> d = ma.call(sentence=u'すもももももももものうち'
                output_coding='utf-8')
>>>
>>> d
<YAPI.Response.MAServiceResponse object at 0x309547f0>
>>>
>>> for w in d.response['ResultSet']['ma_result']['word_list']['word']:
...   print '\t'.join((w['surface'], w['reading'], w['pos']))
...
すもも  すもも  名詞
も      も      助詞
もも    もも    名詞
も      も      助詞
もも    もも    名詞
の      の      助詞
うち    うち    名詞

2007年10月13日

Lightweight Languages AHP

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

Lightweight Languages AHPというのをやってみた。ふだん使っていて、いまやもっとも馴染んでいるPythonよりRubyのほうが若干スコアが高い。実はPythonよりRubyを使いたいと思っているのかも。

細かく見てみるとなかなか興味深い。読み取れるのはこんなところだろうか:

  • RubyはPythonやPerlよりずっと変態性が高いと思っている(そのとおり。)
  • (自分にとっては)PythonのほうがRubyより開発環境と記述性で優れていると思う
  • Ruby/PerlよりもPythonのほうが高速に動くことが多いと思っている(でも実際のところその認識はアヤシイとも思っているし、ほんとうは違いがよくわかっていない。そもそもLLに高速性は求めていない。)
  • Pythonの色気のなさがたまにいやになる
  • もうPerlを大事なところで使おうとは思わない(が、あの変態性はたまに懐かしい)
  • (PHPのことはあまりよく知らないし、知ろうとも思っていない)

実際もう数年すると、Rubyが仕事で使いたい言語になっている可能性はあるかな。

2007年09月20日

Python for 702NK/702NK2プログラミングブック

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

会社からの帰り道、地下鉄のホームで「Python for 702NK/702NK2プログラミングブック」を読みながら歩いている人を見かけました。Pythonの文字と緑色の表紙を手がかりにamazonを検索してタイトルを知ったのですが、なかなかマニアックな本のようです。

こんなものを読みながら歩いている人を見かけるなんて、やはり東京っていろんな人がいるんだなあ、と。

そのとき自分はカバンに入りきらなかった「入門 GNU Emacs 第3版(512ページ)」を手に持っていましたがね。

2007年01月15日

境界を越える日付

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

会社で訊かれたこと。いや、割り込んだことか。日付を1日づつインクリメントして、月の終わりとか、年の終わりとかをきれいに超える簡単な方法。

2006-12-30
2006-12-31
2007-01-01
...
と言うやつね。

python の場合

datetimeを使う。

python
>>> import datetime
>>> d = datetime.date(2006, 12, 25)
>>> d_end = datetime.date(2007, 1, 4)
>>> delta = datetime.timedelta(1)
>>> while True:
...  if d == d_end: break
...  print d.strftime("%Y-%m-%d")
...  d += delta
...
2006-12-25
2006-12-26
2006-12-27
2006-12-28
2006-12-29
2006-12-30
2006-12-31
2007-01-01
2007-01-02
2007-01-03
>>>
shellの場合

こちらはXX日前〜YY日前という指定。

for i in `seq 21 -1 12`; do date --date "$i days ago" +"%Y-%m-%d"; done
2006-12-25
2006-12-26
2006-12-27
2006-12-28
2006-12-29
2006-12-30
2006-12-31
2007-01-01
2007-01-02
2007-01-03

2007年01月10日

osxのpythonでCtrl-Aとか日本語入力とか。

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

setomitsさんがblogSetomits : Mac OS X 上の Python インタプリタとかblogSetomits : あらためて Python 2.4.4あるいはblogSetomits : 続 Mac OS X 上の Python インタプリタで書かれているように、osxのpythonのインタラクティブモードはなんだか動作がヘンです。Emacsキーバインドが効かなかったり、日本語がちゃんと入力できなかったり。

はじめ、readlineをコンパイルしてみたり、python自体をコンパイルしてみたりしたのですが状況はそれほど変わらず。結局、rlwrapをMacPorts(旧DarwinPorts)から導入し、~/.inputrcを設定することで問題が解決しました。

ちなみにrlwrapというのはreadlineラッパーです。これがどんなものかは川o・-・)<2nd life - rlwrap - readline ラッパーで説明されていますので、ご参照ください(手抜き)。自分もここでrlwrapを知りました。

以下、手順。

1.MacPortsのインストール

InstallingMacPorts - MacPorts - Tracに書かれているとおりXcode Toolsをインストールして、環境変数を設定してから、MacPortsの.dmgをインストールすればOK、のはず。自分はDarwinPortsのころにインストールしたのでよくわからん。たぶん同じだけど。

2.rlwrapのインストール

ターミナルから

sudo port install rlwrap

とするだけ。

標準構成ならたぶん /opt/local/bin/rlwrapに入るかな。

3. ~/.inputrcの設定。

意味はわからんけどreadlineさまが機嫌良く動いてくれるように、以下のおまじないを ~/.inputrcに追加。

set convert-meta off
set output-meta on
set input-meta on

4. 実行

以下のような感じ。例ではわからないが、ちゃんとCtrl-AとかCtrl-H とかのEmacsキーバインドが効いている。

% rlwrap python2.4

Python 2.4.4 (#1, Oct 18 2006, 10:34:39) 
[GCC 4.0.1 (Apple Computer, Inc. build 5341)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> u = 'あいうえお'.decode('euc-jp')
>>> len(u)
5
>>> for c in u:
...   print hex(ord(c))
... 
0x3042
0x3044
0x3046
0x3048
0x304a

どうでもいいけど、標準の pytho2.3.5 で decode('euc-jp')とすると、"LookupError: unknown encoding: euc-jp"と怒られてしまう。JapaneseCodecて2.3から標準でなかったっけ?

2006年11月15日

JUMAN Python バインディング (SWIG)

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

形態素解析器JUMANをPythonモジュールとして使うためのバインディングを作りました。

JUMANは-Sオプションをつけて起動すると、サーバーモードで動作します。サーバーモードのJUMANは他のプログラム(たとえばPython)とソケットで通信して、形態素解析の結果を返してくれます。大量の文書を解析するときなどは、ひとつの文書ごとにプロセスを起動するよりも効率がよいのですが、それでもソケット通信の分、速度が落ちてしまいます。

JUMANを、Cで書かれたPythonモジュールとしてラップしてやるバインディングさえ書ければ、このソケット通信の無駄をなくすことができます。

ちょうどSWIGの使いかたを学びたかったこともあって、バインディングを書いてみたのでした。サーバーモードのJUMANとソケット通信するよりは、15〜20%ほど速いようです。

SWIGの定義ファイル作成にあたっては、SWIGオフィシャルや83's : JumanのRubyバインディングを参考にさせていただきました。

モジュールは以下のように使います。

#!/usr/bin/python
# -*- coding: euc-jp -*-
import cJuman

S = [
    '私の名前は中野です。',
    '',
    'これはJUMAN Pythonテストです。',
    ]

cJuman.init(['-B', '-e2'])
print cJuman.parse_opt(S, cJuman.SKIP_NO_RESULT)

結果は以下の通り。

私 わたくし 私 名詞 6 普通名詞 1 * 0 * 0 "漢字読み:訓 代表表記:私"
@ 私 わたし 私 名詞 6 普通名詞 1 * 0 * 0 "代表表記:私"
の の の 助詞 9 接続助詞 3 * 0 * 0 NIL
名前 なまえ 名前 名詞 6 普通名詞 1 * 0 * 0 "代表表記:名前"
は は は 助詞 9 副助詞 2 * 0 * 0 NIL
中野 なかの 中野 名詞 6 人名 5 * 0 * 0 NIL
@ 中野 なかの 中野 名詞 6 地名 4 * 0 * 0 NIL
です です だ 判定詞 4 * 0 判定詞 25 デス列基本形 24 NIL
。 。 。 特殊 1 句点 1 * 0 * 0 NIL
EOS
EOS
これ これ これ 指示詞 7 名詞形態指示詞 1 * 0 * 0 NIL
は は は 助詞 9 副助詞 2 * 0 * 0 NIL
JUMAN JUMAN JUMAN 未定義語 15 その他 1 * 0 * 0 NIL
\  \  \  特殊 1 空白 6 * 0 * 0 NIL
Python Python Python 未定義語 15 その他 1 * 0 * 0 NIL
テスト てすと テスト 名詞 6 サ変名詞 2 * 0 * 0 "代表表記:テスト"
です です だ 判定詞 4 * 0 判定詞 25 デス列基本形 24 NIL
。 。 。 特殊 1 句点 1 * 0 * 0 NIL
EOS

SWIGの定義ファイルはこちら。 [cJuman.i]

これを使って、以下のようにしてモジュールを作成します。

tar xvzf juman-5.1.tar.gz
cd juman-5.1
./configure
make
make install

cd lib
cp ~/cJuman.i .
swig -python cJuman.i
gcc -c cJuman_wrap.c -I/usr/include/python2.4
gcc -shared *.o -o _cJuman.so

ちなみにUbuntuでは CC=/usr/bin/gcc-3.4と、明示的にgccのバージョンを指定しました。

余談。余暇を利用して書いていたのですが、がんばりすぎて体調をくずし、本業を休んでしまいました。本業が忙しかったことに加えて、SWIGでバインディングを書くのが意外と楽しく、睡眠時間を削ってしまったのでした。反省です。

2006年10月30日

Google Co-op で Python Search Engineを作ってみた

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

昨日紹介した Google Co-op の Custom Search Engine 作成機能を使って、Python Search Engineを作ってみました。

まだ、python.org、python.jpのほか、数人のpython使いのブログを登録しただけの状態ですが、python.jpのライブラリリファレンスが簡単に検索できるようになったのは、意外と便利です。

とはいえ、作ってから気づいたのですが、オフィシャルであるpython.orgとpython.jpを除いたら、Python関連サイトをあまり知りません。COREBlogで有名な柴田さんのブログなどを探して登録してみたものの、早くもネタ切れ状態です。

幸い、Custom Search Engine には、Googleアカウントを持っている人同士で共同編集ができる機能があります。Python Search Engineも共同編集(に応募)可能にしてあるので、Python方面でご活躍中の方、Pythonで仕事している方、Pythonに興味ある方、で手伝ってもいいなと思われたら、ぜひご参加ください。Python Search Engineから、"Volunteer to contribute to this search engine." と書かれたリンクをクリックすれば、応募できます(たぶん)。

2006年10月01日

kakaku.com Web API for Python (ElementTree使用版)

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

ついさっきkh.log - kakaku.com Web API for Pythonを書いたところ ですが、ElementTreeという便利なモジュール(python 2.5から標準モジュールになった )を知ったので、書き換えてみました。一応、前のものも残しています。

ElementTreeの使いかたは、perezvonの日記 - Raku APIElementTree Overview ::: www.effbot.orgを参考にさせていただきました。

KakakuComAPIクラス(ElementTree版)をダウンロードする

以下のようなかんじ。だいぶすっきりした。

import urllib, types

try:
    import xml.etree.ElementTree as ET
except ImportError:
    try:
        import cElementTree as ET
    except:
        import elementtree.ElementTree as ET

from xml.dom import minidom

class KakakuComAPI(object):
    API_ENDPOINT = r'http://api.kakaku.com/Ver1/ItemSearch.asp'
    UNMARSHALLERS = {
        'Item': lambda e: dict([(c.tag, c.text) for c in e]),
        'ProductInfo': lambda e: [c.text for c in e if c.tag == 'Item'],
        'Error': lambda e: e[0].text,
        }

    @classmethod
    def search(cls, **args):
        params = cls.__parameterize(args)
        url = cls.API_ENDPOINT + '?' + params
        result = {}
        f = urllib.urlopen(url)
        for event, elem in ET.iterparse(f):
            unmarshal = cls.UNMARSHALLERS.get(elem.tag, lambda e: e.text)
            elem.text = unmarshal(elem)
            if elem.tag in ('ProductInfo', 'Error', 'NumOfResult'):
                result[elem.tag] = elem.text

        f.close()
        result['RequestedUrl'] = url
        return result

    @classmethod
    def __parameterize(cls, args):

        kw = args.get('Keyword')
        arg_enc = args.get('ArgsEncode')
        if type(kw) is types.UnicodeType:
            kw = kw.encode('shift_jis', 'ignore')
        elif arg_enc:
            kw = kw.decode(arg_enc, 'ignore').encode('shift_jis', 'ignore')

        params = []
        params.append("%s=%s" % ('Keyword', urllib.quote(kw)))

        for p in ('ResultSet', 'CategoryGroup', 'SortOrder', 'PageNum'):
            v = args.get(p)
            if v != None:
                params.append("%s=%s" % (p, urllib.quote(v)))

        return '&'.join(params)

以下、使用例。ここは前と同じ。

Keywordに日本語を含む場合はsjisで渡すか、unicodeで渡すか、そうでなければArgsEncodeで明示するかする必要があることに注意。

from kakaku_api import KakakuComAPI

r = KakakuComAPI.search(Keyword="vaio")
r = KakakuComAPI.search(Keyword=u"バイオ")
r = KakakuComAPI.search(Keyword=u"バイオ".encode("shift_jis"))
r = KakakuComAPI.search(Keyword=u"バイオ".encode("euc-jp"), ArgsEncode="euc-jp")
r = KakakuComAPI.search(Keyword="vaio",
                        ResultSet="medium",
                        SortOrder="pricerank",
                        PageNum="4",
                        CategoryGroup="Pc")

結果の形式が前回とはちょっと違っているので注意。商品情報はItemsというキーで格納していたのですが、今回はProductInfoキーで格納してます。


{'ProductInfo': [{'BbsPageUrl': u'http://kakaku.com/bbs/Main.asp?PrdKey=01307211611',
    'CategoryName': u'\u30d1\u30bd\u30b3\u30f3\u5468\u8fba\u6a5f\u5668>MP3',
    'ImageUrl': u'http://img.kakaku.com/images/productimage/m/01307211611.jpg',
    'ItemPageUrl': u'http://kakaku.com/item/01307211611/',
    'LowestPrice': u'15298',
    'MakerName': u'SONY',
    'NumOfBbs': u'516',
    'ProductID': u'01307211611',
    'ProductName': u'NW-E005 \u30d0\u30a4\u30aa\u30ec\u30c3\u30c8 (2GB)',
    'PvRanking': u'4',
    'ReviewPageUrl': u'http://kakaku.com/prdevaluate/evaluate.asp?PrdKey=01307211611'},
  ... ],
 'NumOfResult': u'762',
 'RequestedUrl': 'http://api.kakaku.com/Ver1/ItemSearch.asp?Keyword=vaio&ResultSet=medium&CategoryGroup=Pc&SortOrder=pricerank&PageNum=4'}

または、エラーがあった場合は、

{'Error': u'\nItemNotFound',
 'RequestedUrl': 'http://api.kakaku.com/Ver1/ItemSearch.asp?Keyword=vaio0000'}

kakaku.com Web API for Python

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

価格.com WEBサービス API マニュアル

価格.comがAPIを公開したので、Pythonバインディング: KakakuComAPIクラスを作ってみました。python 2.4以上が必要。

KakakuComAPIクラスをダウンロードする

中身は以下のような感じ。なんか、妙に長い。XMLのパーズ部分をもっとすんなり書けると良いのだけど。

import urllib, types
from xml.dom import minidom

class KakakuComAPI(object):
    API_ENDPOINT = r'http://api.kakaku.com/Ver1/ItemSearch.asp'
    ELEMENTS = ['ProductID',
                'ProductName',
                'MakerName',
                'CategoryName',
                'PvRanking',
                'ImageUrl',
                'ItemPageUrl',
                'BbsPageUrl',
                'ReviewPageUrl',
                'LowestPrice',
                'NumOfBbs']

    @classmethod
    def search(cls, **args):
        params = cls.__parameterize(args)
        url = cls.API_ENDPOINT + '?' + params
        f = urllib.urlopen(url)
        xml = f.read()
        f.close()
        result = cls.__construct(xml)
        result['RequestedUrl'] = url
        return result

    @classmethod
    def __parameterize(cls, args):

        kw = args.get('Keyword')
        arg_enc = args.get('ArgsEncode')
        if type(kw) is types.UnicodeType:
            kw = kw.encode('shift_jis', 'ignore')
        elif arg_enc:
            kw = kw.decode(arg_enc, 'ignore').encode('shift_jis', 'ignore')

        params = []
        params.append("%s=%s" % ('Keyword', urllib.quote(kw)))

        for p in ('ResultSet', 'CategoryGroup', 'SortOrder', 'PageNum'):
            v = args.get(p)
            if v != None:
                params.append("%s=%s" % (p, urllib.quote(v)))

        return '&'.join(params)

    @classmethod
    def __construct(cls, xml):
        result = {}
        dom = minidom.parseString(xml)

        err = dom.getElementsByTagName('Error')
        if err and len(err) >= 1:
            msg = err[0].getElementsByTagName('Message')[0]
            result['Error'] = msg.firstChild.nodeValue

        nor = dom.getElementsByTagName('NumOfResult')
        if nor and len(nor) >=1:
            result['NumOfResult'] = nor[0].firstChild.nodeValue

        items = dom.getElementsByTagName('Item')
        if items:
            item_list = []
            for item in items:
                item_list.append(cls.__parse_item(item))
            result['Items'] = item_list

        return result

    @classmethod
    def __parse_item(cls, item):
        result = {}
        for e in cls.ELEMENTS:
            tags = item.getElementsByTagName(e)
            if tags:
                result[e] = tags[0].firstChild.nodeValue
            else:
                result[e] = ''
        return result

以下、使用例。

Keywordに日本語を含む場合はsjisで渡すか、unicodeで渡すか、そうでなければArgsEncodeで明示するかする必要があることに注意。

from kakaku_api import KakakuComAPI

r = KakakuComAPI.search(Keyword="vaio")
r = KakakuComAPI.search(Keyword=u"バイオ")
r = KakakuComAPI.search(Keyword=u"バイオ".encode("shift_jis"))
r = KakakuComAPI.search(Keyword=u"バイオ".encode("euc-jp"), ArgsEncode="euc-jp")
r = KakakuComAPI.search(Keyword="vaio",
                        ResultSet="medium",
                        SortOrder="pricerank",
                        PageNum="4",
                        CategoryGroup="Pc")

結果として受け取る r はこんなかんじ


{'Items': [{'BbsPageUrl': u'http://kakaku.com/bbs/Main.asp?PrdKey=01307211611',
    'CategoryName': u'\u30d1\u30bd\u30b3\u30f3\u5468\u8fba\u6a5f\u5668>MP3',
    'ImageUrl': u'http://img.kakaku.com/images/productimage/m/01307211611.jpg',
    'ItemPageUrl': u'http://kakaku.com/item/01307211611/',
    'LowestPrice': u'15298',
    'MakerName': u'SONY',
    'NumOfBbs': u'516',
    'ProductID': u'01307211611',
    'ProductName': u'NW-E005 \u30d0\u30a4\u30aa\u30ec\u30c3\u30c8 (2GB)',
    'PvRanking': u'4',
    'ReviewPageUrl': u'http://kakaku.com/prdevaluate/evaluate.asp?PrdKey=01307211611'},
  ... ],
 'NumOfResult': u'762',
 'RequestedUrl': 'http://api.kakaku.com/Ver1/ItemSearch.asp?Keyword=vaio&ResultSet=medium&CategoryGroup=Pc&SortOrder=pricerank&PageNum=4'}

または

{'Error': u'\nItemNotFound',
 'RequestedUrl': 'http://api.kakaku.com/Ver1/ItemSearch.asp?Keyword=vaio0000'}

追記

ElementTreeを使ったバージョンも書いてみました。see: kh.log - kakaku.com Web API for Python (ElementTree使用版)

2006年04月27日

cvsでcommitメールを送るためのpythonスクリプト

このエントリーをはてなブックマークする このエントリーを含むはてなブックマーク | Save This Page (del.icio.us)

とりあえず書いただけ。
設定方法などは後ほど追記します。

cvsでcommitメールを送るためのpythonスクリプト

追記: 2006/04/27 23:00

スクリプトを更新しました。2006/04/24 23:00以前にダウンロードした方は、もう一度ダウンロードしてください。以前の版では、環境によってデッドロックを起こす場合があります。

設置方法は以下の通り…と説明を書こうとしたのですが、力尽きました。commit をメール通知する設定というページを参考に、cvsform.plをcvsmail.pyと読み替えれば、おそらく設定できるはずです。

以下、簡単に注意点や説明を。


  • このスクリプトは、CVSへのcommit時に、更新されたファイルのdiffをリストアップしてメール送信するためのものです。
  • SMTP, FROM, SUBJECT, CVS, KANJIなどを環境に合わせて変更してください。
  • DEFの内容は引数が欠けている場合の気休めなので、基本的に無視してください。
  • CVSのバージョンによって、loginfo中に%{sVv}と書いたときに得られる文字列のフォーマットが違うようです。スクリプト中のコメントを参考に、適合するほうのコメントをはずしてください。

以上。

ちなみにこんなメールが送られてきます。

From: cvs@your.domain
To: kharakawa@ubuntu
Subject: [CVS] testproj commit mail.
Message-Id: <---@ubuntu>
Date: Thu, 27 Apr 2006 23:14:08 +0900 (JST)
 
Update of /usr/share/cvsroot/testproj
In directory ubuntu:/tmp/testproj
 
Modified Files:
        fugahoge
Log Message:
 
change 'before' to 'AFTER'
 
 
 
 
1 file(s) affected.
 
Index: fugahoge
===================================================================
RCS file: /usr/share/cvsroot/testproj/fugahoge,v
retrieving revision 1.1
retrieving revision 1.2
diff -r1.1 -r1.2
3c3
< befor
---
> AFTER

追記: 2006/04/29 22:00

さらに少し修正しました。正規表現の修正。