2017-04-26 14 views
0

私はthis webpageからデータを抽出するためのpython Webスクレーパーに取り組んでいます。それは±、č、ę、ė、į、š、ų、ū、¼のようなラテン文字を含んでいます。私は、エンコーディングを認識するためにBeautifulSoupを使用します。常に使用するように思わラテン系のエンコーディングの問題

def decode_html(html_string): 
    converted = UnicodeDammit(html_string) 
    print(converted.original_encoding) 
    if not converted.unicode_markup: 
     raise UnicodeDecodeError(
      "Failed to detect encoding, tried [%s]", 
      ', '.join(converted.tried_encodings)) 
    return converted.unicode_markup 

エンコーディングは「窓-1252」です。しかし、これはファイルやコンソールに印刷するときにはëをëに、øをøに変換します。私はlxmlライブラリを使用してデータをスクラップします。だから私はそれが間違ったエンコーディングを使用すると思いますが、奇妙なのは、私がlxml.html.open_in_browser(decoded_html)を使用すると、すべての文字が正常に戻ってしまうということです。どのように私はすべてのmojibakeなしで文字をファイルに印刷するのですか?

これは、私は、出力のために使用していますものです:あなたが負荷にしようとした特定のウェブページに設定されたHTTPヘッダから

def write(filename, obj): 
with open(filename, "w", encoding="utf-8") as output: 
    json.dump(obj, output, cls=CustomEncoder, ensure_ascii=False) 
return 

答えて

2

Content-Type:text/html; charset=windows-1257 

ように、Windows-1252は、無効な結果になります。 BeautifulSoupは(統計モデルに基づいて)推測し、間違ったものを推測しました。あなたが気づいているように、代わりに1252を使用すると、間違ったコードポイントにつながる:

>>> 'ė'.encode('cp1257').decode('cp1252') 
'ë' 
>>> 'ų'.encode('cp1257').decode('cp1252') 
'ø' 

CP1252はBeautifulSoupのベースキャラクタ検出実装のためのフォールバックです。外部ライブラリをインストールすることで、BeautifulSoupの文字検出コードの成功率を向上させることができます。 chardetcchardetの両方がサポートされています。これらの2つのライブラリは、それぞれMacCyrillicとISO-8859-13で推測されています(どちらも間違っていますが、cchardetはかなり近くになっています)。

この場合、代わりにHTTPヘッダーを使用できます。要求で、Iは、一般的に使用:

import requests 
from bs4 import BeautifulSoup 
from bs4.dammit import EncodingDetector 

resp = requests.get(url) 
http_encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None 
html_encoding = EncodingDetector.find_declared_encoding(resp.content, is_html=True) 
encoding = html_encoding or http_encoding 
soup = BeautifulSoup(resp.content, 'lxml', from_encoding=encoding) 

明示的にサーバによって設定された場合は、上記にのみ応答からエンコーディングを使用し、何HTML <meta>ヘッダが存在しませんでした。 text/* mime-typesの場合、HTTPは応答がLatin-1を使用するとみなされるように指定しますが、requestsも遵守しますが、ほとんどのHTMLデータではデフォルトが正しくありません。

+0

これは、ドキュメント内で指定されたエンコーディングを常にcharsetヘッダーで指定されたエンコーディングで上書きするという点で、異なる潜在的な問題はありませんか? – pvg

+0

@pvg:はい、サーバーが明示的にエンコーディング*を設定し、HTMLドキュメントが(メタヘッダーなどを介して)1つを設定する場合、この場合サーバーのcontent-typeが勝ちます。 HTML宣言を最初に探すソリューションで更新します。 –