Python 高效提取 HTML 文本的方法
在解决自然语言处理问题时,有时你需要获得大量的文本集。互联网是文本的最大来源,但是从任意HTML页面提取文本是一项艰巨而痛苦的任务。
假设我们需要从各种网页中提取全文,并且要剥离所有HTML标记。通常,默认解决方案是使用BeautifulSoup
软件包中的get_text
方法,该方法内部使用lxml
。这是一个经过充分测试的解决方案,但是在处理成千上万个HTML文档时可能会非常慢。
通过用selectolax
替换BeautifulSoup
,您几乎可以免费获得5-30倍的加速!
这是一个简单的基准测试,可分析commoncrawl(`处理NLP问题时,有时您需要获得大量的文本集。互联网是文本的最大来源,但是不幸的是,从任意HTML页面提取文本是一项艰巨而痛苦的任务。
假设我们需要从各种网页中提取全文,并且要剥离所有HTML标记。通常,默认解决方案是使用BeautifulSoup
软件包中的get_text
方法,该方法内部使用lxml
。这是一个经过充分测试的解决方案,但是在处理成千上万个HTML文档时可能会非常慢。
通过用selectolax
替换BeautifulSoup
,您几乎可以免费获得5-30倍的加速!这是一个简单的基准测试,可分析commoncrawl(https://commoncrawl.org/
)的10,000个HTML页面:
# coding: utf-8from time import timeimport warc
from bs4 import BeautifulSoup
from selectolax.parser import HTMLParserdef get_text_bs(html):tree = BeautifulSoup(html, 'lxml')body = tree.bodyif body is None:return Nonefor tag in body.select('script'):tag.decompose()for tag in body.select('style'):tag.decompose()text = body.get_text(separator='\n')return textdef get_text_selectolax(html):tree = HTMLParser(html)if tree.body is None:return Nonefor tag in tree.css('script'):tag.decompose()for tag in tree.css('style'):tag.decompose()text = tree.body.text(separator='\n')return textdef read_doc(record, parser=get_text_selectolax):url = record.urltext = Noneif url:payload = record.payload.read()header, html = payload.split(b'\r\n\r\n', maxsplit=1)html = html.strip()if len(html) > 0:text = parser(html)return url, textdef process_warc(file_name, parser, limit=10000):warc_file = warc.open(file_name, 'rb')t0 = time()n_documents = 0for i, record in enumerate(warc_file):url, doc = read_doc(record, parser)if not doc or not url:continuen_documents += 1if i > limit:breakwarc_file.close()print('Parser: %s' % parser.__name__)print('Parsing took %s seconds and produced %s documents\n' % (time() - t0, n_documents))
>>> ! wget https://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
Parsing took 16.170367002487183 seconds and produced 3317 documents
>>> process_warc(file_name, get_text_bs, 10000)
Parser: get_text_bs
Parsing took 432.6902508735657 seconds and produced 3283 documents
很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:**810735403**
显然,这并不是对某些事物进行基准测试的最佳方法,但是它提供了一个想法,即selectolax
有时比lxml
快30倍。
selectolax
最适合将HTML剥离为纯文本。如果我有10,000多个HTML片段,需要将它们作为纯文本索引到Elasticsearch中。(Elasticsearch有一个html_strip
文本过滤器,但这不是我想要/不需要在此上下文中使用的过滤器)。事实证明,以这种规模将HTML剥离为纯文本实际上是非常低效的。那么,最有效的方法是什么?
PyQuery
from pyquery import PyQuery as pqtext = pq(html).text()
selectolax
from selectolax.parser import HTMLParsertext = HTMLParser(html).text()
正则表达式
import reregex = re.compile(r'<.*?>')
text = clean_regex.sub('', html)
结果
我编写了一个脚本来计算时间,该脚本遍历包含HTML片段的10,000个文件。注意!这些片段不是完整的<html>
文档(带有<head>
和<body>
等),只是HTML的一小部分。平均大小为10,314字节(中位数为5138字节)。结果如下:
pyquerySUM: 18.61 secondsMEAN: 1.8633 msMEDIAN: 1.0554 ms
selectolaxSUM: 3.08 secondsMEAN: 0.3149 msMEDIAN: 0.1621 ms
regexSUM: 1.64 secondsMEAN: 0.1613 msMEDIAN: 0.0881 ms
我已经运行了很多次,结果非常稳定。重点是:selectolax
比PyQuery
快7倍。
正则表达式好用?真的吗?
对于最基本的HTML Blob
,它可能工作得很好。实际上,如果HTML是<p> Foo&amp; Bar </ p>
,我希望纯文本转换应该是Foo&Bar
,而不是Foo&amp; bar
。
更重要的一点是,PyQuery和selectolax支持非常特定但对我的用例很重要的内容。在继续之前,我需要删除某些标签(及其内容)。例如:
<h4 class="warning">This should get stripped.</h4>
<p>Please keep.</p>
<div style="display: none">This should also get stripped.</div>
正则表达式永远无法做到这一点。
2.0 版本
因此,我的要求可能会发生变化,但基本上,我想删除某些标签。例如:<div class =“ warning”>
、 <div class =“ hidden”>
和 <div style =“ display:none”>
。因此,让我们实现一下:
PyQuery
from pyquery import PyQuery as pq_display_none_regex = re.compile(r'display:\s*none')doc = pq(html)
doc.remove('div.warning, div.hidden')
for div in doc('div[style]').items():style_value = div.attr('style')if _display_none_regex.search(style_value):div.remove()
text = doc.text()
selectolax
from selectolax.parser import HTMLParser_display_none_regex = re.compile(r'display:\s*none')tree = HTMLParser(html)
for tag in tree.css('div.warning, div.hidden'):tag.decompose()
for tag in tree.css('div[style]'):style_value = tag.attributes['style']if style_value and _display_none_regex.search(style_value):tag.decompose()
text = tree.body.text()
这实际上有效。当我现在为10,000个片段运行相同的基准时,新结果如下:
pyquerySUM: 21.70 secondsMEAN: 2.1701 msMEDIAN: 1.3989 ms
selectolaxSUM: 3.59 secondsMEAN: 0.3589 msMEDIAN: 0.2184 ms
regexSkip
同样,selectolax击败PyQuery约6倍。
结论
正则表达式速度快,但功能弱。selectolax
的效率令人印象深刻。
在这里还是要推荐下我自己建的Python开发交流学习(qq)群:810735403
,群里都是学Python开发的,如果你正在学习Python ,欢迎你加入,大家都是软件开发党,不定期分享干货(只有Python软件开发相关的),包括我自己整理的一份2021最新的Python进阶资料和高级开发教程,欢迎进阶中和想深入Python的小伙伴!
Python 高效提取 HTML 文本的方法相关推荐
- python提取html正文为txt,python 提取html文本的方法
假设我们需要从各种网页中提取全文,并且要剥离所有HTML标记.通常,默认解决方案是使用BeautifulSoup软件包中的get_text方法,该方法内部使用lxml.这是一个经过充分测试的解决方案, ...
- python怎么读取pdf为文本_轻松用Python批量提取PDF文本内容,这个小技巧告诉你!...
轻松用Python批量提取PDF文本内容,这个小技巧告诉你!-1.jpg (22.73 KB, 下载次数: 0) 2018-9-7 08:33 上传 本文为你展示,如何用Python把许多PDF文件的 ...
- python读取中文txt文本-python读取中文txt文本的方法
对于python2.7 字符串在Python2.7内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码成unicode,再从unico ...
- python怎么读中文-python读取中文txt文本的方法
对于python2.7 字符串在Python2.7内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码成unicode,再从unico ...
- python离线语音转文本_使用Python将语音转换为文本的方法
使用Python将语音转换为文本的方法,语音,转换为,文本,您的,麦克风 使用Python将语音转换为文本的方法 易采站长站,站长之家为您整理了使用Python将语音转换为文本的方法的相关内容. 语音 ...
- python txt默认读取字符还是行,python读取中文txt文本的方法
字符串在Python2.7内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码成unicode,再从unicode编码成另一种编码. ...
- python如何读取中文文件-python读取中文txt文本的方法
对于python2.7 字符串在Python2.7内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码成unicode,再从unico ...
- 如何用Python批量提取PDF文本内容?
本文为你展示,如何用Python把许多PDF文件的文本内容批量提取出来,并且整理存储到数据框中,以便于后续的数据分析. 问题 最近,读者们在后台的留言,愈发五花八门了. 写了几篇关于自然语言处理的文章 ...
- python 如何批量提取文件中的字符_如何用Python批量提取PDF文本内容?
本文为你展示,如何用Python把许多PDF文件的文本内容批量提取出来,并且整理存储到数据框中,以便于后续的数据分析. 问题 最近,读者们在后台的留言,愈发五花八门了. 写了几篇关于自然语言处理的文章 ...
最新文章
- 使用Process.Start打开文件夹或网页
- 页面导航的两种方式——声明式导航、编程式导航||vue-router编程式导航||router.push() 方法的参数规则
- mysqldatareader获取整行数据给datarow_C# sqladapter 与sqldataReader
- SwiftUI之如何使用@EnvironmentObject在视图之间共享数据
- linux composer使用php,记录linux下composer使用的坑爹过程
- OSPFv3中LSA详解(八)——Type5类LSA详解
- 概率论-1.4 条件概率(重点:对P(A | B)、P(AB)、P(B)之间关系的理解)
- 结对项目-数独程序扩展
- 一日一签免费算卦_一日一签app免费算卦
- 六大类二叉树面试题汇总解答
- cousins什么意思_cousin是什么意思_cousin的翻译_音标_读音_用法_例句_爱词霸在线词典...
- 如何学习投资 推荐几本教材
- 《C系列-实践相关》C语言十
- Mac Terminal 终端:入门指南及进阶技巧
- 输入10个数字,然后逆序输出。
- ubuntu 里安装 OracleXE
- linux版本市场占有率,2020年5月OS市场占有率报告:Ubuntu和Linux分别占有1.89%和0.97%...
- python手工打码_使用Python + Selenium破解滑块验证码
- 《计算机系统与维护》— 计算机硬件的组成
- 计算机毕业设计SSM房屋租赁系统【附源码数据库】
热门文章
- 抗渗等级p6是什么意思_混凝土抗渗等级w4是什么意思?
- Candence中查看MOS管阈值电压Vth、Vgs、Vds、跨导gm、Id等详细MOS参数的方法
- 详解pandas编码函数pd.factorize()
- 崔希凡JavaWeb笔记day19-day21(2016年10月4日17:35:51)
- android支付宝系统繁忙,支付宝支付 系统繁忙,请稍后再试 62008 难道没人碰到过吗...
- 网络对抗技术 实验三
- angularjs2大漠穷秋视频笔记整理
- note-PythonCookbook-第十一章 网络与WEB编程
- UML工具Visual Paradigm最新版本16.2发布
- 工程化框架之feather