Python:在元组中存储许多正则表达式匹配?

时间:2012-03-24 20:28:09

标签: python html regex parsing

我正在尝试使用正则表达式创建一个简单的基于Python的HTML解析器。我的问题是试图让我的正则表达式搜索查询找到所有可能的匹配,然后将它们存储在元组中。

假设我有一个页面,其中存储了以下变量HTMLtext

<ul>
<li class="active"><b><a href="/blog/home">Back to the index</a></b></li>
<li><b><a href="/blog/about">About Me!</a></b></li>
<li><b><a href="/blog/music">Audio Production</a></b></li>
<li><b><a href="/blog/photos">Gallery</a></b></li>
<li><b><a href="/blog/stuff">Misc</a></b></li>
<li><b><a href="/blog/contact">Shoot me an email</a></b></li>
</ul>

我想对此文本执行正则表达式搜索,并返回包含每个链接的最后一个URL目录的元组。所以,我想回复这样的事情:

pages = ["home", "about", "music", "photos", "stuff", "contact"]

到目前为止,我可以使用正则表达式搜索一个结果:

pages = [re.compile('<a href="/blog/(.*)">').search(HTMLtext).group(1)]

运行此表达式会生成pages = ['home']

如何让正则表达式搜索继续整个文本,将匹配的文本附加到此元组?

(注意:I know I probably should NOT be using regex to parse HTML。但我想知道如何做到这一点。)

5 个答案:

答案 0 :(得分:2)

使用re模块的findall功能:

pages = re.findall('<a href="/blog/([^"]*)">',HTMLtext)
print(pages)

输出:

['home', 'about', 'music', 'photos', 'stuff', 'contact']

答案 1 :(得分:2)

您的模式不适用于所有输入,包括您的输入。 .*过于贪婪(从技术上讲,它会找到最大匹配),导致它成为第一个href和最后一个相应的关闭。解决这个问题的两种最简单的方法是使用最小匹配,否则使用否定字符类。

# minimal match approach
pages = re.findall(r'<a\s+href="/blog/(.+?)">', 
                   full_html_text, re.I + re.S)

# negated charclass approach
pages = re.findall(r'<a\s+href="/blog/([^"]+)">',
                   full_html_text, re.I)

强制性警告

对于简单且合理的约束文本,正则表达式很好;毕竟,这就是我们在编辑HTML时在文本编辑器中使用正则表达式搜索和替换的原因!但是,对输入的了解越少,它就会变得越来越复杂,例如

  • 如果在<ahref之间有其他字段介入,例如<a title="foo" href="bar">
  • 套管问题,如<A HREF='foo'>
  • 空白问题
  • 替代引号,例如href='/foo/bar'而不是href="/foo/bar"
  • 嵌入式HTML评论

这不是关注的唯一清单;还有其他人。所以using regexes on HTML thus is possible,但是否是权宜之计取决于太多其他因素来判断。

然而,从您展示的小例子来看,它看起来完全适合您自己的情况。你只需要调整你的模式并调用正确的方法。

答案 2 :(得分:1)

使用findall代替search

>>> pages = re.compile('<a href="/blog/(.*)">').findall(HTMLtext)
>>> pages
['home', 'about', 'music', 'photos', 'stuff', 'contact']

答案 3 :(得分:1)

re.findall()函数和re.finditer()函数用于查找多个匹配项。

答案 4 :(得分:1)

要查找所有结果,请使用findall()。此外,您只需编译re一次,然后您就可以重复使用它。

href_re = re.compile('<a href="/blog/(.*)">')  # Compile the regexp once

pages = href_re.findall(HTMLtext)  # Find all matches - ["home", "about",