在 Python 中提取和清理 HTML 正文文本的最快、最无错误的方法是啥?

Posted

技术标签:

【中文标题】在 Python 中提取和清理 HTML 正文文本的最快、最无错误的方法是啥?【英文标题】:What is the fastest, most error-free method of extracting and cleaning the HTML body text in Python?在 Python 中提取和清理 HTML 正文文本的最快、最无错误的方法是什么? 【发布时间】:2016-06-17 04:00:48 【问题描述】:

我目前有两个函数可以从 Python 中提取 html <body> 文本并将其作为单词包返回。它们提供等效的输出。我还清理了各种标签,否则这些标签会给我带来垃圾文本(例如<script> 代码)。

def html_to_bow_bs(text):
    if text is None or len(text)==0:
        return []

    soup = BeautifulSoup(text, "lxml",parse_only=SoupStrainer('body'))

    # Remove all irrelevant tags
    for elem in soup.findAll(['script','style','a']):
        elem.extract()
    body_text = soup.findAll("body")
    if len(body_text) == 0:
        return []

    # Encoding.  Remove extra whitespace and unprintable characters
    the_text = body_text[0].get_text().encode('utf-8')
    the_text = str(the_text)
    the_text = the_text.strip()
    the_text = re.sub(r'[^\x00-\x7F]+',' ',the_text)
    return [w.lower() for w in the_text.split()]




def html_to_bow_bs_lxml(text):
    if text is None or len(text)==0:
        return []
    body_re = re.findall('<body(.*?)</body>', text, flags=re.DOTALL)
    if len(body_re) == 0:
        return []
    fragment = body_re[0]

    # Remove irrelevant tags
    fragment = re.sub(r'<script.*?</script>', ' ', fragment, flags=re.DOTALL)
    fragment = re.sub(r'<style.*?</style>', ' ', fragment, flags=re.DOTALL)
    text = "<body" + fragment + "</body>"
    soup = BeautifulSoup(text, "lxml")

    if soup is None:
        return []

    # Remote more irrelevant tags
    for elem in soup.findAll(['a']):
        elem.extract()

    # Encoding.  Remove extra whitespace and unprintable characters
    the_text = body_text[0].get_text().encode('utf-8')
    the_text = str(the_text)
    the_text = the_text.strip()
    the_text = re.sub(r'[^\x00-\x7F]+',' ',the_text)
    return [w.lower() for w in the_text.split()]

我的主要要求是匹配输出:来自html_to_bow_bs_lxml(text) 的单词集匹配html_to_bow_bs(text)。目前,两者在运行时间上持平;对于 330 页,它们运行大约 20 秒(慢!)。如果我删除并用正则表达式替换我的第二个函数中的最后一个soup.findAll(['a'])...extract(),我可以节省 6 秒的时间。将BeautifulSoup 完全替换为lxml.etree 可以额外节省10 秒,使总运行时间约为3-4 秒。但是,当用正则表达式替换时,

    输出并不总是匹配。替换 BeautifulSoup 时,输出不匹配或 由于 HTML 格式不正确,我的程序在处理过程中崩溃。如何在保持正确性的同时提高速度?

我在 *** 上看到了各种使用 Python 提取 HTML 的建议,但这些建议可以追溯到几年前(例如 2012 年)。从那时起,库进行了许多更新,这是可以理解的。

(我也尝试过 pyquery,但它并不总是能正确提取正文。)

【问题讨论】:

【参考方案1】:

使用 requests 模块和 bs4

这是打印正文的最简单方法。

import requests
from bs4 import BeautifulSoup
url = "yourUrl"
r = requests.get(url)
soup = BeautifulSoup(r.content, 'lxml')
items = soup.find_all('body')
for item in items:
    print item.text

注意:如果你打印所有正文,它也会打印 jquery 和 javascript 函数,以防万一。

【讨论】:

不幸的是,由于 jQuery 和 JavaScript 将包含在输出中,这不符合上述规范。我们也可以假设 HTML 文本被输入到函数中,所以 import requests 不是必需的。【参考方案2】:

您已经做了很多工作来加快速度 - 汤过滤器和 lxml 解析器通常是使用 BeautifulSoup 优化解析时要尝试的第一件事。

这里是对这个特定代码的一些改进。

删除body存在检查:

body_text = soup.findAll("body")
if len(body_text) == 0:
    return []

改用find()

if text is None or len(text)==0: 替换为if not text:

通过get_text(strip=True)剥离。


改进后的代码:

def html_to_bow_bs(text):
    if not text:
        return []

    soup = BeautifulSoup(text, "lxml", parse_only=SoupStrainer('body'))

    # Remove all irrelevant tags
    for elem in soup.find_all(['script','style','a']):
        elem.extract()

    body = soup.find("body")
    if not body:
        return []

    the_text = body.get_text(strip=True).encode('utf-8')
    the_text = re.sub(r'[^\x00-\x7F]+', ' ', the_text)
    return [w.lower() for w in the_text.split()]

这些只是微小的改进,我认为它们不会改变整体性能图景。我还会研究的内容:

通过pypy 运行脚本(beautifulsoup4 是compatible,但您将无法使用lxml 解析器 - 尝试使用html.parserhtml5lib)。甚至根本不修改代码,您可能会赢得很多。

【讨论】:

谢谢!看起来有一些增量改进。但是,body.get_text(strip=True) 给出的字数比将get_text()strip() 分成两个不同的函数要少得多。我将其替换为' '.join([text for text in body.stripped_strings]).encode('utf-8') 提供了更多我的方法实际上遗漏的单词。不过,此编辑以及上述编辑提供了几乎相同的运行时性能。 @Matt 是的,谢谢,我没想到这些变化会带来很大的性能提升。 pypy 呢? 目前正在尝试。抱歉,评论空间用完了。 :) 哇,pypy 让我的性能提升了一半,令人印象深刻。不幸的是,它与我的其他一些库不兼容(pandas 用于数据分析),但我将把它标记为解决方案。谢谢!

以上是关于在 Python 中提取和清理 HTML 正文文本的最快、最无错误的方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

从 MBOX 文件中提取纯文本/文本和 html 正文到列表

Python - 从纯文本邮件中提取正文

python通用论坛正文提取python论坛评论提取python论坛用户信息提取

从 HTML 正文中提取文本片段(在 .NET 中)

从网站中提取正文文本,例如仅提取文章标题和文本而不是站点中的所有文本

python 解析docx文档的方法,以及提取插入的文本对象和图片