2011年4月13日水曜日

トラブルシューティング

本セクションでは、人々が、Beautiful Soupを使う上で、共通の問題を取り上げます。


Beautiful Soupに渡した非ASCII文字が表示されないのはなぜか?


もし、次のようなエラーが表示されたら:

"'ascii' codec can't encode character 'x' in position y: ordinal not in range(128)",

おそらく、問題は、Beautiful Soup にあるよりも、むしろ、Pythonのインストールにあります。
Beautiful Soup 中以外で非ASCII文字の出力を試してみてください、同様の問題が起こるでしょう。
例えば、以下のようなコードを動かしてみてください:
latin1word = 'Sacr\xe9 bleu!'
unicodeword = unicode(latin1word, 'latin-1')
print unicodeword

もし、これがうまく動作して、Beautiful Soup ではうまくいかないなら、おそらくBeautiful Soup のバグでしょう。しかしながら、これがうまく動かないなら、問題はあなたのPythonのセットアップにあります。Python は、安全に動作するために、ターミナルに非ASCII文字を送出しません。
この動作を上書きする方法は2つあります。
  1. 簡単な方法は、標準出力を、ISO-Latin-1やUTF-8文字をターミナルに送出するコンバーターにリマップすることです。
    import codecs
    import sys
    streamWriter = codecs.lookup('utf-8')[-1]
    sys.stdout = streamWriter(sys.stdout)
    
    codecs.lookup は、多数のバウンドメソッドと、codecsに関連する他のオブジェクトを返します。
    最後の行は、ストリームの出力をラップ出来るStreamWriter オブジェクトです。

  2. 難しい方法は、デフォルトエンコーディングをISO-Latin-1や、UTF-8に設定するPython インストール中で、sitecustomize.py ファイルを作成することです。
    あなたの全てのPythonプログラムは、各プログラムに何もすることなく、標準出力に対し、そのエンコーディングを使用するでしょう。
    私のインストールの場合、/usr/lib/python/sitecustomize.py に、次のように書いています:
    import sys
    sys.setdefaultencoding("utf-8")
    

PythonのUnicodeサポートに関するさらなる情報は、 プログラマのためのUnicode や、 PythonにおけるUnicode web アプリケーションの全てをご覧ください。 Pythonクックブック中のレシピ 1.20 と 1.21 も非常に役に立ちます。
たとえ、ターミナルの表示がASCIIに制限されていたとしても、Beautiful Soup 使って、UTF-8や他のエンコーディングで、ドキュメントを解析、処理、記述することが出来るということは覚えておいてください。print 関数で、特定の文字を表示できないだけです。


Beautiful Soupに渡したデータが削除された!なぜ?どうして?????


Beautiful Soup は、悪い構造のSGMLを操作できますが、SGMLとは全く異なるものを渡されると、時々、データを失います。 これは、悪い構造のマークアップほど、よくあることではありませんが、webクローラーや、それに近いものを構築するなら、おそらくこの問題に出くわすでしょう。
この問題の唯一の解は、正規表現を用いて、早めにサニタイズを行うことです。 ここに、私とBeautiful Soup のユーザーが発見したコード例をいくつか示します:
  • Beautiful Soup は、データとして,邪悪な形式のXMLを扱います。しかしながら、これは、実際には存在しない、良い形式のXML定義を失います:
    from BeautifulSoup import BeautifulSoup
    BeautifulSoup("< ! FOO @=>")
    # < ! FOO @=>
    BeautifulSoup("<b><!FOO>!</b>")
    # <b>!</b>
    
  • もし、あなたのドキュメントが宣言で始まり、宣言を終了しなければ、Bautiful Soup はドキュメントの残りの部分は宣言の一部だとみなすでしょう。
    もし、ドキュメントが宣言の途中で終了したら、Beautiful Soup は宣言全体を無視します。
    いくつか例を示します:
    from BeautifulSoup import BeautifulSoup
    
    BeautifulSoup("foo<!bar") 
    # foo 
    
    soup = BeautifulSoup("<html>foo<!bar</html>") 
    print soup.prettify()
    # <html>
    #  foo<!bar</html>
    # </html>
    

    これを修正する方法がいくつかあります;1つはここに詳細が載っています。

    Beautiful Soup はまた、ドキュメントの最後で終了しないエンティティ参照を無視します:
    BeautifulSoup("&lt;foo&gt")
    # &lt;foo
    

    実際のwebページで、これは見たことありませんが、多分、そこらにあるでしょう。

  • 不正な形式のコメントがあると、Beautiful Soupはドキュメントの残りを無視します。
    正規表現を用いて不良データをサニタイズするの中で取り上げられています。


BeautifulSoup
クラスが構築した解析木が気に触る!

違った方法でマークアップの解析を行うためには、他のビルトインパーサーを調査するか、あるいは、カスタムパーサーを構築してください。


Beautiful Soupは遅すぎる!


Beautiful Soupは、要素木や、カスタムビルトの SGMLParser のサブクラスのように高速に動作しません。要素木はCで書かれており、SGMLParser を使えば、あなたが望む動作だけを行う、あなただけの小さな Beautiful Soup を書くことが出来ます。 Beautiful Soup のポイントはプログラマーの時間を減らすことであり、処理時間を減らすものではありません。
いわば、あなたが必要とするドキュメントの部分を解析することによってのみ大幅に、Beautiful Soupのスピードを上げることが出来ます、 そして、抽出や分解を使って、不要なオブジェクトをガベージコレクト出来ます。

0 件のコメント:

コメントを投稿

【和訳】Django Rest Framework 目次

目次 【和訳】Django Rest Framework クイックスタート 【和訳】Django Rest Framework チュートリアル1:シリアル化 【和訳】Django Rest Framework チュートリアル2:リクエストとレスポンス 【和訳】Django Res...