2016-06-20 20 views
0

Ich versuche Tupel von einer url und ich habe es geschafft, zu extrahieren String Text und Tupeln mit dem re.search(pattern_str, text_str) zu extrahieren. Allerdings blieb ich stecken, als ich versuchte, eine Liste von Tupeln mit re.findall(pattern_str, text_str) zu extrahieren.Wie extrahieren Tupel mit Fundall?

Der Text sieht so aus:

<li> 
    <a href="11111"> 
    some text 111 
    <span class="some-class"> 
     #11111 
    </span> 
    </a> 
</li><li> 
    <a href="22222"> 
    some text 222 
    <span class="some-class"> 
     #22222 
    </span> 
    </a> 
</li><li> 
    <a href="33333"> 
    some text 333 
    <span class="some-class"> 
     #33333 
    </span> 
    </a> 
... # repeating 
... 
... 

und ich bin mit dem folgenden Muster & Code die Tupel zu extrahieren:

text_above = "..." # this is the text above 
pat_str = '<a href="(\d+)">\n(.+)\n<span class' 
pat = re.compile(pat_str) 
# following line is supposed to return the numbers from the 2nd line 
# and the string from the 3rd line for each repeating sequence 
list_of_tuples = re.findall(pat, text_above) 

for t in list_of tuples: 
    # supposed to print "11111 -> blah blah 111" 
    print(t[0], '->', t[1]) 

Vielleicht etwas seltsam & unmöglich Ich versuche vielleicht seine besser, die Daten mit primitiven String-Manipulationen zu extrahieren ... Aber für den Fall, dass es eine Lösung gibt?

+5

Sie analysieren nicht HTML mit regulären Ausdrücken. Verwenden Sie einen Parser wie eine schöne Suppe! –

Antwort

1

Wie in den Kommentaren vorgeschlagen, den Einsatz ein hTML-Parser wie BeautifulSoup:

from bs4 import BeautifulSoup 

h = """<li> 
    <a href="11111"> 
    some text 111 
    <span class="some-class"> 
     #11111 
    </span> 
    </a> 
</li><li> 
    <a href="22222"> 
    some text 222 
    <span class="some-class"> 
     #22222 
    </span> 
    </a> 
</li><li> 
    <a href="33333"> 
    some text 333 
    <span class="some-class"> 
     #33333 
    </span> 
    </a>""" 

soup = BeautifulSoup(h) 

Sie die href und die previous_sibling auf die Spanne zu erreichen:

print([(a["href"].strip(), a.span.previous_sibling.strip()) for a in soup.find_all("a")]) 
[('11111', u'some text 111'), ('22222', u'some text 222'), ('33333', u'some text 333')] 

Oder href und dem ersten Inhalt f rom den Anker:

print([(a["href"].strip(), a.contents[0].strip()) for a in soup.find_all("a")]) 

Oder mit .find(text=True) nur den Tag-Text zu erhalten und nicht von den Kindern.

[(a["href"].strip(), a.find(text=True).strip()) for a in soup.find_all("a")] 

Auch wenn Sie nur die Anker innerhalb der Liste Tags möchten, können Sie speziell diejenigen analysieren:

[(a["href"].strip(), a.contents[0].strip()) for a in soup.select("li a")] 
+0

Nun, meine Absicht war es zu lernen und sich an 're.search()' & 're.findall()' zu gewöhnen. Ich weiß, dass ich leicht mit 'bs4' umgehen kann, aber ich versuche es ein andermal (nachdem ich * regex * gelernt habe). – ssd

+0

Es brachte mich dazu, meine Haare rauszuziehen, aber schließlich habe ich es mit ** Regex ** gemacht. Allerdings, um fair zu sein, als ich es mit w ** bs4 ** ... Voila! Das spart Zeit wie kein anderer. Vielen Dank. – ssd

2

Ihre Regex berücksichtigt nicht den Leerraum (Einrückung) zwischen \n und <span. (Und weder die Leerzeichen am Anfang der Zeile, die Sie aufnehmen möchten, aber das ist nicht so sehr ein Problem.), Es zu beheben, einige \s* könnte hinzufügen:

pat_str = '<a href="(\d+)">\n\s*(.+)\n\s*<span class' 
+0

Nun ... Das ist meine Schuld. Es schien eine vernünftige Lösung zu sein; Also habe ich 'pat_str = ' [\ n \ s] * (. +) [\ n \ s] * ssd

+1

@ merkez3110 Regex verhält sich standardmäßig gierig. Wie Sie es getan haben, wird es versuchen, die größtmögliche Übereinstimmung zu finden, und diese Übereinstimmung wird von der ersten "href" bis zur letzten "span" reichen. Entweder machen Sie die nicht-gierigen mit '*?' Statt '*' oder benutzen Sie einfach meine Variante. –

+0

Jetzt komme ich irgendwo ... Nur eine letzte Frage, wenn es Ihnen nichts ausmacht: Ist es eine bessere Lösung, die 're.DOTALL' in der Kompilierungsanweisung zu verwenden oder sollte ich es den' \ n' Zeichen überlassen ? – ssd