當前位置:成語大全網 - 書法字典 - python html解析器是什麽意思?

python html解析器是什麽意思?

在PyCon上準備關於HTML的演講時,我覺得應該比較壹些現有的解析器和文檔模型。

其實情況有點復雜,因為處理HTML有幾個步驟:

解析此HTML

將其解析為壹個對象(如文檔對象)

連載壹下

有些解析器只處理第壹步,有些只處理第二步,有些可以處理所有三步。例如,ElementSoup使用ElementTree表示文檔,但BeautifulSoup用作實際的解析器。BeautifulSoup內部也有壹個document對象。HTMLParser只進行解析(不分離出任何對象),但是html5lib可以生成幾種不同的文檔樹(DOM樹)。序列化也分為XML和HTML。

因此,我選擇了以下解析器庫進行基準性能測試:

Lxml:包含壹個解析器,可以生成文檔對象,支持HTML序列化。它也可以使用BeautifulSoup或html5lib進行解析,而不使用內置的解析器。

beautiful soup:nbsp;包含壹個可以生成文檔對象並支持HTML序列化的解析器。

Html5lib:有解析器。它也有壹個序列化器,但我沒有使用它。它還有壹個內置的文檔對象(也就是simpletree),但是……除了自測,我不知道這個東西還能做什麽。

ElementTree:此包中有壹個XML序列化程序。ElementTree可以生成文檔對象,也是python內置的XML解析模塊。我認為下壹個版本會帶來壹個HTML序列化器,但是我也沒有測試過這個XML序列化器。它還有壹個解析器。測試時,我用html5lib作為解析器來測試ElementTree。

CElementTree:這是壹個用C語言擴展的python模塊,實現了ElementTree。

HTMLParser:包含壹個分析器。但實際上它無法解析文檔對象,很多正常的網頁都無法正常處理(包括表格或者腳本),更不用說有語法錯誤的頁面了。它只是使用解析器來遍歷文檔。

Htmlfill:它使用HTMLParser作為解析器,在解析過程中它對元素的處理比HTMLParser多。

石根[1]:包含壹個解析器,可以生成文檔對象,支持HTML序列化。

XML . DOM . minidom:Python標準庫中內置的文檔模型,可以通過html5lib解析。(我不建議用minidom——這篇文章裏有壹些原因,還有很多原因我沒寫。)

我預計lxml的性能會更好,因為它是基於C庫libxml2的。但其實它的性能比我預想的要好,超過了其他所有同類庫。所以,除非妳考慮到壹些很難的安裝問題(尤其是在Mac上),否則我推薦妳使用lxml進行HTML解析。

我的測試代碼在這裏。妳可以自己下載並運行測試程序。它包含所有示例數據,用於生成圖表的命令也在這裏。這些測試數據來自python.org隨機選取的部分頁面(共355頁)。

分析

lxml:0.6;beautiful soup:10.6;html 5 lib element tree:30.2;html 5 lib minidom:35.2;石根:7.3;html parser:2.9;htmlfill:4.5

第壹個測試運行這些解析器來解析文檔。應該註意,lxml比HTMLParser快6倍,雖然HTMLParser

不生成文檔對象(lxml在內存中創建壹個文檔樹)。html5lib並不能生成所有種類的樹,因為每壹種樹都需要相同的時間。之所以包含使用xml.dom.minidom作為輸出結果的html5lib測試結果,是為了說明minidom有多慢。石根非常快,但也是最不穩定的。相比之下,html5lib、lxml和BeautifulSoup就健壯多了。html5lib的優點是html總是可以被正確解析(至少理論上是這樣)。

Lxml會在解析過程中釋放GIL,但我認為影響應該不大。

連載

lxml:0.3;beautiful soup:2.0;html 5 lib element tree:1.9;html 5 lib minidom:3.8;石根:4.4

所有這些庫執行序列化的速度都很快,但是lxml再次遙遙領先。ElementTree和minidom只做XML序列化,沒有理由說HTML序列化更快。此外,石根實際上比minidom慢。說實話,任何比minidom慢的東西都是相當震撼的。

內存占用

