発端
某社のC++静的解析ツールが吐き出すレポート(HTML形式)から、必要なテキストだけを抜き出そうと思い立ち Python2.7 + Beautifulsoup4でごそごそと始めてみましたが…
bs4test.py
from bs4 import BeautifulSoup
soup = BeautifulSoup(open("rep_38248_dev1.html"))
print soup.prettify("shift_jis")
あれぇ? HTML全体(約2万6千行)の1/10の2500行ぐらいしか読み込まないじゃないか!!
弱った。参った。困った。
探索の旅
こういう時の常套手段は、「同じ境遇にいる人をネットで探す」です。
早速、googleで検索みると…どんびしゃな情報はありません。トほほ。
しかたがないので、bs4のソースコードであちこち突いて調べてみました。
原因は、bs4が下請けで呼び出している lxmlのfeed()メソッドの不具合で、巨大なHTMLテキストを食わせると途中でこぼれてしまうのでした。
対策は、bs4/builder/_lxml.py の LXMLTreeBuilder.feed() をコメントアウトするだけでOKです。(なぜか、XMLパーサーのLXMLTreeBuilderForXML.feed()は対策済みでした)
bs4/builder/_lxml.py
class LXMLTreeBuilder(HTMLTreeBuilder, LXMLTreeBuilderForXML):
features = [LXML, HTML, FAST, PERMISSIVE]
is_xml = False
def default_parser(self, encoding):
return etree.HTMLParser
# def feed(self, markup):
# encoding = self.soup.original_encoding
# try:
# self.parser = self.parser_for(encoding)
# self.parser.feed(markup)
# self.parser.close()
# except (UnicodeDecodeError, LookupError, etree.ParserError), e:
# raise ParserRejectedMarkup(str(e))
結末
あらためてググってみると、おや! Googleグループのbeautifulsoupフォーラムに関連するポストがありました。LXMLTreeBuilderForXML.feed() は、この時にBugFixされたようです。で、LXMLTreeBuilderの修正は漏れていた…ありゃまでした。