python 提取html文本的方法
假設(shè)我們需要從各種網(wǎng)頁中提取全文,并且要剝離所有HTML標記。通常,默認解決方案是使用BeautifulSoup軟件包中的get_text方法,該方法內(nèi)部使用lxml。這是一個經(jīng)過充分測試的解決方案,但是在處理成千上萬個HTML文檔時可能會非常慢。
通過用selectolax替換BeautifulSoup,您幾乎可以免費獲得5-30倍的加速!
這是一個簡單的基準測試,可分析commoncrawl(`處理NLP問題時,有時您需要獲得大量的文本集?;ヂ?lián)網(wǎng)是文本的最大來源,但是不幸的是,從任意HTML頁面提取文本是一項艱巨而痛苦的任務(wù)。
假設(shè)我們需要從各種網(wǎng)頁中提取全文,并且要剝離所有HTML標記。通常,默認解決方案是使用BeautifulSoup軟件包中的get_text方法,該方法內(nèi)部使用lxml。這是一個經(jīng)過充分測試的解決方案,但是在處理成千上萬個HTML文檔時可能會非常慢。
通過用selectolax替換BeautifulSoup,您幾乎可以免費獲得5-30倍的加速!這是一個簡單的基準測試,可分析commoncrawl(https://commoncrawl.org/)的10,000個HTML頁面:
#coding:utf-8 fromtimeimporttime importwarc frombs4importBeautifulSoup fromselectolax.parserimportHTMLParser defget_text_bs(html): tree=BeautifulSoup(html,'lxml') body=tree.body ifbodyisNone: returnNone fortaginbody.select('script'): tag.decompose() fortaginbody.select('style'): tag.decompose() text=body.get_text(separator='\n') returntext defget_text_selectolax(html): tree=HTMLParser(html) iftree.bodyisNone: returnNone fortagintree.css('script'): tag.decompose() fortagintree.css('style'): tag.decompose() text=tree.body.text(separator='\n') returntext defread_doc(record,parser=get_text_selectolax): url=record.url text=None ifurl: payload=record.payload.read() header,html=payload.split(b'\r\n\r\n',maxsplit=1) html=html.strip() iflen(html)>0: text=parser(html) returnurl,text defprocess_warc(file_name,parser,limit=10000): warc_file=warc.open(file_name,'rb') t0=time() n_documents=0 fori,recordinenumerate(warc_file): url,doc=read_doc(record,parser) ifnotdocornoturl: continue n_documents+=1 ifi>limit: break warc_file.close() print('Parser:%s'%parser.__name__) print('Parsingtook%ssecondsandproduced%sdocuments\n'%(time()-t0,n_documents))
>>>!wgethttps://commoncrawl.s3.amazonaws.com/crawl-data/CC-MAIN-2018-05/segments/1516084886237.6/warc/CC-MAIN-20180116070444-20180116090444-00000.warc.gz >>>file_name="CC-MAIN-20180116070444-20180116090444-00000.warc.gz" >>>process_warc(file_name,get_text_selectolax,10000) Parser:get_text_selectolax Parsingtook16.170367002487183secondsandproduced3317documents >>>process_warc(file_name,get_text_bs,10000) Parser:get_text_bs Parsingtook432.6902508735657secondsandproduced3283documents
顯然,這并不是對某些事物進行基準測試的最佳方法,但是它提供了一個想法,即selectolax有時比lxml快30倍。
selectolax最適合將HTML剝離為純文本。如果我有10,000多個HTML片段,需要將它們作為純文本索引到Elasticsearch中。(Elasticsearch有一個html_strip文本過濾器,但這不是我想要/不需要在此上下文中使用的過濾器)。事實證明,以這種規(guī)模將HTML剝離為純文本實際上是非常低效的。那么,最有效的方法是什么?
- PyQuery
frompyqueryimportPyQueryaspq text=pq(html).text()
- selectolax
fromselectolax.parserimportHTMLParser text=HTMLParser(html).text()
- 正則表達式
importre regex=re.compile(r'<.*?>') text=clean_regex.sub('',html)
結(jié)果
我編寫了一個腳本來計算時間,該腳本遍歷包含HTML片段的10,000個文件。注意!這些片段不是完整的<html>文檔(帶有<head>和<body>等),只是HTML的一小部分。平均大小為10,314字節(jié)(中位數(shù)為5138字節(jié))。結(jié)果如下:
pyquery SUM:18.61seconds MEAN:1.8633ms MEDIAN:1.0554ms selectolax SUM:3.08seconds MEAN:0.3149ms MEDIAN:0.1621ms regex SUM:1.64seconds MEAN:0.1613ms MEDIAN:0.0881ms
我已經(jīng)運行了很多次,結(jié)果非常穩(wěn)定。重點是:selectolax比PyQuery快7倍。
正則表達式好用?真的嗎?
對于最基本的HTML Blob,它可能工作得很好。實際上,如果HTML是<p> Foo&amp; Bar </ p>,我希望純文本轉(zhuǎn)換應(yīng)該是Foo&Bar,而不是Foo&amp; bar。
更重要的一點是,PyQuery和selectolax支持非常特定但對我的用例很重要的內(nèi)容。在繼續(xù)之前,我需要刪除某些標簽(及其內(nèi)容)。例如:
<h4class="warning">Thisshouldgetstripped.</h4> <p>Pleasekeep.</p> <divstyle="display:none">Thisshouldalsogetstripped.</div>
正則表達式永遠無法做到這一點。
2.0 版本
因此,我的要求可能會發(fā)生變化,但基本上,我想刪除某些標簽。例如:<div class =“ warning”> 、 <div class =“ hidden”> 和 <div style =“ display:none”>。因此,讓我們實現(xiàn)一下:
- PyQuery
frompyqueryimportPyQueryaspq _display_none_regex=re.compile(r'display:\s*none') doc=pq(html) doc.remove('div.warning,div.hidden') fordivindoc('div[style]').items(): style_value=div.attr('style') if_display_none_regex.search(style_value): div.remove() text=doc.text()
- selectolax
fromselectolax.parserimportHTMLParser _display_none_regex=re.compile(r'display:\s*none') tree=HTMLParser(html) fortagintree.css('div.warning,div.hidden'): tag.decompose() fortagintree.css('div[style]'): style_value=tag.attributes['style'] ifstyle_valueand_display_none_regex.search(style_value): tag.decompose() text=tree.body.text()
這實際上有效。當我現(xiàn)在為10,000個片段運行相同的基準時,新結(jié)果如下:
pyquery SUM:21.70seconds MEAN:2.1701ms MEDIAN:1.3989ms selectolax SUM:3.59seconds MEAN:0.3589ms MEDIAN:0.2184ms regex Skip
同樣,selectolax擊敗PyQuery約6倍。
結(jié)論
正則表達式速度快,但功能弱。selectolax的效率令人印象深刻。
以上就是python 提取html文本的方法的詳細內(nèi)容,更多關(guān)于python 提取html文本的資料請關(guān)注本站其它相關(guān)文章!
版權(quán)聲明:本站文章來源標注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。