u'\xd0\x9a\xd1\x83\xd1\x80\xd1\x83\xd0\xbc\xd0\xbe\xd1\x87'
何かおかしいことに気づきましたか? そして、ここにいます。 行はUnicodeのようですが、内部にはutf-8でエンコードされたバイトがあります。 ここで何かが間違っています。 さらに理解し、これを生成するスクリプトを要求すると、データがWebから取得されることが明らかになります。
urllib
を介した非常に通常の方法で、解析のために
lxml.html
にフィードされます。
urllib
はバイト文字列のみを扱うため、そのようなUnicodeに変換することはできませんでした。つまり、
lxml
せいです。
一般に、
lxml
非常にクールなライブラリであり、高速で機能的であり、
ElementTree
下のインターフェースを模倣して
ElementTree
と対話できます。
xml
何らかの形で便利に使用する必要がある場合、Pythonistには長い間人気があります。
しかし、これは少し異なるケースです。 これはhtmlパーサーを使用します。 そして、文字列でこれらの不愉快な変態が起こるのはその中にあります。
私は問題が何であり、この行動を克服する方法を理解することにしました。
始めるために、私はyandex.ruに行き、どのようなhtmlがそこに与えられているかを見ました。 Utf8コンテンツエンコーディング。 すぐに私の目を引いたのは、エンコード宣言の欠如であり、必須ではありませんが、まだ頻繁に使用されています。 同様のhtmlを作成することにより:
data = """<html>
<head>
</head>
<body> </body>
</html>"""
html = lxml.html.document_fromstring(data)
そして、それを
lxml.html
に詰め込んで、悲しいかな、予想される結果を受け取りました:
>>> s
u'\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82 \xd0\xbc\xd0\xb8\xd1\x80'
>>> print s
Привет м
s-これはまさに「Hello World」という行であり、xpathを通じて引き裂かれています。 ご覧のとおり、デコードされていません。 概して、この問題はその場で解決できます。 このような特別なコーデックraw-unicode-escapeがあり、このような行からはバイトが作成されますが、変換も行われません。
>>> print s.encode('raw-unicode-escape')
しかし、そのような決定は悪いです。 どういうわけか
lxml.html
非ASCII文字のモックにしないでください。
嫌なメタヘッダーhtmlでエンコードを指定するとどうなりますか?
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body> </body>
</html>
すべてがすぐに配置されます。
>>> print s
もちろん、httpヘッダーからエンコードに関する情報を取得する方が論理的ですが、lxml.htmlの場合、謎が入ったプロトコルであり、それを当てにすることはできません。
これを解決する別の方法は、lxml.htmlに入力をバイト文字列ではなくユニコードにすることです(もちろん、エンコードを自分で知っている場合を除きます)。
>>> html = lxml.html.document_fromstring(data.decode('utf-8'))
...
>>> print s
私の意見では、
lxml.html
が「すべてのコストで生き残り」、コンテンツを台無しにしようとしないが、xmlを解析する場合のように、エンコードが設定されていないことを明示的に通知する方がより正しいでしょう。 しかし、いずれにしても、回避策があります。
警戒してください。