Регулярное выражение для ссылок в тексте html

Надеюсь, это не вопрос RTFM. Я пытаюсь написать сценарий Python, который извлекает ссылки со стандартной веб-страницы HTML (теги <link href...). Я искал в Интернете подходящие регулярные выражения и нашел много разных шаблонов. Есть ли какое-либо согласованное стандартное регулярное выражение для сопоставления ссылок?

Адам

Обновлено: На самом деле я ищу два разных ответа:

  1. Какое библиотечное решение для разбора HTML-ссылок. Красивый суп кажется хорошим решением (спасибо, Igal Serban и cletus!)
  2. Можно ли определить ссылку с помощью регулярного выражения?
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
7
0
14 661
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Регулярные выражения с HTML запутываются. Просто используйте парсер DOM, например Beautiful Soup.

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

S.Lott 10.01.2009 17:39

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

annakata 10.01.2009 19:26

Нет, нет.

Вы можете рассмотреть возможность использования Красивый суп. Вы можете назвать это стандартом для разбора файлов html.

Это немного зависит от того, как создается HTML. Если это несколько контролируется, вам сойдет с рук:

re.findall(r'''<link\s+.*?href=['"](.*?)['"].*?(?:</link|/)>''', html, re.I)

Отвечаю на два ваших подвопроса.

  1. Я иногда создавал подклассы SGMLParser (включенный в основной дистрибутив Python) и должен сказать, что это прямолинейно.
  2. Я не думаю, что HTML поддается «четко определенным» регулярным выражениям, поскольку это не обычный язык.

Может быть. Там, где я работаю, не всегда все идет на передовой знак равно

PEZ 10.01.2009 18:34

:-) Любые рекомендации по правильной замене py3?

Adam Matan 10.01.2009 22:39

Не совсем. Возможно, в этой статье можно найти некоторые зацепки: boddie.org.uk/python/HTML.html

PEZ 10.01.2009 23:23

Shoudln't a link be a well-defined regex?

Нет, [X] HTML в общем случае не поддается синтаксическому анализу с помощью регулярных выражений. Рассмотрим такие примеры, как:

<link title='hello">world' href = "x">link</link>
<!-- <link href = "x">not a link</link> -->
<![CDATA[ ><link href = "x">not a link</link> ]]>
<script>document.write('<link href = "x">not a link</link>')</script>

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

Если вы знаете и можете полагаться на точный формат вывода целевой страницы, вы можете обойтись с регулярным выражением. В противном случае это совершенно неправильный выбор для очистки веб-страниц.

Все ваши примеры на самом деле анализируются с помощью регулярного выражения (чтобы не сказать, что последний недействителен). Синтаксический анализатор XML SAX (который нужен OP) - не что иное, как лексер языка, определенного RE. "искаженные возможности" ничего в этом не меняют.

jpalecek 06.03.2009 23:49

В ответ на вопрос № 2 (не должна ли ссылка быть четко определенным регулярным выражением) ответ будет ... нет.

Структура ссылок HTML является рекурсивной, как скобки и скобки в языках программирования. Должно быть равное количество начальных и конечных конструкций, а выражение «ссылка» может быть вложено внутри себя.

Чтобы правильно сопоставить выражение «ссылка», потребуется регулярное выражение для подсчета начального и конечного тегов. Регулярные выражения - это класс конечных автоматов. По определению Конечный Автомат не может «подсчитывать» конструкции в шаблоне. Грамматика необходима для описания такой рекурсивной структуры данных. Неспособность регулярного выражения «подсчитывать» - вот почему вы видите языки программирования, описанные с помощью грамматик, в отличие от регулярных выражений.

Таким образом, невозможно создать регулярное выражение, которое будет положительно соответствовать 100% всех выражений «ссылки». Конечно, существуют регулярные выражения, которые будут соответствовать большому количеству «ссылок» с высокой степенью точности, но они никогда не будут идеальными.

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

