Regex: извлечение читабельных (некодных) текста и URL-адресов из документов HTML

StackOverflow https://stackoverflow.com/questions/3951485

Вопрос

Я создаю приложение, которое возьмет URL в качестве ввода, извлеките содержимое HTML страницы с веб-сайта и извлечения все, что не содержится в теге. Отказ Другими словами, текстовое содержание страницы, как видно посетитель этой страницы. Который включает в себя «маскировку», все инкапсулировано в <script></script>, <style></style> а также <!-- -->, поскольку эти порции содержат текст, который не охватывается в теге (но лучше оставить в покое).

Я построил это регез:

(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>)

Он правильно выбирает все содержимое, которое я хочу игнорировать, и оставляет только текстовое содержимое страницы. Однако это означает, что то, что я хочу извлечь, не будет отображаться в коллекции совпадений (я использую vb.net в Visual Studio 2010).

Есть ли способ «инвертировать» сопоставление целого документа, подобного этому, чтобы я получил совпадения на всех текстовых строках, которые остаются подходящим в приведенном выше Regex?

До сих пор, что я сделал, было добавить еще одну альтернативу в конце, что выбирает любую последовательность, которая не содержит <или> «», которая затем означает остаток в лешке. Я назвал этот последний бит в группе захвата, и когда я повторяю на матчах, я проверяю наличие текста в группе «Текст». Это работает, но мне было интересно, было ли удалось сделать все это через Regex и только что в конечном итоге с матчами на простом тексте.

Это должно быть совместно работать, не зная каких-либо конкретных тегов в HTML. Это должно извлечь все текст. Кроме того, мне нужно сохранить оригинальный HTML, поэтому страница сохраняет все его ссылки и сценарии - мне нужно только иметь возможность извлечь текст, чтобы я мог выполнить поиск и замены в нем, без боязни в «переименовании» любых тегов, атрибуты или Script Vimiables и т. Д. (Итак, я не могу просто сделать «заменить ни на что» на все спички, которые я получаю, потому что, хотя я потом ушел с тем, что мне нужно, это хлопот, чтобы перейти в правильные места Полностью функциональный документ).

Я хочу знать, что это вообще возможно, используя Regex (и я знаю о HTML Agility Pack и XPath, но не чувствую себя как).

Какие-либо предложения?

Обновлять:Вот решение (Regeex) решение, которое я оказался: http://www.martinwardener.com/regex/, внедренные в демонстрационном приложении, которое покажет как активные строки Regeex вместе с тестовым двигателем, который позволяет запустить анализ на любой онлайн-HTML-странице, давая вам время анализа и извлеченные результаты (для ссылки, URL и текстовых порций индивидуально - как Хорошо, как мнения, где все спички Regex выделены на месте в полном HTML-документе).

Это было полезно?

Решение 5

Хорошо, так вот как я делаю это:

Используя мое оригинальное регулярное выражение (с добавленным рисунком поиска для простого текста, что происходит, чтобы быть любым текстом, который оставлен выше после выполнения поиска тегов):

