Python正则表达式可以捕获重复的组

时间:2014-01-12 12:49:58

标签: python regex scrapy findall

上下文

我正在使用python regex来解析一些HTML,因为它们太破碎而无法使用更适合这些任务的处理器(例如scrapy选择器)。我要解析的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 --> 
    

我需要捕获List标题(和其他信息),并为每个标题捕获所有嵌套元素及其附加信息。

途径

import regex as re

re.findall

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

如果我们在上面的例子中看到info 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", ...)

re.search和.captures

使用相同的正则表达式,我可以使用.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'

解决方案?

我找到的唯一可行的方法是最后一个,这个方法并不优雅。你能帮我找到更好的解决方案吗?感谢

2 个答案:

答案 0 :(得分: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  ']

答案 1 :(得分:2)

正则表达式解析HTML不是一个好主意,应该尽可能避免RegEx match open tags except XHTML self-contained tags

在走这条路之前,我会重新评估“它们太破碎了”并尝试尽力解析/调试它们,请参阅How to parse malformed HTML in python