python 提取html文本的方法


Posted in Python onMay 20, 2021

假设我们需要从各种网页中提取全文,并且要剥离所有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-8

from time import time

import warc
from bs4 import BeautifulSoup
from selectolax.parser import HTMLParser


def get_text_bs(html):
    tree = BeautifulSoup(html, 'lxml')

    body = tree.body
    if body is None:
        return None

    for tag in body.select('script'):
        tag.decompose()
    for tag in body.select('style'):
        tag.decompose()

    text = body.get_text(separator='\n')
    return text


def get_text_selectolax(html):
    tree = HTMLParser(html)

    if tree.body is None:
        return None

    for tag in tree.css('script'):
        tag.decompose()
    for tag in tree.css('style'):
        tag.decompose()

    text = tree.body.text(separator='\n')
    return text


def read_doc(record, parser=get_text_selectolax):
    url = record.url
    text = None

    if 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, text


def process_warc(file_name, parser, limit=10000):
    warc_file = warc.open(file_name, 'rb')
    t0 = time()
    n_documents = 0
    for i, record in enumerate(warc_file):
        url, doc = read_doc(record, parser)

        if not doc or not url:
            continue

        n_documents += 1

        if i > limit:
            break

    warc_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

显然,这并不是对某些事物进行基准测试的最佳方法,但是它提供了一个想法,即selectolax有时比lxml快30倍。
selectolax最适合将HTML剥离为纯文本。如果我有10,000多个HTML片段,需要将它们作为纯文本索引到Elasticsearch中。(Elasticsearch有一个html_strip文本过滤器,但这不是我想要/不需要在此上下文中使用的过滤器)。事实证明,以这种规模将HTML剥离为纯文本实际上是非常低效的。那么,最有效的方法是什么?

  • PyQuery
from pyquery import PyQuery as pq

text = pq(html).text()
  • selectolax
from selectolax.parser import HTMLParser

text = HTMLParser(html).text()
  • 正则表达式
import re

regex = re.compile(r'<.*?>')
text = clean_regex.sub('', html)

结果

我编写了一个脚本来计算时间,该脚本遍历包含HTML片段的10,000个文件。注意!这些片段不是完整的<html>文档(带有<head>和<body>等),只是HTML的一小部分。平均大小为10,314字节(中位数为5138字节)。结果如下:

pyquery
  SUM:    18.61 seconds
  MEAN:   1.8633 ms
  MEDIAN: 1.0554 ms
selectolax
  SUM:    3.08 seconds
  MEAN:   0.3149 ms
  MEDIAN: 0.1621 ms
regex
  SUM:    1.64 seconds
  MEAN:   0.1613 ms
  MEDIAN: 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个片段运行相同的基准时,新结果如下:

pyquery
  SUM:    21.70 seconds
  MEAN:   2.1701 ms
  MEDIAN: 1.3989 ms
selectolax
  SUM:    3.59 seconds
  MEAN:   0.3589 ms
  MEDIAN: 0.2184 ms
regex
  Skip

同样,selectolax击败PyQuery约6倍。

结论

正则表达式速度快,但功能弱。selectolax的效率令人印象深刻。

以上就是python 提取html文本的方法的详细内容,更多关于python 提取html文本的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python修改字典内key对应值的方法
Jul 11 Python
Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例
Aug 18 Python
Python如何实现MySQL实例初始化详解
Nov 06 Python
Tensorflow实现卷积神经网络用于人脸关键点识别
Mar 05 Python
Scrapy框架爬取西刺代理网免费高匿代理的实现代码
Feb 22 Python
Django单元测试中Fixtures用法详解
Feb 25 Python
Python 面向对象静态方法、类方法、属性方法知识点小结
Mar 09 Python
python实现mask矩阵示例(根据列表所给元素)
Jul 30 Python
详解如何在pyqt中通过OpenCV实现对窗口的透视变换
Sep 20 Python
python中random.randint和random.randrange的区别详解
Sep 20 Python
解决Pytorch半精度浮点型网络训练的问题
May 24 Python
python中redis包操作数据库的教程
Apr 19 Python
学会用Python实现滑雪小游戏,再也不用去北海道啦
pytorch 带batch的tensor类型图像显示操作
pytorch 中nn.Dropout的使用说明
May 20 #Python
Python 线程池模块之多线程操作代码
May 20 #Python
pytorch中[..., 0]的用法说明
May 20 #Python
浅谈pytorch中stack和cat的及to_tensor的坑
May 20 #Python
pytorch实现手写数字图片识别
You might like
PHP中对于浮点型的数据需要用不同的方法解决
2014/03/11 PHP
PHP小教程之实现链表
2014/06/09 PHP
PHP获取毫秒级时间戳的方法
2015/04/15 PHP
php生成mysql的数据字典
2016/07/07 PHP
php二维码生成以及下载实现
2017/09/28 PHP
javascript new fun的执行过程
2010/08/05 Javascript
jquery.cvtooltip.js 基于jquery的气泡提示插件
2010/11/19 Javascript
jQuery EasyUI API 中文文档 - Menu菜单
2011/10/03 Javascript
uploadify在Firefox下丢失session问题的解决方法
2013/08/07 Javascript
JS(JQuery)操作Array的相关方法介绍
2014/02/11 Javascript
jquery.idTabs 选项卡使用示例代码
2014/09/03 Javascript
JS拖拽组件学习使用
2016/01/19 Javascript
基于javascript html5实现3D翻书特效
2016/03/14 Javascript
javascript面向对象程序设计高级特性经典教程(值得收藏)
2016/05/19 Javascript
Bootstrap+jfinal退出系统弹出确认框的实现方法
2016/05/30 Javascript
Vue的百度地图插件尝试使用
2017/09/06 Javascript
在ES5与ES6环境下处理函数默认参数的实现方法
2018/05/13 Javascript
微信小程序实现手指触摸画板
2018/07/09 Javascript
nodejs如何在package.json中设置多条启动命令
2020/03/16 NodeJs
Vue中通过vue-router实现命名视图的问题
2020/04/23 Javascript
原生js实现九宫格拖拽换位
2021/01/26 Javascript
python实现求最长回文子串长度
2018/01/22 Python
python中的文件打开与关闭操作命令介绍
2018/04/26 Python
Python3 导入上级目录中的模块实例
2019/02/16 Python
Python-jenkins模块获取jobs的执行状态操作
2020/05/12 Python
使用Tensorflow-GPU禁用GPU设置(CPU与GPU速度对比)
2020/06/30 Python
python爬虫中PhantomJS加载页面的实例方法
2020/11/12 Python
Django Model层F,Q对象和聚合函数原理解析
2020/11/12 Python
高中毕业自我鉴定
2013/12/22 职场文书
就业意向书范文
2014/04/01 职场文书
2014年评职称工作总结
2014/11/20 职场文书
建议书格式
2015/02/04 职场文书
太空授课观后感
2015/06/17 职场文书
如何在centos上使用yum安装rabbitmq-server
2021/03/31 Servers
golang goroutine顺序输出方式
2021/04/29 Golang
Python内置的数据类型及使用方法
2022/04/13 Python