Проблема с регулярными выражениями в python - PullRequest
2 голосов
/ 18 сентября 2008

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

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

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> строк.

Ответы [ 6 ]

23 голосов
/ 18 сентября 2008

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

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

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

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

4 голосов
/ 18 сентября 2008

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

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

2 голосов
/ 06 марта 2009

Я использовал 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, то лучше использовать его. :)

2 голосов
/ 18 сентября 2008

Опираясь на ответы до сих пор:

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

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

p = re.compile(r'<(h[0-9])>(.+?)</\1>', re.IGNORECASE | re.DOTALL)
stories = re.findall(p, html)
for i in stories:
    print i
2 голосов
/ 18 сентября 2008

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

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

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

1 голос
/ 18 сентября 2008

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

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

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()

Вот несколько хороших ресурсов регулярных выражений:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...