lxml:26;beautiful soup:82;beautiful soup lxml:104;html 5 lib celement tree:54;html 5 lib element tree:64;html 5 lib simple tree:98;html 5 lib minidom:192;石根:64人;html fill:5.5;html解析器:4.4

最後考驗的是記憶力。我不是特別確定我做這個測試的方法是否科學,但是數據總能說明壹些問題。該測試將解析所有文檔並將解析後的DOM樹保存在內存中,並使用ps命令結果的RSS(resident set size)段來表示進程占用的內存。在計算了基準內存使用量之後,所有的庫都已經被導入,所以只解析HTML和生成文檔對象會導致內存使用量的增加。

我只使用HTMLParser作為基線,因為它將文檔保存在內存中,並且只產生壹些中間字符串。最後這些中間字符串並不會占用太多內存,因為內存占用基本等於這些html要價的總和。

測量過程中有壹個棘手的問題是python的內存分配器不會釋放它請求的內存,所以如果壹個解析器創建了很多中間對象(字符串等。)然後釋放它們,這個過程仍然會保存這些記憶。為了檢測這種情況,我試圖分配壹些新的字符串來了解進程占用的內存增長(檢測已分配但未使用的內存),但實際上我沒有檢測到任何東西,只有BeautifulSoup解析器,當序列化為lxml樹時,顯示使用了額外的內存。

只有在內存測試中,html5lib才能顯示出使用cElementTree表示文檔對象和使用ElementTree的明顯區別。我並不驚訝。我猜是因為還沒有找到用C語言寫的序列化工具,所以只有在本地代碼中調用的時候使用cElementTree構建文檔樹更快(像本地libxml,也不需要把數據結構傳入python)。

Lxml節省內存可能是因為它使用libxml2的本地數據結構,並且只在必要時才創建Python對象。

摘要

我在基準測試之前就知道lxml會更快,但我自己也沒想到會這麽快。

所以,總結壹下:lxml很牛逼[2]。妳可以在很多方面使用它。妳可以解析,序列化,解析,反序列化壹個HTML,在機器卡頓之前,妳可以重復這些操作很多次。很多操作都是通過本地接口實現的,python只是做了壹個淺層的封裝。比如妳做壹個XPath查詢,查詢字符串會被編譯成本地代碼,然後遍歷本地的libxml2對象,只有當查詢結果返回時,才會生成壹個python對象。另外,lxml在測試中占用內存小,讓我更有理由相信lxml在高負載下依然會很可靠。

在我看來,文檔樹比按字符流解析更有優勢(不生成樹,只掃描文檔壹次,針對特定標簽進行處理)。表面上看,按字符流解析似乎更好:妳沒有把整個文檔放在內存中,處理時間與文檔大小成線性關系。HTMLParser就是這樣壹個解析器,遇到各種符號(標簽開始和結束,過渡中間的文本等。).石根也使用這種模式,因為它使用了壹些更先進的功能(如過濾器)

)所以用起來更自然。事實上,字符流模型本身並不是處理XML文檔的壹種特別自然的方式。在某種程度上,它只是壹種笨拙的方式來處理壹些可以被當作字符串處理的文檔(regex可以實現同樣的功能)。按字符流解析只有在需要處理G的XML文件時才有意義(雖然lxml和ElementTree都有額外的參數支持這種情況)。HTML文件不會這麽大,這些測試也有理由相信lxml可以很好地處理大HTML文件,所以壹個大文檔不會導致壹個針對小文檔優化的系統崩潰。

伊恩·比克2008年3月30日周日

[1].石根是EdgewallSoftware的產品,它的其他產品包括著名的Trac。

[2].本文作者Ian Bicking是lxml.html(lxml的壹個模塊)的開發者和維護者(此處正確)。

P.S .譯者註:這裏還有壹個解析器沒有提到,就是python標準庫中的SGMLParser,它也可以生成ElementTree,但是性能很差。本地測試解析壹個600k的html文檔(ddd的單頁html文檔)需要480秒,不建議在性能要求高的場合使用。本文作者也是lxml的作者,強烈推薦自己的作品很正常。我測過lxml的性能確實不錯。