Контекст
Я использую 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'
Решения?
Единственный рабочий подход, который я нашел, был последним, который имхо не элегантный. Не могли бы вы помочь мне найти лучшее решение? Спасибо
re.compile("<li>([^\r\n]+)", re.IGNORECASE)
сfindall
? Это дает вам это (без новой строки или тега<LI>
). Но это при условии, что я понял, чего вы на самом деле добивались. В противном случае я бы рекомендовал попробовать BeautifulSoup. - person Jerry   schedule 12.01.2014