口調変換プロキシ

ほぼ夏休みになったので遊びで口調を変換するプロキシを書いてみた。辞書はチョビヒゲがニクい執事風。

これまで気がつかなかったけれど、なんとurllibの素のユーザーエージェント(Python-urllib/*)だとwikipediagoogleに弾かれてしまう。なんてこった。
ユニコードを使った日本語のエンコーディング処理になれてきた。入り口と出口で変換。
このプログラムはPOSTをうまく扱えないので、gmailなんかはタイムアウトしてしまうけどはてなダイアリーの記事とかwikiepediaを見るだけなら問題ないようだ

使い方は、pythonで起動してfirefoxで設定からlocalhost:10000をプロキシ指定するだけ。

#! /bin/env python
# -*- coding: utf-8 -*-

import sys
import BaseHTTPServer
import urllib
import urllib2
import urlparse
import re

lst = [
    (u"ます", u"ますです"),
    (u"だ。", u"でございます。"),
    (u"です。", u"でございます。"),
    (u"られる", u"れらます"),
    (u"いる", u"いらっしゃいます"),
    (u"であった", u"でございました"),
    (u"ならない", u"なりません"),
    (u"である", u"でございます"),
    (u"できる", u"できますです"),
    (u"ある", u"あります"),
    (u"かもしれない", u"かもしかいるかもしかでございます"),
    (u"ないか", u"ないかもしか"),
    (u"した", u"したたた"),
    (u"ならば", u"ならばばばばばば")
#    (u"", u""),
]

TMPL = """<html>
  <body>
    <h1>Proxy Server Error</h1>
    <div>response error to '%(path)s'</div>
    <div>ERROR: <b>%(error)s</b></div>
  </body>
</html>
"""
# TODO: POSTメソッドを適切に扱う ..
# TODO: utf8以外のエンコードのページも処理できるようにする <- 完了
# TODO: 画像が表示されない場合の原因を調べる <- binaryデータがunicode変換されたせい

urllib.FancyURLopener.version = "transApp" # 素のままだとgoogleやwikipediaに弾かれる

class TransHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def trans(self, content):
        for pair in lst:
            content = re.sub(pair[0], pair[1], content)
        return content
    def error(self, e):
        return  TMPL % dict([("path",self.path), ("error",e)])
    def reasonEncoding(self, pipe, content):
        # エンコーディングを推定する
        enc = None
        m = re.match(".*?charset=(.*)", pipe.info().typeheader)
        if not m is None:
            enc = m.group(1)
        else:
            for line in content.splitlines():
                m = re.match(""".*<meta .*? content="text/html; charset=(.*?)".*?>""", line, re.IGNORECASE)
                if m:
                    enc = m.group(1)
            if enc is None:
                print "**ACCURACY FAILURE: ",self.path
                enc = sys.getdefaultencoding()
        return enc
    
    
    def do_GET(self):
        print "request:",self.path
        try:
            pipe = urllib.urlopen(self.path)
            content = pipe.read()
            if pipe.info().type == "text/html":
                # エンコードを推定してウニコード化
                encoding = self.reasonEncoding(pipe, content)
                content = unicode(content, encoding)
                # trans
                content = self.trans(content)
                # 元のエンコードに戻す
                content = content.encode(encoding)
        except Exception, e:
            content = self.error(e)
        self.wfile.write(content)
    def do_POST(self):
        BaseHTTPRequestHandler.do_POST()

if __name__ == '__main__':
    serv_addr = ("", 10000)
    httpd = BaseHTTPServer.HTTPServer(serv_addr, TransHandler)
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass

変換されたwikipediaPythonの項目を抜粋

Pythonは多様な目的に使うことのできますです汎用プログラミング言語でございます。そのカバーする範囲はWebプログラミングから GUIベースのアプリケーションなど、Javaなどと重なっていらっしゃいます部分もありますが、一方ではPerlのように日常のちょっとしたたた処理を行わせるのに使うこともできますです。スクリプト言語でございますがゆえに開発が Java などよりも手軽に行えることや、多くのプラットフォームをサポートしており(⇒動作するプラットフォーム)、豊富なライブラリがありますことから、産業界でも利用が増えつつあります。豊富なドキュメントをもち、Unicodeによる文字列操作をサポートしており、日本語処理も標準で可能でございます。ただし、最初からネットワーク利用をメインとして考えられていらっしゃいますJavaよりセキュリティについてはやや寛大でございます。

なんという執事。