(?:(?:<(?P<tag>script|style)[\s\S]*?</(?P=tag)>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?P<text>[^<>]*)

Тогда во vb.net:

Dim regexText As New Regex("(?:(?:<(?<tag>script|style)[\s\S]*?</\k<tag>>)|(?:<!--[\s\S]*?-->)|(?:<[\s\S]*?>))|(?<text>[^<>]*)", RegexOptions.IgnoreCase)
Dim source As String = File.ReadAllText("html.txt")
Dim evaluator As New MatchEvaluator(AddressOf MatchEvalFunction)
Dim newHtml As String = regexText.Replace(source, evaluator)

Фактическая замена текста происходит здесь:

Private Function MatchEvalFunction(ByVal match As Match) As String
    Dim plainText As String = match.Groups("text").Value
    If plainText IsNot Nothing AndAlso plainText <> "" Then
        MatchEvalFunction = match.Value.Replace(plainText, plainText.Replace("Original word", "Replacement word"))
    Else
        MatchEvalFunction = match.Value
    End If
End Function

Вуаля. newHtml Теперь содержит точную копию оригинала, кроме любого вхождения «оригинального слова» на странице (так как он представлен в браузере), переключается с «заменой Word», и весь код HTML и скрипта сохраняется нетронутым. Конечно, можно было бы / поставить в более сложный рутину замены, но это показывает основной принцип. Это 12 строк кода, включая декларацию функции и загрузку HTML-кода и т. Д. Я был бы очень заинтересован в виде параллельного решения, выполненного в DOM и т. Д. Для сравнения (да, я знаю, что этот подход может быть выброшен от баланса определенный Вхождения некоторых вложенных тегов quirks - в переписывании сценария - но ущерб от этого все равно будет очень ограничено, если таковые имеются (см. Некоторые из комментариев выше), и вообще это сделает работу довольно Darn хорошо).

Другие советы

Что я сделал, это было добавить еще одну альтернативу в конце, что выбирает любую последовательность, которая не содержит < или >«Что тогда означает остаток в лешке. Я назвал этот последний бит в группе захвата, и когда я повторяю на матчах, я проверяю наличие текста в группе« Текст ».

Это то, что обычно делают. Или даже проще, замените каждое совпадение шаблона разметки с пустой строкой и то, что вы оставили, - это то, что вы ищете.

Это как бы работает, но здесь, кажется, есть строка, и там поднята, что не должно быть.

Ну, да, это потому, что ваше выражение - и регулярное выражение вообще - неадекватно, чтобы разбирать даже Valid HTML, не говоря уже о ужасах, которые находятся в настоящей сети. Первый совет, чтобы посмотреть, если вы действительно хотите преследовать этот бесполезный подход: значения атрибутов (а также текстовое содержимое в целом) могут содержать беззаботный > персонаж.

Я хотел бы еще раз предложить преимущества пакета ловкости HTML.

ETA: Поскольку вы, кажется, хотите, вот несколько примеров разметки, похожего на то, что он будет путешествовать по вашему выражению.

<a href=link></a> - unquoted
<a href= link></a> - unquoted, space at front matched but then required at back
<a href="~/link"></a> - very common URL char missing in group
<a href="link$!*'link"></a> - more URL chars missing in group
<a href=lïnk></a> - IRI
<a href
    ="link"> - newline (or tab)
<div style="background-image: url(link);"> - unquoted
<div style="background-image: url( 'link' );"> - spaced
<div style="background-image: u&#114;l('link');"> - html escape
<div style="background-image: ur\l('link');"> - css escape
<div style="background-image: url('link\')link');"> - css escape
<div style="background-image: url(\
'link')"> - CSS folding
<div style="background-image: url
('link')"> - newline (or tab)

и это просто совершенно действительная разметка, что нет Сопоставьте правильную ссылку, не какую-либо из возможных недействительных разметки, разметки, которые не должны соответствовать ссылке или любую из многих проблем с другой техникой размытия расщепления от текста. Это вершина айсберга.

Regex не является надежным для извлечения текстового содержимого HTML-документов. Regex не может обрабатывать вложенные теги. Предположим, что документ не содержит вложенного тега, Regex все еще требует, чтобы все теги были правильно закрыты.

Если вы используете PHP, для простоты я настоятельно рекомендую вам использовать DOM (модель объекта документов) для разбора / извлечения HTML-документов. Библиотека DOM обычно существует в каждом языке программирования.

Если вы хотите извлечь части строки, не совпадающей на Regex, вы можете просто заменить детали, которые являются сопоставляется с пустой строкой для того же эффекта.

Обратите внимание, что единственная причина, по которой это может работать, это потому, что теги, которые вы заинтересованы в удалении, <script> а также <style> Теги, не могут быть вложены.

Тем не менее, это не редкость для одного <script> Теги, чтобы содержать код для программного добавления другого <script> Тег, в этом случае ваше регулярное выражение будет потерпеть неудачу. Он также не удается в случае, когда любой тег не закрыт должным образом.

Вы не можете анализировать HTML с регулярными выражениями.

Разбор HTML с регулярными выражениями приводит к печали.

Я знаю, что вы просто делаете это для удовольствия, но там так много пакетов там, чем на самом деле делать разбор правильного пути и сделать это надежно, и были проверены.

Не переименяйте колесо и делаем это таким образом, но гарантированно расстраивает вас по дороге.

Довожу до вашего сведения,

Вместо регулярного воздействия, с jQuery, можно извлечь текст в одиночку от разметки HTML. Для этого вы можете использовать следующий рисунок.

$("<div/>").html("#elementId").text()

Вы можете отослать это Jsfiddle.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top