Регулярное сопоставление элементов после заголовка в HTML - PullRequest
0 голосов
/ 25 октября 2010

То, что должно быть довольно простым извлечением регулярных выражений, смущает меня. Не смог найти похожий вопрос по SO, поэтому рад, что на него указывают, если он существует. Учитывая следующий HTML:

<h1 class="title">Title One</h1><p><a href="#">40.5</a><a href="#">31.3</a></p>

<h1 class="title alternate">Title Two</h1><p><a href="#">12.1</a><a href="#">82.0</a></p>

(среди больших документов - выдержки, скорее всего, будут состоять из нескольких строк)

Как я могу построить регулярное выражение, которое находит текст в тегах A, в первом P после H1? Регулярное выражение будет проходить в цикле, так что я могу передать его в заголовок, чтобы получить следующие элементы.

<a[^>]*>([0-9.]+?)</a> очевидно соответствует всем элементам в теге (и должно быть в порядке, поскольку теги не могут быть связаны), но я не могу связать их с H1.

.+Title One.+<a[^>]*>([0-9.]+?)</a></p> не удается.

Я пытался использовать взгляд сзади так:

(?<=Title One.+)<a[^>]*>([0-9.]+?)</a></p> и некоторые варианты, но это разрешено только для совпадений фиксированной ширины (что не будет здесь).

Для контекста это будет использовать движок регулярных выражений Python. Я знаю, что регулярные выражения не обязательно являются лучшим решением для этого, поэтому альтернативные предложения, использующие DOM или что-то еще, также с благодарностью получены:)


Обновление

Чтобы пояснить вышесказанное, я хотел бы получить следующее:

{"Title One": ["40.5", "31.3"], "Title Two": ["12.1", "82.0"]}

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

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


Ответы [ 5 ]

1 голос
/ 25 октября 2010

Это то, что вы ищете?

>>> from lxml import etree
>>>
>>> data = """
... <h1 class="title">Title One</h1><p><a href="#">40.5</a><a href="#">31.3</a></p>
... <h1 class="title alternate">Title Two</h1><p><a href="#">12.1</a><a href="#">82.0</a></p>
... """
>>>
>>> d = etree.HTML(data)
>>> d.xpath('//h1/following-sibling::p[1]/a/text()')
['40.5', '31.3', '12.1', '82.0']

В этом решении используется выражение lxml.etree и выражение xpath.


Обновление

>>> from lxml import etree
>>> from pprint import pprint
>>>
>>> data = """
... <h1 class="title">Title One</h1><p><a href="#">40.5</a><a href="#">31.3</a></p>
... <h1 class="title alternate">Title Two</h1><p><a href="#">12.1</a><a href="#">82.0</a></p>
... """
>>>
>>> d = etree.HTML(data)
>>> #d.xpath('//h1[following-sibling::*[1][local-name()="p"]]') 
...
>>> results = {}
>>> for h in d.xpath('//h1[following-sibling::*[1][local-name()="p"]]'):
...   r = results.setdefault(str(h.text),[])
...   r += [ str(x) for x in h.xpath('./following-sibling::*[1][local-name()="p"]/a/text()') ]
...
>>> pprint(results)
{'Title One': ['40.5', '31.3'], 'Title Two': ['12.1', '82.0']}

Теперь, используя предикаты для просмотра вперед, следует перебирать теги <h1>, за которыми сразу следуют теги <p>. (Приведение tag.text к строкам в явном виде, так как я помню, что они не являются обычными строками, у вас возникнут проблемы с их выделением и т.

1 голос
/ 25 октября 2010

Вы правы, регулярное выражение - абсолютно неправильный инструмент для соответствия HTML.

Однако ваш вопрос звучит так же, как и проблема для Beautiful Soup - анализатора HTML, который может работать с неидеальным HTML.

1 голос
/ 25 октября 2010

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

0 голосов
/ 25 октября 2010

Вот способ, использующий только обычные манипуляции со строками

html='''
<h1 class="title">Title One</h1><p><a href="#">40.5</a>
<a href="#">31.3</a></p>
<h1 class="title alternate">Title Two</h1><p><a href="#">12.1</a><a href="#">82.0</a></p>
'''

for i in html.split("</a>"):
    if "<a href" in i:
        print i.split("<a href")[-1].split(">")[-1]

output

$ python test.py
40.5
31.3
12.1
82.0

Я не совсем понимаю, что вы хотите получить, но если ваше требование ПРОСТО, да, регулярное выражение или несколько искажений строки могут сделать это.Не обязательно нужен парсер для этого.

0 голосов
/ 25 октября 2010

Не используйте регулярные выражения для анализа HTML.Это не может быть сделано по определению.Вместо этого используйте html-парсер.Я предлагаю lxml.html.

lxml.html лучше справляется с плохо сформированным html, чем BeautifulSoup, активно поддерживается (BeautifulSoup нет) и работает намного быстрее, поскольку использует libxml2 для внутреннего использования.

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