HTMLページをロードしてテキストを出力しようとしていますが、Webページを正しく取得しているにもかかわらず、BeautifulSoupは何らかの方法でエンコードを破棄します。
ソース:
# -*- coding: utf-8 -*-
import requests
from BeautifulSoup import BeautifulSoup
url = "http://www.columbia.edu/~fdc/utf8/"
r = requests.get(url)
encodedText = r.text.encode("utf-8")
soup = BeautifulSoup(encodedText)
text = str(soup.findAll(text=True))
print text.decode("utf-8")
抜粋出力:
...Odenw\xc3\xa4lderisch...
これはOdenwälderischである必要があります
2つの間違いを犯しています。エンコーディングを誤って処理し、結果リストを、情報を失うことなく文字列に安全に変換できるものとして扱います。
まず、_response.text
_は使用しないでください。ここでの問題はBeautifulSoupではありません。あなたは Mojibake を再エンコードしています。 requests
ライブラリは、サーバーが明示的にエンコードを指定していない場合、デフォルトで_text/*
_コンテンツタイプのLatin-1エンコーディングに設定されます。これは、HTTP標準でデフォルトとされているためです。
EncodingAdvancedのドキュメントのセクション を参照してください:
リクエストがこれを行わないのは、HTTPヘッダーに明示的な文字セットが存在しない場合のみですand _
Content-Type
_ヘッダーにtext
が含まれています。 この状況では、RFC 2616は、デフォルトの文字セットが_ISO-8859-1
_でなければならないことを指定しています。この場合、要求は仕様に従います。別のエンコーディングが必要な場合は、_Response.encoding
_プロパティを手動で設定するか、生の_Response.content
_を使用できます。
大胆な強調鉱山。
代わりに_response.content
_生データを渡します。
_soup = BeautifulSoup(r.content)
_
BeautifulSoup 3を使用しているようですが、代わりにBeautifulSoup 4にアップグレードしたいと考えています。バージョン3は2012年に廃止され、いくつかのバグが含まれています。 _beautifulsoup4
_プロジェクト をインストールし、_from bs4 import BeautifulSoup
_を使用します。
BeautifulSoup 4は通常、解析時にHTML _<meta>
_タグまたは提供されたバイトの統計分析のいずれかから、使用する適切なエンコーディングを理解するという優れた機能を果たします。サーバーが文字セットを提供する場合でも、これを応答からBeautifulSoupに渡すことができますが、requests
がデフォルトを使用しているかどうかを最初にテストします。
_encoding = r.encoding if 'charset' in r.headers.get('content-type', '').lower() else None
soup = BeautifulSoup(r.content, from_encoding=encoding)
_
最後に、BeautifulSoup 4では、soup.get_text()
を使用してページからすべてのテキストを抽出できます。
_text = soup.get_text()
print text
_
代わりに、結果リスト(soup.findAll()
の戻り値)を文字列に変換しています。 Pythonのコンテナーはリストの各要素でrepr()
を使用してデバッグ文字列を生成するため、これは機能しません。印刷できないもののエスケープシーケンスを取得するASCII文字。
BeautifulSoupのせいではありません。これは、BeautifulSoupを使用する前にencodedText
を印刷することで確認できます。非ASCII文字はすでに意味不明です。
ここでの問題は、バイトと文字を混同していることです。違いの概要については、 Joelの記事の1つ を参照してください。ただし、要点は、バイトはバイト(追加の意味を持たない8ビットのグループ)であり、文字はテキストの文字列を構成します。 エンコードすると文字がバイトになり、デコードするとバイトが文字に戻ります
requests
ドキュメント を見ると、r.text
がバイトではなく文字で構成されていることがわかります。エンコードするべきではありません。そうしようとすると、バイト文字列が作成され、それを文字として処理しようとすると、悪いことが起こります。
これを回避するには2つの方法があります。
r.content
に格納されている、デコードされていない生のバイトを使用します Martijnの提案どおり 。次に、自分でデコードして文字に変換できます。requests
でデコードを行いますが、正しいコーデックを使用していることを確認してください。この場合はUTF-8であることがわかっているので、r.encoding = 'utf-8'
を設定できます。これをbeforeする前に(---)r.text
にアクセスすると、r.text
にアクセスすると、正しくデコードされ、文字列が得られます。文字エンコーディングをいじる必要はまったくありません。ちなみに、Python 3を使用すると、文字列とバイト文字列の違いを維持しやすくなります。これは、さまざまな種類のオブジェクトを使用して表現する必要があるためです。
コードにいくつかのエラーがあります:
まず、テキストを再エンコードする試みは必要ありません。リクエストはページのネイティブエンコーディングを提供し、BeautifulSoupはこの情報を取得してデコード自体を行うことができます。
# -*- coding: utf-8 -*-
import requests
from BeautifulSoup import BeautifulSoup
url = "http://www.columbia.edu/~fdc/utf8/"
r = requests.get(url)
soup = BeautifulSoup(r.text, "html5lib")
第二に、エンコーディングの問題があります。端末で結果を視覚化しようとしている可能性があります。取得できるのは、ASCIIセットに含まれていないすべての文字のテキスト内の文字のUnicode表現です。次のように結果を確認できます。
res = [item.encode("ascii","ignore") for item in soup.find_all(text=True)]