BeautifulSoup get_text 不会去除所有标签和 JavaScript

Posted

技术标签:

【中文标题】BeautifulSoup get_text 不会去除所有标签和 JavaScript【英文标题】:BeautifulSoup get_text does not strip all tags and JavaScript 【发布时间】:2012-05-18 10:59:42 【问题描述】:

我正在尝试使用 BeautifulSoup 从网页中获取文本。

下面是我为此编写的脚本。它有两个参数,第一个是输入的 html 或 XML 文件,第二个是输出文件。

import sys
from bs4 import BeautifulSoup

def stripTags(s): return BeautifulSoup(s).get_text()

def stripTagsFromFile(inFile, outFile):
    open(outFile, 'w').write(stripTags(open(inFile).read()).encode("utf-8"))

def main(argv):
    if len(sys.argv) <> 3:
        print 'Usage:\t\t', sys.argv[0], 'input.html output.txt'
        return 1
    stripTagsFromFile(sys.argv[1], sys.argv[2])
    return 0

if __name__ == "__main__":
    sys.exit(main(sys.argv))

不幸的是,对于许多网页,例如:http://www.greatjobsinteaching.co.uk/career/134112/Education-Manager-Location 我得到了这样的东西(我只显示了几行第一行):

html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    Education Manager  Job In London With  Caleeda | Great Jobs In Teaching

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-15255540-21']);
_gaq.push(['_trackPageview']);
_gaq.push(['_trackPageLoadTime']);

我的脚本有什么问题吗?我试图将“xml”作为第二个参数传递给 BeautifulSoup 的构造函数,以及“html5lib”和“lxml”,但它没有帮助。 有没有比 BeautifulSoup 更适合这项任务的替代品?我想要的只是提取将在浏览器中为该网页呈现的文本。

任何帮助将不胜感激。

【问题讨论】:

可能重复:***.com/questions/1936466/… 谢谢,我问的时候还没有看到。它确实指向了一个好的方向,但它并不完美,因为它不会删除所有 JS 和 cmets。 【参考方案1】:

nltk 的clean_html() 很擅长这个!

假设您已经将 html 存储在变量 html

html = urllib.urlopen(address).read()

然后就用

import nltk
clean_text = nltk.clean_html(html)

更新

未来版本的 nltk 将不再支持 clean_htmlclean_url。请暂时使用 BeautifulSoup...这很不幸。

有关如何实现此目的的示例在此页面上:

BeatifulSoup4 get_text still has javascript

【讨论】:

看来nltk以后不支持清理html了:github.com/nltk/nltk/commit/… 太糟糕了,支持被放弃了。这是 nltk 中一个非常有用的功能。【参考方案2】:

这是一种基于此处答案的方法:BeautifulSoup Grab Visible Webpage Text by jbochi。这种方法允许将 cmets 嵌入包含页面文本的元素中,并通过去除换行符、合并空格等来清理输出。

html = urllib.urlopen(address).read()
soup = BeautifulSoup.BeautifulSoup(html)
texts = soup.findAll(text=True)

def visible_text(element):
    if element.parent.name in ['style', 'script', '[document]', 'head', 'title']:
        return ''
    result = re.sub('<!--.*-->|\r|\n', '', str(element), flags=re.DOTALL)
    result = re.sub('\s2,|&nbsp;', ' ', result)
    return result

visible_elements = [visible_text(elem) for elem in texts]
visible_text = ''.join(visible_elements)
print(visible_text)

【讨论】:

谢谢,但是你用我提供的示例 URL 测试了吗? 是的,它似乎对我有用。你有问题吗? 是的,问题是,示例网页的脚本输出开头为:'IFRAME class="nsframe" scrolling="no" frameborder="0">',然后是带有 JavaScript 代码的 【参考方案3】:

这就是我遇到的问题。似乎没有解决方案能够返回文本(实际上将在网络浏览器中呈现的文本)。其他解决方案提到 BS 不适合渲染,而 html2text 是一个很好的方法。我尝试了 html2text 和 nltk.clean_html 并且对计时结果感到惊讶,因此认为他们需要为后代提供答案。当然,速度增量​​可能在很大程度上取决于数据的内容......

@Helge 的一个答案是关于使用所有事物的 nltk。

import nltk

%timeit nltk.clean_html(html)
was returning 153 us per loop

返回带有渲染 html 的字符串非常有效。这个 nltk 模块甚至比 html2text 还要快,尽管 html2text 可能更健壮。

betterHTML = html.decode(errors='ignore')
%timeit html2text.html2text(betterHTML)
%3.09 ms per loop

【讨论】:

以上是关于BeautifulSoup get_text 不会去除所有标签和 JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

Beautifulsoup - get_text,单行输出

来自 find_all 的 BeautifulSoup get_text

Python 3.8 - BeautifulSoup 4 - unwrap() 不会删除所有标签

无法使用BeautifulSoup获取div和meta标记的内容

.text 和 .get_text() 之间的区别

BeautifulSoup基础