【问题标题】:BeautifulSoup get_text does not strip all tags and JavaScriptBeautifulSoup get_text 不会去除所有标签和 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 更适合这项任务的替代品?我想要的只是提取将在浏览器中为该网页呈现的文本。

任何帮助将不胜感激。

【问题讨论】:

  • 谢谢,我问的时候还没有看到。它确实指向了一个好的方向,但它并不完美,因为它不会删除所有 JS 和 cmets。

标签: python html xml screen-scraping beautifulsoup


【解决方案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('\s{2,}|&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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    • 2019-12-20
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多