HTMLからテキストを抽出する正規表現
-
05-07-2019 - |
質問
一般的なHTMLページからすべてのテキスト(表示または非表示)を抽出したい。
削除したい
- 任意のHTMLタグ
- 任意のjavascript
- 任意のCSSスタイル
それを達成する正規表現(1つ以上)はありますか?
解決
正規表現でHTMLを実際に解析することはできません。複雑すぎます。 REは<![CDATA[
セクションを正しく処理しません。さらに、ブラウザでは<text>
などの一般的なHTMLのいくつかの種類は適切なテキストとして機能しますが、単純なREを困惑させる可能性があります。
適切なHTMLパーサーを使用すると、より幸せで成功するでしょう。 Pythonの人々はしばしば Beautiful Soup を使用してHTMLを解析し、タグとスクリプトを取り除きます。
また、ブラウザは、設計上、不正なHTMLを許容します。そのため、明らかに不適切なHTMLを解析しようとしていることがよくありますが、たまたまブラウザで問題なく動作します。
REで不正なHTMLを解析できる場合があります。必要なのは忍耐と勤勉です。ただし、他の人のパーサーを使用する方が簡単な場合がよくあります。
他のヒント
javascriptとCSSを削除します:
<(script|style).*?</\1>
タグを削除
<.*?>
PHPSimpleDOMと同様(またはそれ以上)のプレーンテキストを返す正規表現ソリューション( php )が必要でしたが、はるかに高速でした。ここに私が思いついた解決策があります:
function plaintext($html)
{
// remove comments and any content found in the the comment area (strip_tags only removes the actual tags).
$plaintext = preg_replace('#<!--.*?-->#s', '', $html);
// put a space between list items (strip_tags just removes the tags).
$plaintext = preg_replace('#</li>#', ' </li>', $plaintext);
// remove all script and style tags
$plaintext = preg_replace('#<(script|style)\b[^>]*>(.*?)</(script|style)>#is', "", $plaintext);
// remove br tags (missed by strip_tags)
$plaintext = preg_replace("#<br[^>]*?>#", " ", $plaintext);
// remove all remaining html
$plaintext = strip_tags($plaintext);
return $plaintext;
}
いくつかの複雑なサイトでこれをテストすると(フォーラムには解析が難しいHTMLが含まれているようです)、このメソッドはPHPSimpleDOMプレーンテキストと同じ結果を、はるかに高速で返しました。また、PHPSimpleDOMが処理しなかったリスト項目(liタグ)も適切に処理しました。
速度について:
- SimpleDom:0.03248秒。
- 正規表現:0.00087秒。
37倍高速!
正規表現でこれを行うことを考えるのは困難です。 XSLTを検討しましたか?スクリプト<!> ampを除く、XHTMLドキュメント内のすべてのテキストノードを抽出するXPath式。スタイルコンテンツ:
//body//text()[not(ancestor::script)][not(ancestor::style)]
正規表現の定義にperl構文を使用すると、開始は次のようになります。
!<body.*?>(.*)</body>!smi
次に、そのグループの結果に次の置換を適用します。
!<script.*?</script>!!smi
!<[^>]+/[ \t]*>!!smi
!</?([a-z]+).*?>!!smi
/<!--.*?-->//smi
もちろん、これはテキストファイルとしてうまくフォーマットしませんが、すべてのHTMLを取り除きます(ほとんどの場合、正しく動作しない場合がいくつかあります)。しかし、より良いアイデアは、使用している言語でXMLパーサーを使用してHTMLを適切に解析し、そこからテキストを抽出することです。
単純なHTMLの最も簡単な方法(Pythonの例):
text = "<p>This is my> <strong>example</strong>HTML,<br /> containing tags</p>"
import re
" ".join([t.strip() for t in re.findall(r"<[^>]+>|[^<]+",text) if not '<' in t])
これを返します:
'This is my> example HTML, containing tags'
これは、最も複雑なhtmlタグでも削除する関数です。
function strip_html_tags( $text )
{
$text = preg_replace(
array(
// Remove invisible content
'@<head[^>]*?>.*?</head>@siu',
'@<style[^>]*?>.*?</style>@siu',
'@<script[^>]*?.*?</script>@siu',
'@<object[^>]*?.*?</object>@siu',
'@<embed[^>]*?.*?</embed>@siu',
'@<applet[^>]*?.*?</applet>@siu',
'@<noframes[^>]*?.*?</noframes>@siu',
'@<noscript[^>]*?.*?</noscript>@siu',
'@<noembed[^>]*?.*?</noembed>@siu',
// Add line breaks before & after blocks
'@<((br)|(hr))@iu',
'@</?((address)|(blockquote)|(center)|(del))@iu',
'@</?((div)|(h[1-9])|(ins)|(isindex)|(p)|(pre))@iu',
'@</?((dir)|(dl)|(dt)|(dd)|(li)|(menu)|(ol)|(ul))@iu',
'@</?((table)|(th)|(td)|(caption))@iu',
'@</?((form)|(button)|(fieldset)|(legend)|(input))@iu',
'@</?((label)|(select)|(optgroup)|(option)|(textarea))@iu',
'@</?((frameset)|(frame)|(iframe))@iu',
),
array(
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
"\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0",
"\n\$0", "\n\$0",
),
$text );
// Remove all remaining tags and comments and return.
return strip_tags( $text );
}
PHPを使用している場合は、SourceForgeで入手可能なSimple HTML DOMを試してください。
それ以外の場合、Google html2textを使用すると、基本的に一連の正規表現を使用してすべてのマークアップを吸い取るさまざまな言語のさまざまな実装が見つかります。ここで注意してください、終了のないタグは、<!> amp;などの特殊文字と同様に残されることがあります。 (<!> amp; amp;)。
また、正規表現を扱うのが特に面倒であることがわかったので、コメントとJavascriptに注意してください。また、一般に、無料のパーサーにすべての作業を任せることを好む理由もあります。
このページが役立つ場合はありません。
C#で使用可能なWebBrowserコントロールを使用することはできませんか?
System.Windows.Forms.WebBrowser wc = new System.Windows.Forms.WebBrowser();
wc.DocumentText = "<html><body>blah blah<b>foo</b></body></html>";
System.Windows.Forms.HtmlDocument h = wc.Document;
Console.WriteLine(h.Body.InnerText);
string decode = System.Web.HttpUtility.HtmlDecode(your_htmlfile.html);
Regex objRegExp = new Regex("<(.|\n)+?>");
string replace = objRegExp.Replace(g, "");
replace = replace.Replace(k, string.Empty);
replace.Trim("\t\r\n ".ToCharArray());
then take a label and do "label.text=replace;" see on label out put
。
あなたならできると思う
document.body.innerText
ドキュメント内のすべてのテキストノードのコンテンツを表示するかどうかを返します。
[edit(olliej):ため息、これはSafariとIEでのみ機能します。Firefoxを夜間にダウンロードしてトランクに存在するかどうかを確認することはできません:-/]