BeautifulSoupグラブ可視ウェブページのテキスト
-
20-09-2019 - |
質問
基本的に、私は、Webページ上で厳密にの表示テキストのをつかむためにBeautifulSoupを使用したいです。たとえば、このWebページのrel="noreferrer"> の質問このに提案を試してみました私はしたくない<script>
タグとHTMLコメントの多くを返します。私は機能 findAll()
ただ、ウェブページ上に表示テキストを取得するためにます。
だから、私は、スクリプト、コメント、CSSなどを除くすべての表示テキストを見つける必要がありますか。?
解決
これを試してください:
from bs4 import BeautifulSoup
from bs4.element import Comment
import urllib.request
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.request.urlopen('http://www.nytimes.com/2009/12/21/us/21storm.html').read()
print(text_from_html(html))
他のヒント
@jbochiから承認された答えは私のために動作しません。それはBeautifulSoup要素で非ASCII文字をエンコードすることができないため、STR()関数呼び出しは、例外が発生します。ここに表示されるテキストに例のウェブページをフィルタリングするために、より簡潔な方法です。
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'))
私は完全にレンダリングされたコンテンツを取得するには美しいスープを使用して尊重するが、それはページにレンダリングされたコンテンツを取得するための理想的なパッケージではないかもしれない。
私はレンダリングされたコンテンツ、または一般的なブラウザに表示コンテンツを取得するために同様の問題がありました。特に、私は以下のような単純な例で動作するように多くの、おそらく非定型例がありました。この場合、非表示のタグは、スタイルタグにネストされている、と私がチェックしている多くのブラウザでは表示されません。他の変形は、noneにディスプレイを設定するクラスのタグを定義するように存在します。その後の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>
上記掲載一つの解決策はあります:
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']
このソリューションは、確かに多くの場合、アプリケーションを持っており、一般的に非常によく仕事をしていませんが、それの上に掲示HTMLでレンダリングされていないテキストを保持します。カップルのソリューションは BeautifulSoup GET_TEXTここまで来たSO検索した後プレーンテキストにすべてのタグとJavaScript と、ここでレンダリングされたHTMLを削除しません。使ってPython の
私は両方のこれらのソリューションを試してみました:html2textとnltk.clean_htmlとタイミング結果に驚いたので、彼らは後世のための答えを正当と思いました。もちろん、速度は非常にデータの内容に依存...
@Helgeからここに一つの答えは、すべてのもののNLTKを使っについてでした。
import nltk
%timeit nltk.clean_html(html)
was returning 153 us per loop
これは、レンダリングされたHTMLの文字列を返すために本当によく働きました。おそらくhtml2textがより堅牢であるが、これNLTKモジュールは、さえhtml2textよりも速かったです。
betterHTML = html.decode(errors='ignore')
%timeit html2text.html2text(betterHTML)
%3.09 ms per loop
空行やがらくたせずに、単に文字列を取得するために以下のコードで最も簡単な方法はBeautifulSoup使用します。
tag = <Parent_Tag_that_contains_the_data>
soup = BeautifulSoup(tag, 'html.parser')
for i in soup.stripped_strings:
print repr(i)
、ここでは別の、より効率的な方法です。
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
を返します。
タイトルが<nyt_headline>
タグとID「物品」と<h1>
タグ内にネストされ<div>
タグの内側にあります。
soup.findAll('nyt_headline', limit=1)
動作するはずです。
記事本文は、ID「articleBody」と<nyt_text>
タグ内にネストされ<div>
タグの内側にあります。 <nyt_text>
要素の内部では、テキスト自体は<p>
タグ内に含まれています。画像は、これらの<p>
タグ内ではありません。私は構文を使って実験することは難しいですが、私は働いて擦り傷がこのような何かを見て期待しています。
text = soup.findAll('nyt_text', limit=1)[0]
text.findAll('p')
、私は完全に誰かが不正なHTMLの目に見える部分を表示しようとしている場合、一般的には美しいスープを使用することをお勧めしますが(たとえば、あなただけのセグメントまたはウェブページのライン持っている場合)どんな-理由では、以下は<
と>
タグの間のコンテンツを削除します。
import re ## only use with malformed html - this is not efficient
def display_visible_html_using_re(text):
return(re.sub("(\<.*?\>)", "",text))