Проблема с регулярными выражениями в Python

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

Я скомпилировал регулярное выражение:

regex = re.compile(r'''
    <h[0-9]>\s?
    (<a[ ]href = "[A-Za-z0-9.]*">)?\s?
    [A-Za-z0-9.,:'"=/?;\s]*\s?
    [A-Za-z0-9.,:'"=/?;\s]?
''',  re.X)

Когда я запускаю это в python reg ex. тестером, отлично работает.

Пример данных:

<body>
    <h1>Dog </h1>
    <h2>Cat </h2>
    <h3>Fancy </h3>
    <h1>Tall cup of lemons</h1>
    <h1><a href = "dog.com">Dog thing</a></h1>
</body>

Теперь в REDemo это прекрасно работает.

Однако когда я помещаю его в свой код Python, он печатает только <a href = "dog.com">

Вот мой код на Python, я не уверен, что я делаю что-то не так или что-то потеряно при переводе. Я ценю вашу помощь.

stories=[]
response = urllib2.urlopen('http://apricotclub.org/duh.html')
html = response.read().lower()
p = re.compile('<h[0-9]>\s?(<a href=\"[A-Za-z0-9.]*\">)?\s?[A-Za-z0-9.,:\'\"=/?;\s]*\s?[A-Za-z0-9.,:\'\"=/?;\s]?')
stories=re.findall(p, html)
for i in stories:
    if len(i) >= 5:
        print i 

Я также должен отметить, что когда я извлекаю (<a href=\"[A-Za-z0-9.]*\">)? из регулярного выражения, он отлично работает для несвязанных строк <hN>.

Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
1 066
6

Ответы 6

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

Обратной стороной является не очень быстрая работа. Есть lxml для синтаксического анализа правильно сформированного html, но вам действительно стоит использовать BeautifulSoup, если вы не на 100% уверены, что ваш ввод всегда будет правильно сформирован.

Из-за фигурных скобок вокруг тега привязки эта часть интерпретируется как группа захвата. Это приводит к возврату только группы захвата, а не всего совпадения регулярного выражения.

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

Но действительно, вам стоит использовать настоящий парсер.

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

В: Как разобрать HTML с помощью регулярных выражений?

A: Пожалуйста, не надо.

Используйте BeautifulSoup, html5lib или lxml.html. Пожалуйста.

Не забывайте, что html5lib также может анализировать несоответствующие документы в разумную структуру.

Allen 18.09.2008 09:06

@Jerub: Я согласен с вашим ответом, но он не отвечает на вопрос OP. Представьте, что вы не можете использовать BeautifulSoup, html5lib, lxml, а ваши html-файлы просто очень, тогда будет достаточно тривиального регулярного выражения.

jfs 06.03.2009 13:08

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

Вот как вы могли бы сделать это с помощью регулярного выражения:

import re

html = '''
<body>

<h1>Dog </h1>
<h2>Cat </h2>
<h3>Fancy </h3>
<h1>Tall cup of lemons</h1>
<h1><a href = "dog.com">Dog thing</a></h1>
</body>
'''

p = re.compile(r'''
    <(?P<header>h[0-9])>             # store header tag for later use
    \s*                              # zero or more whitespace
    (<a\shref = "(?P<href>.*?)">)?     # optional link tag. store href portion
    \s*
    (?P<title>.*?)                   # title
    \s*
    (</a>)?                          # optional closing link tag
    \s*
    </(?P=header)>                   # must match opening header tag
''', re.IGNORECASE + re.VERBOSE)

stories = p.finditer(html)

for match in stories:
    print '%(title)s [%(href)s]' % match.groupdict()

Вот пара хороших ресурсов по регулярным выражениям:

Регулярное выражение не работает для заголовков со ссылками. И OP спрашивает конкретно о заголовках ссылок с.

jfs 06.03.2009 12:40

Основываясь на ответах на данный момент:

Лучше всего использовать движок синтаксического анализа. Он может охватывать множество случаев и элегантно. Я пробовал BeautifulSoup, и он мне очень нравится. Также прост в использовании, с отличным учебником.

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

p = re.compile(r'<(h[0-9])>(.+?)</>', re.IGNORECASE | re.DOTALL)
stories = re.findall(p, html)
for i in stories:
    print i

i в ваших случаях - это кортеж, например. ('h1', '<a href="dog.com"> Собака </a>')

jfs 06.03.2009 12:51

Я использовал beautifulsoup для синтаксического анализа желаемого HTML. У меня есть указанный выше HTML-код в файл с именем foo.html, который позже читается как файловый объект.

from BeautifulSoup import BeautifulSoup


H_TAGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']

def extract_data():
   """Extract the data from all headers
   in a HTML page."""
   f = open('foo.html', 'r+')
   html = f.read()
   soup = BeautifulSoup(html)
   headers = [soup.findAll(h) for h in H_TAGS if soup.findAll(h)]
   lst = []
   for x in headers:
      for y in x:
         if y.string:
            lst.append(y.string)
         else:
            lst.append(y.contents[0].string)
   return lst

Вышеупомянутая функция возвращает:

>>> [u'Dog ', u'Tall cup of lemons', u'Dog thing', u'Cat ', u'Fancy ']

Вы можете добавить любое количество тегов заголовков в список h_tags. Я принял все заголовки. Если вы можете легко решать проблемы с помощью BeautifulSoup, то лучше его использовать. :)

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