Регулярное выражение Python findall для захвата повторяющихся групп

Контекст

Я использую python regex для анализа некоторых HTML, потому что они слишком сломаны для использования процессоры, лучше подходящие для этих задач (например, скрейпер-селекторы). Фрагмент HTML, который я хочу разобрать, выглядит так:

    <LI><B>First list title</B> Additional info
      <UL>
      <LI><I>List element 1</I> additional info
      </UL>
    
    <LI><B>Second list title</B> Additional info
      <UL>
      <LI><I>List element 1</I> additional info1
      <LI><I>List element 2</I> additional info2
      <LI><I>List element 3</I> additional info3
      <LI><I>List element 4</I> additional info4
      </UL>
    
    <!-- many more elements like the ones above --> 
    

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

подходы

import regex as re

ре.финдалл

reg = re.compile("<li><b>(.*)\n\s*<ul>\n(\s*<li>.+\n)+\s*</ul>", re.IGNORECASE)
g_info = re.findall(reg, response.body)

Если мы посмотрим информацию g_info в приведенном выше примере, мы увидим, что для тех, у кого есть один элемент списка, все в порядке:

g_info[0] <- ('First list title</B> Additional info', "  <LI><I>List element 1</I> additional info\n")

Но когда есть несколько элементов подсписка, получается только последний.

g_info[1] <- ('Second list title</B> Additional info', "  <LI><I>List element 4</I> additional info4\n")

Я хотел бы, чтобы это было что-то вроде:

g_info[1] <- ('Second list title</B> Additional info', "  <LI><I>List element 1</I> additional info1\n", "  <LI><I>List element 2</I> additional info2\n", ...)

исследования и захваты

Используя то же регулярное выражение, я могу использовать функцию .captures для захвата всех элементов. Я немного настрою его, чтобы он работал с этим примером:

reg = re.compile("<li><b>(.*)\n\s*<ul>\n(\s*<li>.+\n){2,}\s*</ul>", re.IGNORECASE)
g_info = re.search(reg, response.body)

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

g_info.captures() <-- '<LI><B>Second list title</B> Additional info\n  <UL>\n  <LI><I>List element 1</I> additional info1\n  <LI><I>List element 2</I> additional info2\n ...'

Если бы я мог получить их все в этом формате, мне бы этого хватило.

re.findall и дополнительные циклы и фильтрация

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

reg = re.compile("(\s*<li>.+\n)", re.IGNORECASE)
g_info = re.findall(reg, response.body)

Я получаю что-то вроде этого:

g_info[0] <- '\n\n<LI><B>First list title</B> Additional info\n'
g_info[1] <- '\n  <LI><I>List element1</I> additional info\n'
g_info[2] <- '\n\n<LI><B>Second list title</B> Additional info\n'
g_info[3] <- '\n  <LI><I>List element</I> additional info1\n'
g_info[4] <- '  <LI><I>List element2</I> additional info2\n'
g_info[5] <- '  <LI><I>List element3</I> additional info3\n'

Решения?

Единственный рабочий подход, который я нашел, был последним, который имхо не элегантный. Не могли бы вы помочь мне найти лучшее решение? Спасибо


person isaacbernat    schedule 12.01.2014    source источник
comment
Как насчет использования чего-то вроде re.compile("<li>([^\r\n]+)", re.IGNORECASE) с findall? Это дает вам это (без новой строки или тега <LI>). Но это при условии, что я понял, чего вы на самом деле добивались. В противном случае я бы рекомендовал попробовать BeautifulSoup.   -  person Jerry    schedule 12.01.2014
comment
Каким должен быть ваш конечный результат?   -  person Jon Clements♦    schedule 12.01.2014


Ответы (2)


import re
pattern = re.compile("(?<=<li><b>).*?(?=</ul>)", re.IGNORECASE | re.DOTALL)
print re.findall(pattern, data)

Вывод

['First list title</B> Additional info\n  <UL>\n  <LI><I>List element 1</I> additional info\n  ',
 'Second list title</B> Additional info\n  <UL>\n  <LI><I>List element 1</I> additional info1\n  <LI><I>List element 2</I> additional info2\n  <LI><I>List element 3</I> additional info3\n  <LI><I>List element 4</I> additional info4\n  ']
person thefourtheye    schedule 12.01.2014

регулярное выражение для синтаксического анализа html не является хорошей идеей, и его следует по возможности избегать tags">RegEx соответствует открытым тегам, кроме автономных тегов XHTML

прежде чем идти по этому пути, я бы переоценил «они слишком сломаны» и попытался сделать все возможное, чтобы проанализировать/отладить их, см. Как анализировать некорректный HTML в python

person Guy Gavriely    schedule 12.01.2014