И интересно, и полезно - спасибо. Кстати, эта проблема решается автоматом стека с выталкиванием вниз, который имеет большую вычислительную мощность, чем регулярное выражение - и это можно легко доказать с помощью леммы о накачке (en.wikipedia.org/wiki/Pumping_lemma)

Adam Matan 10.01.2009 22:45

Не правда. Рекурсивные структуры в HTML (такие как таблицы в таблицах и многие другие), безусловно, не поддаются синтаксическому анализу с помощью RE, но LINK и As рекурсивны в HTML, поэтому вам просто не нужно заботиться о рекурсивных структурах для получения ссылок.

jpalecek 07.03.2009 00:15

@jpalecek, вы ошибаетесь. Тег A, безусловно, рекурсивен, потому что содержимое тега A может содержать другой тег. Это может показаться странным, но это определенно разбираемый HTML.

JaredPar 07.03.2009 00:17

Нет, тег не может содержать теги A. Из HTML 4.01 DTD: «<! ELEMENT A - - (% inline;) * - (A)», - (A) означает, что не может быть тега A, вложенного в другой тег A. XML DTD не может выразить это, но w3.org/TR/xhtml1/#prohibiteds запрещает это.

jpalecek 07.03.2009 00:28

@jpalecek, интересно. Я обычно подхожу к этим вопросам гораздо больше, исходя из вопроса «поддается ли это синтаксическому анализу», чем «легителен ли это HTML?», Потому что веб-сайты, как правило, находятся на стороне первого. Даже без указания того, что у вас все еще может быть <a> буквально внутри него, вставив в CDATA или буквальную строку.

JaredPar 07.03.2009 00:48

Да, но на самом деле это не "анализируемое", потому что браузеры не анализируют его :-) Это свойство, которое упрощает язык, разработчики браузеров используют его, так что зачем беспокоиться. Что касается CDATA и литералов - все они являются обычными языками, поэтому не являются препятствием для RE.

jpalecek 07.03.2009 01:16

Shoudln't a link be a well-defined regex? This is a rather theoretical question,

Второй ответ PEZ:

I don't think HTML lends itself to "well defined" regular expressions since it's not a regular language.

Насколько мне известно, любой HTML-тег может содержать любое количество вложенных тегов. Например:

<a href = "http://stackoverflow.com">stackoverflow</a>
<a href = "http://stackoverflow.com"><i>stackoverflow</i></a>
<a href = "http://stackoverflow.com"><b><i>stackoverflow</i></b></a>
...

Таким образом, в принципе, чтобы правильно сопоставить тег, вы должны уметь сопоставить хотя бы строки вида:

BE
BBEE
BBBEEE
...
BBBBBBBBBBEEEEEEEEEE
...

где B означает начало тега, а E означает конец. То есть вы должны иметь возможность сопоставлять строки, образованные любым количеством букв B, за которыми следует число E одно и тоже. Для этого ваш сопоставитель должен уметь «подсчитывать», а регулярные выражения (то есть конечные автоматы) просто не могут этого делать (для подсчета автомату нужен как минимум стек). Что касается ответа PEZ, HTML - это контекстно-свободная грамматика, а не обычный язык.

Нет, на самом деле тебе это не нужно. В HTML теги A не могут быть вложенными, и то, что внутри них, выходит за рамки того, что вам нужно для получения ссылок.

jpalecek 06.03.2009 23:43
Ответ принят как подходящий

Как предлагали другие, если производительность в реальном времени не требуется, BeautifulSoup - хорошее решение:

import urllib2
from BeautifulSoup import BeautifulSoup

html = urllib2.urlopen("http://www.google.com").read()
soup = BeautifulSoup(html)
all_links = soup.findAll("a")

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

Если вы уверены, что работаете со стандартным XHTML, вы можете использовать (гораздо) более быстрые анализаторы XML, такие как expat.

Регулярное выражение по указанным выше причинам (синтаксический анализатор должен поддерживать состояние, а регулярное выражение не может этого сделать) никогда не будет общим решением.

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