регулярное выражение для извлечения текста из HTML
-
05-07-2019 - |
Вопрос
Я хотел бы извлечь из общей HTML-страницы весь текст (отображаемый или нет).
Я бы хотел удалить
- любые HTML-теги
- Любой javascript
- Любые стили CSS
Существует ли регулярное выражение (одно или несколько), которое позволит достичь этого?
Решение
На самом деле вы не можете анализировать HTML с помощью регулярных выражений.Это слишком сложно.RE's не справится <![CDATA[
разделы вообще корректны.Кроме того, некоторые виды распространенных HTML-файлов, таких как <text>
будет работать в браузере как обычный текст, но может сбить с толку наивного пользователя.
Вы будете счастливее и успешнее с правильным анализатором HTML.Люди из Python часто используют что-то Прекрасный Суп для синтаксического анализа HTML и удаления тегов и скриптов.
Кроме того, браузеры по своей конструкции допускают искаженный HTML.Таким образом, вы часто будете ловить себя на том, что пытаетесь разобрать HTML, что явно неправильно, но, оказывается, нормально работает в браузере.
Возможно, вы сможете разобрать плохой HTML с помощью RE's.Все, что для этого требуется, - это терпение и упорный труд.Но часто проще использовать чужой синтаксический анализатор.
Другие советы
Удалите javascript и CSS:
<(script|style).*?</\1>
Удалить теги
<.*?>
Требовалось решение с регулярным выражением (в php) это вернуло бы обычный текст так же хорошо (или лучше, чем) PHPSimpleDOM, только намного быстрее.Вот решение, которое я придумал:
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 plaintext, только намного, намного быстрее.Он также правильно обрабатывал элементы списка (теги li), чего не делал PHPSimpleDOM.
Что касается скорости:
- Простой мир:0,03248 сек.
- Регулярное выражение:0,00087 сек.
в 37 раз быстрее!
Мысль о том, чтобы сделать это с помощью регулярных выражений, пугает.Рассматривали ли вы XSLT?Выражение XPath для извлечения всех текстовых узлов в документе XHTML, за вычетом содержимого script & style, будет следующим:
//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, попробуйте Простой HTML DOM, доступный в SourceForge.
В противном случае, загуглите html2text, и вы найдете множество реализаций для разных языков, которые в основном используют серию регулярных выражений, чтобы удалить всю разметку.Будьте осторожны здесь, потому что иногда могут быть оставлены теги без окончаний, а также специальные символы, такие как & (который является &).
Кроме того, следите за комментариями и Javascript, поскольку я обнаружил, что иметь дело с регулярными выражениями особенно неприятно, и поэтому я обычно предпочитаю, чтобы бесплатный синтаксический анализатор делал всю работу за меня.
И не уверен эта страница могло бы помочь.
Разве вы не можете просто использовать веб- браузерный элемент управления, доступный с C # ?
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
Который вернет содержимое всех текстовых узлов в документе, видимых или нет.
[править (олли): вздох неважно, это работает только в Safari и IE, и я не могу утруждать себя загрузкой firefox каждую ночь, чтобы посмотреть, существует ли он в trunk :-/ ]