2016-02-28 76 views
-1

我想從一段文本中提取所有鏈接目標。因此,例如,從以下匹配所有鏈接,除了括號中的開頭部分

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) 

我怎麼能跳過括號初始鏈接?

+0

我試圖澄清它:我想在第一個不在括號中的鏈接之前忽略括號中的任何鏈接。在第一個鏈接之後,括號不再重要。 – Daniel

回答

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不是一種常規語言,正則表達式無法真正處理它的完整複雜性。但是你似乎正在處理這種「常規」的數據,正則表達式可能正常工作。

2

解析HTML不是一件容易的事,用regexp也不容易,你最好使用一個真正的HTML解析器,比如html5lib,這真的很棒。一旦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)