7

我正在尝试使用 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 更适合这项任务的替代品?我想要的只是提取将在浏览器中为该网页呈现的文本。

任何帮助都感激不尽。

4

3 回答 3

14

nltk'sclean_html()在这方面做得很好!

假设您已经将 html 存储在一个变量中,html例如

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

然后只需使用

import nltk
clean_text = nltk.clean_html(html)

更新

对 nltk 未来版本的支持clean_html并将被删除。clean_url请暂时使用 BeautifulSoup ......这很不幸。

此页面上有一个如何实现此目的的示例:

BeatifulSoup4 get_text 仍然有 javascript

于 2012-11-14T19:48:38.470 回答
2

这是我遇到的问题。似乎没有解决方案能够返回文本(实际上将在网络浏览器中呈现的文本)。其他解决方案提到 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
于 2013-11-05T17:48:52.277 回答
2

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

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)
于 2012-05-10T22:58:00.707 回答