匹配所有链接,除了括号中开头的链接

时间:2016-02-28 22:34:55

标签: python regex

我想从一段文字中提取所有链接目标。例如,从以下

开始
data1 = '<a href="a"> a (d <a href="b"> f) b (<a href="c">) d <a href="d"> d(<a href="e">)'

我想得到['a','b','c','d','e']。

但是,我想跳过括号中的任何链接,并且在不在括号中的链接之前发生。在第一个不在括号中的链接之后,括号变得无关紧要,我想匹配所有链接。所以,对于字符串

data2 = 'a (d <a href="b"> f) b (<a href="c">) d <a href="d"> d(<a href="e">)'

我想得到['d','e']。

我尝试过使用正则表达式模块。以下表达式捕获所有链接(带括号和不带括号):

regex.match('(?:.*?<a href="([^>])+">)*', data2).captures(1)

如何跳过括号中的初始链接?

2 个答案:

答案 0 :(得分:2)

解析HTML并不是一件容易的事,并且使用regexp并不容易,你最好使用像html5lib这样真正优秀的HTML解析器。解析HTML后,您可以使用简单的状态机或任何您喜欢的方式发现有趣的值:

import html5lib

document = html5lib.parse('a (d <a href="b"> f) b (<a href="c">) d <a href="d"> d(<a href="e">)')
tokens = []
for element in document.getiterator():
    tokens.append((element.tag[element.tag.index('}')+1:], element))
    if element.text is not None:
        for char in element.text:
            tokens.append(('text', char))

state = 'OUT_OF_PARENTHESIS'
for token_type, value in tokens:
    if state == 'OUT_OF_PARENTHESIS':
        if token_type == 'a':
            state = 'GOT_AN_A_OUT_OF_PARENTHESIS'
            print(value.attrib)
            continue
    if state == 'OUT_OF_PARENTHESIS':
        if token_type == 'text' and '(' in value:
            state = 'IN_PARENTHESIS'
            continue
    if state == 'IN_PARENTHESIS':
        if token_type == 'text' and ')' in value:
            state = 'OUT_OF_PARENTHESIS'
            continue
    if state == 'GOT_AN_A_OUT_OF_PARENTHESIS':
        if token_type == 'a':
            print(value.attrib)

答案 1 :(得分:1)

所以基本上任务是在括号内放置链接,然后返回余数中的所有链接。您可以将(恰当命名的)itertools.dropwhile与正则表达式结合使用。

这是我将如何做到的:

from itertools import dropwhile

def get_links(s):
    without_paren = r'<a href="(?P<WITHOUT_PAREN>[^"]+)">'
    with_paren = r'\(.*?<a href="(?P<WITH_PAREN>[^"]+)">.*?\)'
    master_pattern = with_paren + '|' + without_paren  # try with_paren first
    it = re.finditer(master_pattern, s)
    # Drop matches in `it` until we hit the first without_paren match
    # and yield every match from there onwards
    for mo in dropwhile(lambda mo: mo.lastgroup == 'WITH_PAREN', it):
        yield mo.group(mo.lastgroup)

尝试使用您的数据:

>>> print(list(get_links(data1)))
['a', 'b', 'c', 'd', 'e']
>>> print(list(get_links(data2)))
['d', 'e']

人们通常会告诉你使用专门的库解析HTML等,它们通常都是正确的。 HTML不是一种常规语言,正则表达式在其完全复杂性方面无法真正处理它。但你似乎正在处理一个常规的&#34;这里有一些数据,正则表达式可能正常工作。