Regex для ссылок в html-тексте

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

Адам

UPDATE: Я действительно ищу два разных ответа:

  • Что такое библиотечное решение для синтаксического анализа ссылок HTML. Beautiful Soup кажется хорошим решением (спасибо, Igal Serban и cletus!)
  • Можно ли определить ссылку с помощью регулярного выражения?

Ответ 1

Как показали другие, если производительность в режиме реального времени не требуется, 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.

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

Ответ 2

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

Ответ 3

Нет. Нет.

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

Ответ 4

Неправильно ли ссылка будет четко определенным регулярным выражением?

Нет, [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-супом HTML, существует миллион искаженных возможностей.

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

Ответ 5

Не будет ли ссылка корректным регулярным выражением? Это довольно теоретический вопрос,

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

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

Насколько я знаю, любой тег 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 - это контекстно-свободная грамматика, а не обычный язык.

Ответ 6

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

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

Ответ 7

Отвечая на ваши два подзапроса там.

  • Я иногда подклассифицировал SGMLParser (входит в основной дистрибутив Python) и должен сказать это прямо.
  • Я не думаю, что HTML поддается "хорошо определенным" регулярным выражениям, поскольку он не является обычным языком.

Ответ 8

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

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

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

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

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