Python正则表达式findall捕获重复组

标签 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 --> 
    

我需要捕获列表标题(和附加信息),以及每个标题的所有嵌套元素及其附加信息。

方法

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/

相关文章:

c# - 将屏幕截图从 C# Unity 项目发送到 Python 套接字

使用 db-api 进行 Python 类型提示

python-3.x - Python Scrapy:在“href”中查找文本

java - html 文件内内联后端代码

javascript - 从JS的特定数字中删除逗号分隔

javascript - 正则表达式删除第一个字符的特殊字符、空格和数字

regex - 根据创建日期移动文件

Python + Scrapy + MySQL UTF8编码错误

python - 使用 pip 安装 Python 模块

python - 关于 Python 中的 os.fork() 函数