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





Регулярные выражения с HTML запутываются. Просто используйте парсер DOM, например Beautiful Soup.
Я клянусь, что этот вопрос возникает достаточно, чтобы оставить ответ в часто задаваемых вопросах.
Нет, нет.
Вы можете рассмотреть возможность использования Красивый суп. Вы можете назвать это стандартом для разбора файлов html.
Это немного зависит от того, как создается HTML. Если это несколько контролируется, вам сойдет с рук:
re.findall(r'''<link\s+.*?href=['"](.*?)['"].*?(?:</link|/)>''', html, re.I)
Отвечаю на два ваших подвопроса.
Может быть. Там, где я работаю, не всегда все идет на передовой знак равно
:-) Любые рекомендации по правильной замене py3?
Не совсем. Возможно, в этой статье можно найти некоторые зацепки: boddie.org.uk/python/HTML.html
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. "искаженные возможности" ничего в этом не меняют.
В ответ на вопрос № 2 (не должна ли ссылка быть четко определенным регулярным выражением) ответ будет ... нет.
Структура ссылок HTML является рекурсивной, как скобки и скобки в языках программирования. Должно быть равное количество начальных и конечных конструкций, а выражение «ссылка» может быть вложено внутри себя.
Чтобы правильно сопоставить выражение «ссылка», потребуется регулярное выражение для подсчета начального и конечного тегов. Регулярные выражения - это класс конечных автоматов. По определению Конечный Автомат не может «подсчитывать» конструкции в шаблоне. Грамматика необходима для описания такой рекурсивной структуры данных. Неспособность регулярного выражения «подсчитывать» - вот почему вы видите языки программирования, описанные с помощью грамматик, в отличие от регулярных выражений.
Таким образом, невозможно создать регулярное выражение, которое будет положительно соответствовать 100% всех выражений «ссылки». Конечно, существуют регулярные выражения, которые будут соответствовать большому количеству «ссылок» с высокой степенью точности, но они никогда не будут идеальными.
Я недавно написал в блоге статью об этой проблеме. Ограничения регулярных выражений
И интересно, и полезно - спасибо. Кстати, эта проблема решается автоматом стека с выталкиванием вниз, который имеет большую вычислительную мощность, чем регулярное выражение - и это можно легко доказать с помощью леммы о накачке (en.wikipedia.org/wiki/Pumping_lemma)
Не правда. Рекурсивные структуры в HTML (такие как таблицы в таблицах и многие другие), безусловно, не поддаются синтаксическому анализу с помощью RE, но LINK и As рекурсивны в HTML, поэтому вам просто не нужно заботиться о рекурсивных структурах для получения ссылок.
@jpalecek, вы ошибаетесь. Тег A, безусловно, рекурсивен, потому что содержимое тега A может содержать другой тег. Это может показаться странным, но это определенно разбираемый HTML.
Нет, тег не может содержать теги A. Из HTML 4.01 DTD: «<! ELEMENT A - - (% inline;) * - (A)», - (A) означает, что не может быть тега A, вложенного в другой тег A. XML DTD не может выразить это, но w3.org/TR/xhtml1/#prohibiteds запрещает это.
@jpalecek, интересно. Я обычно подхожу к этим вопросам гораздо больше, исходя из вопроса «поддается ли это синтаксическому анализу», чем «легителен ли это HTML?», Потому что веб-сайты, как правило, находятся на стороне первого. Даже без указания того, что у вас все еще может быть <a> буквально внутри него, вставив в CDATA или буквальную строку.
Да, но на самом деле это не "анализируемое", потому что браузеры не анализируют его :-) Это свойство, которое упрощает язык, разработчики браузеров используют его, так что зачем беспокоиться. Что касается CDATA и литералов - все они являются обычными языками, поэтому не являются препятствием для RE.
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 не могут быть вложенными, и то, что внутри них, выходит за рамки того, что вам нужно для получения ссылок.
Как предлагали другие, если производительность в реальном времени не требуется, 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.
Регулярное выражение по указанным выше причинам (синтаксический анализатор должен поддерживать состояние, а регулярное выражение не может этого сделать) никогда не будет общим решением.
+1: Нет, HTML нельзя описать регулярными выражениями. Это более сложно. И, что еще хуже, браузеру разрешено принимать недопустимый HTML, поэтому веб-сайты отправляют недопустимый HTML.