Webstemmer使おうとして引数エラーと文字コードに悩まされる
Webページの本文を抽出したくて、MOONGIFTで見つけたWebstemmerを使おうと思ったら、いろんな障害にぶつかった。Python歴3日なので、ソース読むのも一苦労。
エラー1
『ステップ1. 学習するためのHTMLページを取得する』をやろうとしたら早速エラーが。
C:\Python27\Lib\site-packages\webstemmer> textcrawler.py -o asahi http://asahi.com/ Writing: 'asahi.201107111850.zip' Traceback (most recent call last): File "C:\Python27\Lib\site-packages\webstemmer\textcrawler.py", line 444, in <module> if __name__ == '__main__': main() File "C:\Python27\Lib\site-packages\webstemmer\textcrawler.py", line 436, in main debug=debug).run() File "C:\Python27\Lib\site-packages\webstemmer\textcrawler.py", line 356, in __init__ cookie_file, acldb, urldb, default_charset, delay, timeout, debug) File "C:\Python27\Lib\site-packages\webstemmer\textcrawler.py", line 113, in __init__ self.robotstxt.read() File "C:\Python27\lib\robotparser.py", line 57, in read f = opener.open(self.url) File "C:\Python27\lib\urllib.py", line 205, in open return getattr(self, name)(url) File "C:\Python27\lib\urllib.py", line 342, in open_http h.endheaders(data) TypeError: endheaders() takes exactly 1 argument (2 given)
エラーの意味は「引数2つあるよ!1つにしてよ!」らしい。(参考:『初めてのPython』 IV部 演習問題 - ケーズメモ)
試しにendheaders()の元であるhttplib.pyの中身を覗くと、
class HTTPConnection: ... def endheaders(self, message_body=None): ...
となってる。引数がちゃんと2つあるのでこれはおかしい。
試行錯誤の結果、httplib.pyがそこかしこのフォルダに存在していることがわかったため、まずimportの優先順位を確認する。
import sys
sys.path
結果がこう。
['C:\\Python27\\Lib\\site-packages\\webstemmer', 'C:\\Python27\\Lib\\site-packages', 'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 'C:\\Python27\\lib\\lib-tk', 'C:\\Python27']
で、C:\Python27\Lib\site-packages\webstemmerの中を見ると、しっかりhttplib.pyが入ってる。こっちのendheaders()を確認すると、
class HTTPConnection: ... def endheaders(self): ...
引数が1つしかない。ようやく原因特定。
呼び出し先の引数を増やしても、呼び出し元の引数を減らしても一応動いたけど、引数減らすのはちょっと怖いので、webstemmerフォルダのC:\Python27\lib\httplib.pyに書き換えた。よく分からないしこれ以上触りたくない。
エラー2
『ステップ4. 学習したパターンを使って本文を抽出する』を実行し、やっと終わったと思いきや。
C:\Python27\Lib\site-packages\webstemmer>extract.py -C euc-jp asahi.pat asahi.201107111623.zip PATTERN: 201107111602/www.asahi.com/digital/av/TKY201106280357.html MAIN-6: 召ツ宵エ。・将ツ。・。・娼。将苡ェイ召エ宵ョ将」召ェツ。ェ。。ェゥ。ェメ。ェ。\将「\宵ェ\召エ召ツ娼ャ。ェ。。ェゥ。ェメ。ェ。召ツ娼ホ。ェ。。ゥテ。ゥテ。ォタ。ォゥ \。宵ェ\。゚\将ウ召ェチ召「・\召・召ェョ召・召・召ツ宵繽「・召ォア宵イ。ュ召ト将イ召・召「ト???将モ召ェョ召・召ツ宵ウ
文字化け!これは辛い。文字コード周りについて一から調べることになってしまった。
色々調べて分かったことは、
- 元の文字列はUnicode文字列
- EUC-JP,shift-jis,utf-8などひと通りエンコード試したけど全て文字化け
- PyhtonはUnicode文字列を直接表示できない
- 直接表示しようとすると"UnicodeEncodeError: 'cp932' codec can't encode character u'\xa1' in position 0:illegal multibyte sequence"
- try-except文を使って1文字ずつ↑のエラー吐かせてみた
- u'\xa1' u'\xca' u'\xa3' u'\xb6' u'\xb7' u'\xee' u'\xa3' u'\xb2' ...
- Unicode対応 文字コード表でEUCの文字コードを2バイトずつ確認すると、"a1ca,a3b6,b7ee,a3b2"→"(,6,月,2"
- 元記事の本文始めは「(6月29日発売のAERAムック『AERA×Apple アップルはお好きですか』から抜粋した記事です)」
- 合ってるし!
ここまでやって今日は諦めた。文字コード自体はeuc-jpで合ってるっぽいので、文字列の扱い方が良くないんだろうか?なんとか明日中に解決したい。