BeautifulSoup get_text不会删除所有标记和JavaScript

时间:2012-05-09 21:31:50

标签: python html xml screen-scraping beautifulsoup

我正在尝试使用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可以更好地完成这项任务?我想要的只是提取将在此网页的浏览器中呈现的文本。

任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:13)

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

答案 1 :(得分:1)

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

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)

答案 2 :(得分:1)

这就是我遇到的问题。没有解决方案似乎能够返回文本(实际上将在web broswer中呈现的文本)。其他解决方案提到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