BeautifulSoup抓住可见的网页文本

基本上,我想使用BeautifulSoup来严格地抓住网页上的可见文本 。 比如说, 这个网页就是我的testing用例。 我主要是想获得正文(文章),甚至可以在这里和那里的几个标签名称。 我已经在这个问题中尝试了这个build议,它返回了很多我不想要的<script>标记和html注释。 我无法弄清楚函数findAll()所需的参数,以便在网页上获取可见的文本。

那么,我应该如何find所有可见的文本,不包括脚本,评论,CSS等?

尝试这个:

 from bs4 import BeautifulSoup from bs4.element import Comment import urllib def tag_visible(element): if element.parent.name in ['style', 'script', 'head', 'title', 'meta', '[document]']: return False if isinstance(element, Comment): return False return True def text_from_html(body): soup = BeautifulSoup(body, 'html.parser') texts = soup.findAll(text=True) visible_texts = filter(tag_visible, texts) return u" ".join(t.strip() for t in visible_texts) html = urllib.urlopen('http://www.nytimes.com/2009/12/21/us/21storm.html').read() print(text_from_html(html)) 

@ jbochi的批准答案不适合我。 str()函数调用引发exception,因为它不能编码BeautifulSoup元素中的非ASCII字符。 以下是将示例网页过滤为可见文本的更简洁的方法。

 html = open('21storm.html').read() soup = BeautifulSoup(html) [s.extract() for s in soup(['style', 'script', '[document]', 'head', 'title'])] visible_text = soup.getText() 
 import urllib from bs4 import BeautifulSoup url = "https://www.yahoo.com" html = urllib.urlopen(url).read() soup = BeautifulSoup(html) # kill all script and style elements for script in soup(["script", "style"]): script.extract() # rip it out # get text text = soup.get_text() # break into lines and remove leading and trailing space on each lines = (line.strip() for line in text.splitlines()) # break multi-headlines into a line each chunks = (phrase.strip() for line in lines for phrase in line.split(" ")) # drop blank lines text = '\n'.join(chunk for chunk in chunks if chunk) print(text.encode('utf-8')) 

我完全尊重使用美丽的汤来获取渲染的内容,但它可能不是获取页面上呈现的内容的理想的包。

我有一个类似的问题获得渲染的内容,或典型的浏览器中的可见内容。 特别是我有许多非典型的案例可以用下面这样一个简单的例子来工作。 在这种情况下,不可显示的标签嵌套在一个样式标签中,并且在我检查过的许多浏览器中不可见。 存在其他变体,例如将类别标签设置显示定义为无。 然后使用这个类的div。

 <html> <title> Title here</title> <body> lots of text here <p> <br> <h1> even headings </h1> <style type="text/css"> <div > this will not be visible </div> </style> </body> </html> 

上面的一个解决scheme是:

 html = Utilities.ReadFile('simple.html') soup = BeautifulSoup.BeautifulSoup(html) texts = soup.findAll(text=True) visible_texts = filter(visible, texts) print(visible_texts) [u'\n', u'\n', u'\n\n lots of text here ', u' ', u'\n', u' even headings ', u'\n', u' this will not be visible ', u'\n', u'\n'] 

这个解决scheme在许多情况下肯定有应用程序,而且通常做得非常好,但是在上面贴出的HTML中,它保留了未呈现的文本。 search后,一些解决scheme出现在这里BeautifulSoup get_text不会去除所有的标签和JavaScript ,在这里使用Python将HTML呈现为纯文本

我尝试了这两个解决scheme:html2text和nltk.clean_html,并对时间结果感到惊讶,所以认为他们应该为后代的答案。 当然,速度高度依赖于数据的内容。

@Helge的一个答案就是关于使用nltk的所有东西。

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

它非常好地返回一个string与呈现的HTML。 这个nltk模块甚至比html2text更快,不过也许html2text更强大。

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

使用BeautifulSoup最简单的方法,用较less的代码来获取string,没有空行和废话。

 tag = <Parent_Tag_that_contains_the_data> soup = BeautifulSoup(tag, 'html.parser') for i in soup.stripped_strings: print repr(i) 

虽然,我会完全build议一般使用美丽的汤,如果有人正在寻找显示一个格式不正确的HTML的可见部分(例如,你只是一个网页段或行),无论出于何种原因,以下将删除<>标签之间的内容:

 import re ## only use with malformed html - this is not efficient def display_visible_html_using_re(text): return(re.sub("(\<.*?\>)", "",text)) 

标题位于<nyt_headline>标签内,嵌套在<h1>标签和id为“article”的<div>标签内。

 soup.findAll('nyt_headline', limit=1) 

应该工作。

文章正文位于<nyt_text>标签内,它嵌套在ID为“articleBody”的<div>标签内。 在<nyt_text>元素中,文本本身包含在<p>标签中。 图像不在这些<p>标签内。 我对语法进行实验是很困难的,但是我期望看到这样的工作。

 text = soup.findAll('nyt_text', limit=1)[0] text.findAll('p') 

如果你关心性能,这是另一种更有效的方法:

 import re INVISIBLE_ELEMS = ('style', 'script', 'head', 'title') RE_SPACES = re.compile(r'\s{3,}') def visible_texts(soup): """ get visible text from a document """ text = ' '.join([ s for s in soup.strings if s.parent.name not in INVISIBLE_ELEMS ]) # collapse multiple spaces to two spaces. return RE_SPACES.sub(' ', text) 

soup.strings是一个迭代器,它会返回NavigableString以便您可以直接检查父代的标签名称,而不会经历多个循环。