10

Python の ElementTree を使用して HTML を解析、操作、および出力しようとしています。

import sys
from cStringIO  import StringIO
from xml.etree  import ElementTree as ET
from htmlentitydefs import entitydefs

source = StringIO("""<html>
<body>
<p>Less than &lt;</p>
<p>Non-breaking space &nbsp;</p>
</body>
</html>""")

parser = ET.XMLParser()
parser.parser.UseForeignDTD(True)
parser.entity.update(entitydefs)
etree = ET.ElementTree()

tree = etree.parse(source, parser=parser)
for p in tree.findall('.//p'):
    print ET.tostring(p, encoding='UTF-8')

Mac OS X 10.6 で Python 2.7 を使用してこれを実行すると、次のようになります。

<p>Less than &lt;</p>

Traceback (most recent call last):
  File "bar.py", line 20, in <module>
    print ET.tostring(p, encoding='utf-8')
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 1120, in tostring
    ElementTree(element).write(file, encoding, method=method)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 815, in write
    serialize(write, self._root, encoding, qnames, namespaces)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 931, in _serialize_xml
    write(_escape_cdata(text, encoding))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 1067, in _escape_cdata
    return text.encode(encoding, "xmlcharrefreplace")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 19: ordinal not in range(128)

"encoding='UTF-8'" を指定すると改行なしのスペース文字が処理されると思っていましたが、どうやらそうではないようです。代わりに何をすべきですか?

4

5 に答える 5

7

0xA0はlatin1文字であり、Unicode文字ではなく、ループ内のp.textの値はstrであり、Unicodeではありません。つまり、utf-8でエンコードするには、最初にPythonによって暗黙的にUnicodeに変換する必要があります。文字列(つまり、デコードを使用)。これを行うときは、他に何も言われなかったので、ASCIIを想定しています。0xa0は有効なASCII文字ではありませんが、有効なlatin1文字です。

Unicode文字の代わりにlatin1文字を使用する理由は、entitydefsが名前をlatin1エンコード文字列にマッピングするためです。htmlentitydef.name2codepointから取得できるユニコードコードポイントが必要です

以下のバージョンはあなたのためにそれを修正するはずです:

import sys
from cStringIO  import StringIO
from xml.etree  import ElementTree as ET
from htmlentitydefs import name2codepoint

source = StringIO("""<html>
<body>
<p>Less than &lt;</p>
<p>Non-breaking space &nbsp;</p>
</body>
</html>""")

parser = ET.XMLParser()
parser.parser.UseForeignDTD(True)
parser.entity.update((x, unichr(i)) for x, i in name2codepoint.iteritems())
etree = ET.ElementTree()

tree = etree.parse(source, parser=parser)
for p in tree.findall('.//p'):
    print ET.tostring(p, encoding='UTF-8')
于 2012-05-29T02:37:00.347 に答える
4

XML は、、、、および のみを&lt;定義します。その他はHTMLから来ています。したがって、いくつかの選択肢があります。&gt;&apos;&quot;&amp;&nbsp;

  1. &#160;のような数値エンティティを使用するようにソースを変更することができ&#xA0;ます&nbsp;
  2. これらの値を定義する DTD を使用できます。

XSLT FAQに役立つ情報があります (XSLT について書かれていますが、XSLT は XML を使用して書かれているため同じです) 。


質問にはスタック トレースが含まれているようです。それは物事を変えます。文字列が にあることを確認しますUTF-8か? それが 1 バイトに解決される場合は、そう0xA0ではなく、または.UTF-8cp1252iso-8859-1

于 2012-05-18T13:54:48.113 に答える
3

&nbsp;改行なしスペースのデフォルト (ascii) エンコーディングである '\xa0' に変換されています (UTF-8 エンコーディングは '\xc2\xa0' です) 。

'\xa0'.encode('utf-8')

デフォルトのコーデックである ascii は 128 文字までしか動作せず、ord('\xa0') = 160 であるため、UnicodeDecodeError が発生します。

import sys
reload(sys)  # must reload sys to use 'setdefaultencoding'
sys.setdefaultencoding('latin-1')

print '\xa0'.encode('utf-8', "xmlcharrefreplace")

あなたの問題を解決するはずです。

于 2012-05-29T03:37:44.473 に答える
-1

ここでの問題は、nbsp エンティティではなく、print ステートメントにあると思います。

エラーは次のとおりです。

UnicodeDecodeError: 'ascii' コーデックは位置 19 のバイト 0xa0 をデコードできません: 序数が範囲外です (128)

ET.tostring(p, encoding='utf-8')これは、(から) utf-8 文字列を取得し、ASCII 端末でエコーアウトしようとしているからだと思います。そのため、Python はその文字列を暗黙的に Unicode に変換してから、再度 ascii に変換しています。nbspはutf-8 で直接表現できますが、ascii で直接表現することはできません。したがって、エラー。

代わりに出力をファイルに保存して、期待どおりになるかどうかを確認してください。

または、 を試しprint ET.toString(p, encoding='ascii')てください。これにより、ElementTree は数値エンティティを使用して、ASCII で表現できないものを表現します。

于 2012-05-18T15:05:10.973 に答える
-1

HTML は XML と同じではないため、 のようなタグは機能し&nbsp;ません。理想的には、その情報を XML 経由で渡そうとする場合、最初に上記のデータを xml エンコードすると、次のようになります。

<xml>
<mydata>
&lt;htm&gt;
&lt;body&gt;
&lt;p&gt;Less than &amp;lt;&lt;/p&gt;
&lt;p&gt;Non-breaking space &amp;nbsp;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</mydata>
</xml>

そして、XML を解析した後、文字列を HTML でエンコード解除できます。

于 2012-05-18T14:09:51.557 に答える