上下文
我正在使用 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 -->
我需要捕获列表标题(和附加信息),以及每个标题的所有嵌套元素及其附加信息。
方法
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)
如果我们在上面的例子中查看 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", ...)
重新搜索和.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'
解决方案?
我发现的唯一可行的方法是最后一种方法,恕我直言,这并不优雅。你能帮我找到更好的解决方案吗?谢谢
最佳答案
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 ']
关于Python正则表达式findall捕获重复组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21074790/