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处理json数据中的中文
Mar 06 Python
python去除所有html标签的方法
May 05 Python
Python向日志输出中添加上下文信息
May 24 Python
python的构建工具setup.py的方法使用示例
Oct 23 Python
python3处理含有中文的url方法
May 10 Python
python删除文本中行数标签的方法
May 31 Python
Appium Python自动化测试之环境搭建的步骤
Jan 23 Python
Python3.5基础之函数的定义与使用实例详解【参数、作用域、递归、重载等】
Apr 26 Python
Python之pymysql的使用小结
Jul 01 Python
浅谈matplotlib 绘制梯度下降求解过程
Jul 12 Python
Python如何使用vars返回对象的属性列表
Oct 17 Python
如何将Pycharm中调整字体大小的方式设置为&quot;ctrl+鼠标滚轮上下滑&quot;
Nov 17 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
gd库图片下载类实现下载网页所有图片的php代码
2012/08/20 PHP
php获取指定日期之间的各个周和月的起止时间
2014/11/24 PHP
php设计模式之委托模式
2016/02/13 PHP
PHP的openssl加密扩展使用小结(推荐)
2016/07/18 PHP
PHP设计模式之装饰器模式定义与用法详解
2018/04/02 PHP
详解PHP中的8个魔术常量
2020/07/06 PHP
JavaScript与C# Windows应用程序交互方法
2007/06/29 Javascript
IE 下的只读 innerHTML
2009/08/21 Javascript
使用jQuery内容过滤选择器选择元素实例讲解
2013/04/18 Javascript
Extjs中RowExpander控件的默认展开问题示例探讨
2014/01/24 Javascript
javascript实现Table间隔色以及选择高亮(和动态切换数据)的方法
2015/05/14 Javascript
jquery中map函数遍历数组用法实例
2015/05/18 Javascript
javascript中传统事件与现代事件
2015/06/23 Javascript
javascript实现的字符串与十六进制表示字符串相互转换方法
2015/07/17 Javascript
举例讲解如何判断JavaScript中对象的类型
2016/04/22 Javascript
Bootstrap嵌入jqGrid,使你的table牛逼起来
2016/05/05 Javascript
js实现带农历和八字等信息的日历特效
2016/05/16 Javascript
怎样判断jQuery当前元素是隐藏还是显示
2016/11/23 Javascript
详解vue项目的构建,打包,发布全过程
2017/11/23 Javascript
用Cordova打包Vue项目的方法步骤
2019/02/02 Javascript
JavaScript中var的重要性实例分析
2019/07/09 Javascript
详解Vue3.0 + TypeScript + Vite初体验
2021/02/22 Vue.js
[04:59]DOTA2-DPC中国联赛 正赛 Ehome vs iG 选手采访
2021/03/11 DOTA
python中使用smtplib和email模块发送邮件实例
2014/04/22 Python
Python第三方库xlrd/xlwt的安装与读写Excel表格
2017/01/21 Python
python安装Scrapy图文教程
2017/08/14 Python
Python爬虫实例_城市公交网络站点数据的爬取方法
2018/01/10 Python
Python二进制串转换为通用字符串的方法
2018/07/23 Python
李维斯德国官方网上商店:Levi’s德国
2016/09/10 全球购物
美国领先的在线邮轮旅游公司:CruiseDirect
2018/06/07 全球购物
施工安全标语
2014/06/07 职场文书
国庆宣传标语
2014/06/30 职场文书
2015年公司工作总结
2015/04/25 职场文书
社区党员干部承诺书
2015/05/04 职场文书
python微信智能AI机器人实现多种支付方式
2022/04/12 Python
Win11 Beta 预览版 22621.575 和 22622.575更新补丁KB5016694发布(附更新内容大全)
2022/08/14 数码科技