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

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

Адам

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

  1. каково библиотечное решение для разбора HTML-ссылок. Красивый Суп кажется хорошим решением (спасибо,Igal Serban и cletus!)
  2. можно ли определить ссылку с помощью регулярного выражения?

8 ответов


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


Regexes с HTML становятся грязными. Просто используйте парсер DOM, как красивый суп.


нет.

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


Shoudln не ссылка быть четко определено выражение?

нет, [X]HTML В общем случае не анализируется с помощью regex. Рассмотрим такие примеры, как:

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

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


Shoudln не ссылка быть четко определено выражение? Это скорее теоретический вопрос,

Я второй ответ Пеза:

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


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

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

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

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

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

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

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

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

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