pythonを使用してWebページをスクリーンスクレイピングする場合、ページの文字エンコードを知っている必要があります。出力よりも間違った文字エンコードは台無しになります。
人々は通常、エンコーディングを検出するためにいくつかの基本的な手法を使用します。ヘッダーの文字セットまたはメタタグで定義された文字セットを使用するか、 エンコード検出器 (メタタグまたはヘッダーを考慮しない)を使用します。これらの手法を1つだけ使用すると、ブラウザの場合と同じ結果が得られない場合があります。
ブラウザは次のようにします。
(まあ...少なくとも、ほとんどのブラウザがそうしていると私は信じています。ドキュメントは本当に不足しています。)
私が探しているのは、ブラウザと同じようにページの文字セットを決定できるライブラリです。私はそうではないと確信していますこの問題の適切な解決策を必要とする最初の人。
Beautiful Soupのドキュメント によると。
Beautiful Soupは、ドキュメントをUnicodeに変換するために、優先度の高い順に次のエンコードを試みます。
これには html5lib を使用します。
Urllibまたはurllib2を含むファイルをダウンロードすると、文字セットヘッダーが送信されたかどうかを確認できます。
fp = urllib2.urlopen(request)
charset = fp.headers.getparam('charset')
BeautifulSoupを使用して、HTML内のメタ要素を見つけることができます。
soup = BeatifulSoup.BeautifulSoup(data)
meta = soup.findAll('meta', {'http-equiv':lambda v:v.lower()=='content-type'})
どちらも使用できない場合、ブラウザは通常、自動検出と組み合わせてユーザー構成にフォールバックします。 rajaxが提案するように、chardetモジュールを使用できます。ページを中国語(たとえば)にする必要があることを示すユーザー構成を使用できる場合は、より適切に実行できる可能性があります。
niversal Encoding Detector を使用します:
>>> import chardet
>>> chardet.detect(urlread("http://google.cn/"))
{'encoding': 'GB2312', 'confidence': 0.99}
他のオプションは、wgetを使用することです。
import os
h = os.popen('wget -q -O foo1.txt http://foo.html')
h.close()
s = open('foo1.txt').read()
提示された回答のハイブリッドが必要なようです。
<meta>
美しいスープまたは他の方法を使用したタグ正直なところ、それ以上のものが見つかるとは思いません。
実際、他の回答のコメントでリンクしたFAQ)をさらに読んだ場合、それが検出器ライブラリの作成者が提唱していることです。
FAQを信じるなら、これはブラウザが行うことです(元の質問で要求されたように)。検出器はFirefoxスニッフィングコードのポートです。
Scrapyは、requests.get(url).textやurlopenとは異なり、ページをダウンロードして正しいエンコーディングを検出します。そうするために、それはブラウザのようなルールに従おうとします-ウェブサイトの所有者は彼らのウェブサイトをブラウザで動作させるインセンティブを持っているので、これはできる最善の方法です。 Scrapyは、HTTPヘッダー、<meta>
タグ、BOMマーク、およびエンコード名の違いを考慮に入れる必要があります。
コンテンツベースの推測(chardet、UnicodeDammit)自体は、失敗する可能性があるため、正しい解決策ではありません。ヘッダーまたは<meta>
またはBOMマークが使用できないか、情報を提供しない場合の最後の手段としてのみ使用する必要があります。
エンコーディング検出機能を取得するためにScrapyを使用する必要はありません。それらは(他のいくつかのものと一緒に)w3libと呼ばれる別のライブラリでリリースされます: https://github.com/scrapy/w3lib 。
ページエンコーディングとUnicode本文を取得するには、 w3lib.encoding.html_to_unicode 関数を使用し、コンテンツベースの推測フォールバックを使用します。
import chardet
from w3lib.encoding import html_to_unicode
def _guess_encoding(data):
return chardet.detect(data).get('encoding')
detected_encoding, html_content_unicode = html_to_unicode(
content_type_header,
html_content_bytes,
default_encoding='utf8',
auto_detect_fun=_guess_encoding,
)
ページを取得してからブラウザが使用する文字セットを把握する代わりに、ブラウザを使用してページを取得し、使用する文字セットを確認してみませんか。
from win32com.client import DispatchWithEvents
import threading
stopEvent=threading.Event()
class EventHandler(object):
def OnDownloadBegin(self):
pass
def waitUntilReady(ie):
"""
copypasted from
http://mail.python.org/pipermail/python-win32/2004-June/002040.html
"""
if ie.ReadyState!=4:
while 1:
print "waiting"
pythoncom.PumpWaitingMessages()
stopEvent.wait(.2)
if stopEvent.isSet() or ie.ReadyState==4:
stopEvent.clear()
break;
ie = DispatchWithEvents("InternetExplorer.Application", EventHandler)
ie.Visible = 0
ie.Navigate('http://kskky.info')
waitUntilReady(ie)
d = ie.Document
print d.CharSet
BeautifulSoupはUnicodeDammitでこれを投与します: nicode、Dammit