2012-12-21 49 views
2

當我得到一個網頁,我用UnicodeDammit將其轉換爲UTF-8編碼,就像:python lxml模塊在內部使用哪種編碼?

import chardet 
from lxml import html 
content = urllib2.urlopen(url).read() 
encoding = chardet.detect(content)['encoding'] 
if encoding != 'utf-8': 
    content = content.decode(encoding, 'replace').encode('utf-8') 
doc = html.fromstring(content, base_url=url) 

但是當我使用:

text = doc.text_content() 
print type(text) 

輸出爲<type 'lxml.etree._ElementUnicodeResult'>。 爲什麼?我認爲這將是一個utf-8字符串。

回答

6

lxml.etree._ElementUnicodeResult是從unicode繼承的類:

$ pydoc lxml.etree._ElementUnicodeResult 

lxml.etree._ElementUnicodeResult = class _ElementUnicodeResult(__builtin__.unicode) 
| Method resolution order: 
|  _ElementUnicodeResult 
|  __builtin__.unicode 
|  __builtin__.basestring 
|  __builtin__.object 

在Python中,這是相當常見的有來自基類型擴展到添加一些特定模塊的功能類。將對象像普通的Unicode字符串一樣對待應該是安全的。

+0

除非它不是。如果'some_str'是一個'_ElementUnicodeResult',Path('foo/bar')/ some_str'將會失敗,因爲'intern(some_str)'會失敗 –

1

您可能想要跳過重新編碼步驟,因爲lxml.html會自動使用源文件中指定的編碼,只要它以有效unicode結尾,可能沒有理由關心它是如何最初編碼。

除非你的項目非常小而且非正式,以至於你可以肯定你永遠不會遇到8位字符串(即它總是7位ASCII,英文沒有特殊字符),所以明智地將你的文本變成unicode儘可能早(如在檢索之後),並保持這種狀態,直到需要序列化它以寫入文件或通過套接字發送爲止。

您看到<type 'lxml.etree._ElementUnicodeResult'>的原因是因爲lxml.html.fromstring()會自動爲您執行解碼步驟。注意,這意味着你上面的代碼將不會與UTF-16,例如編碼的頁面工作,因爲8位字符串將採用UTF-8編碼,但HTML仍然會說UTF-16

<meta http-equiv="Content-Type" content="text/html; charset=utf-16" /> 

和lxml將嘗試根據utf-16編碼規則對字符串進行解碼,並在我期望的短時間內引發異常。

如果你想序列化爲UTF-8編碼 8位串輸出,所有你需要的是這樣的:

>>> text = doc.text_content().encode('utf-8') 
>>> print type(text) 
<type 'str'>