Python正则表达式匹配元素与一个正则表达式匹配

时间:2013-03-28 15:52:24

标签: python regex

假设我有这个HTML代码:

<table id="test_table">
    <td>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
    </td>
</table>
<table id="test_table2">
    <td>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
    </td>
</table>

我想只在#test_table中匹配hrefs并迭代它们?我试过这样的事情:

<table id="test_table">\s*<td>(\s*<a href="(?P<url>.*?)">(?P<anchor>.*?)</a>\n)*

但这只与第一个元素匹配,我被困在这几个小时,我无法正确,谢谢你的帮助。

4 个答案:

答案 0 :(得分:3)

对于HTML,请使用正确的工具。请改用HTML解析器,例如BeautifulSoup

from bs4 import BeautifulSoup

soup = BeautifulSoup(html)

table = soup.find('table', id='test_table')
for anchor in table.find_all('a'):
    print anchor['href'], anchor.string

不要使用正则表达式,将HTML与此类表达式匹配会变得太复杂,太快。不要那样做。

答案 1 :(得分:1)

不要使用正则表达式来解析HTML,为此使用LXML。

使用iPython的示例(测试是您的文件)

In [55]: import lxml.html

In [56]: x = lxml.html.fromstring(open("test").read())

In [57]: for i in x.iterlinks():
    print i # print ALL links 
   ....:     
(<Element a at 0x1bb7110>, 'href', '#', 0)
(<Element a at 0x1ba8c50>, 'href', '#', 0)
(<Element a at 0x1ba89b0>, 'href', '#', 0)
(<Element a at 0x1ba8e30>, 'href', '#', 0)
(<Element a at 0x1ba8c50>, 'href', '#', 0)
(<Element a at 0x1ba89b0>, 'href', '#', 0)
(<Element a at 0x1ba8e30>, 'href', '#', 0)
(<Element a at 0x1ba8c50>, 'href', '#', 0)
(<Element a at 0x1bb7110>, 'href', '#', 0)
(<Element a at 0x1ba89b0>, 'href', '#', 0)
(<Element a at 0x1ba8c50>, 'href', '#', 0)
(<Element a at 0x1ba8e30>, 'href', '#', 0)
(<Element a at 0x1ba89b0>, 'href', '#', 0)
(<Element a at 0x1ba8c50>, 'href', '#', 0)
(<Element a at 0x1ba8e30>, 'href', '#', 0)
(<Element a at 0x1ba89b0>, 'href', '#', 0)

In [58]: path = x.xpath("./table[@id='test_table']")[0]

In [59]: for i in path.iterlinks():
   ....:     print i
   ....:     
(<Element a at 0x1bb7110>, 'href', '#', 0)
(<Element a at 0x1bb7050>, 'href', '#', 0)
(<Element a at 0x1ba89b0>, 'href', '#', 0)
(<Element a at 0x1ba8e30>, 'href', '#', 0)
(<Element a at 0x1bb7050>, 'href', '#', 0)
(<Element a at 0x1ba89b0>, 'href', '#', 0)
(<Element a at 0x1ba8e30>, 'href', '#', 0)
(<Element a at 0x1bb7050>, 'href', '#', 0)

使用Xpath可以让事情变得更容易,减少头痛和减少咖啡;)

答案 2 :(得分:0)

另请查看PyQuery,我喜欢它提供的jQuery熟悉程度:

>>> from pyquery import PyQuery as pq
>>> html = '''<table id="test_table">
...     <td>
...         <a href="#">#</a>
...         <a href="#">#</a>
...         <a href="#">#</a>
...         <a href="#">#</a>
...         <a href="#">#</a>
...         <a href="#">#</a>
...         <a href="#">#</a>
...         <a href="#">#</a>
...     </td>
... </table>
... <table id="test_table2">
...     <td>
...         <a href="#">#33</a>
...         <a href="#">#33</a>
...         <a href="#">#33</a>
...         <a href="#">#33</a>
...         <a href="#">#33</a>
...         <a href="#">#33</a>
...         <a href="#">#33</a>
...         <a href="#">#33</a>
...     </td>
... </table>'''
>>> d = pq(html)
>>> for a in d('#test_table').find('a'):
...     print a.attrib.items()
...
...
[('href', '#')]
[('href', '#')]
[('href', '#')]
[('href', '#')]
[('href', '#')]
[('href', '#')]
[('href', '#')]
[('href', '#')]

答案 3 :(得分:0)

您的正则表达式确实捕获HTML的正确部分。

问题是当你有一个以+或*结尾的捕获组(例如((?P<anchor>.*?)*)时,groups()方法只返回最后一组。

例如:

sss='''<table id="test_table">
    <td>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#">#</a>
        <a href="#last_url">#last_anch</a>
    </td>
</table>
<table id="test_table2">
    <td>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
        <a href="#">#33</a>
    </td>
</table>'''

import re

res='<table id="test_table">\s*<td>(\s*<a href="(?P<url>.*?)">(?P<anchor>.*?)</a>\n)*'
m=re.search(res,sss)
print m.groups()

<强>输出:

('        <a href="#last_url">#last_anch</a>\n', '#last_url', '#last_ach')

我不同意你应该总是使用像BeautifulSoup这样的专用HTML处理器的其他海报。这些开销可能很高,而且对于简单的任务,可能需要更长的代码。

另一种方法是使用以下两个re:

res='<table id="test_table">.*?</table>'
mm=re.search(res,sss,re.DOTALL)
results=[m.group('url','anchor') for m in re.finditer('<a href="(?P<url>.*?)">(?P<anchor>.*?)</a>',mm.group())]