HTMLparser nächstes Tag finden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
error1
User
Beiträge: 3
Registriert: Montag 1. Oktober 2012, 21:12

Hallo,
ich bin recht unerfahren in python und Programmieren allgemein. Für kleinere Scripts reicht es jedoch noch.

Nun stehe ich vor der Aufgabe HTML mittles html.parser zu parsen (Python 3).

Ich schaffe es Text „Text1“ zu Filter bei Tags in der Form von:

<td class="Class1"> Text1 </td>

Indem ich Tags <td> mit class “Class1” filtere und mittels

def handle_data(self, data):
print(data)

rausschreibe

Nun kommt es vor das in der HTML außerdem Sachen in der Form von:

<td class="ClassB”> Some Text</td>
<td class="ClassB”> Some Text1</td>
<td class="ClassB”> Some Text2</td>
.
.
</tr>
<tr class="new"><td class="ClassA">Text A</td>
<td class="ClassB”> Text Eins A</td>
</tr>
</tr>
<tr class="new"><td class="ClassA">Text A</td>
<td class="ClassB”> Text Eins B</td>
</tr>

Nun kann ich das Script davor nicht nutzen das ClassB öfter vorkommt ich jedoch nur den Text brauche (Text Eins) wenn „Text A“ in dem Feld davor steht.
Wäre es möglich class „new“ zu filtern und sich dann zwei Tags runter zu hangeln?
Habe da leider nichts gefunden

Gruß und Danke
Error1
BlackJack

@error1: Ich würde da eher einen Parser verwenden der mit real existierendem HTML klar kommt und auch eine einfachere Navigation im Ergebnis erlaubt. `lxml.html` oder `BeautifulSoup` sind dafür geeignet. Ich weiss allerdings nicht ob und welcher davon für Python 3 verfügbar ist.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

lxml funktioniert mit Python 2.x und Python 3.x

Beautiful Soap 4 ebenso.
BlackJack

Na dann kann man sich ja zum Beispiel für `lxml` entscheiden und hat dort die Auswahl zwischen `cssselect()` und `xpath()`. Falls ich die Kriterien richtig verstanden habe:

Code: Alles auswählen

from lxml import html


def main():
    root = html.parse('test.html').getroot()
    # 
    # Variante 1
    # 
    nodes = (
        n.itersiblings('td').next()
        for n in root.cssselect('tr.new td.ClassA')
        if n.text == 'Text A'
    )
    result = [n.text.strip() for n in nodes if n.get('class') == 'ClassB']
    print result
    # 
    # Variante 2
    # 
    result = [
        s.strip() for s in root.xpath(
            '//tr[@class="new"]'
            '/td[@class="ClassA" and text()="Text A"]'
            '/following-sibling::td[@class="ClassB"][1]'
            '/text()'
        )
    ]
    print result


if __name__ == '__main__':
    main()
error1
User
Beiträge: 3
Registriert: Montag 1. Oktober 2012, 21:12

Hallo,

vielen dank für die anregungen. Habe sowas schon vermutet.
Ich werde es mal mit lxml versuchen.

Der Test ode an im Schnelltest nicht funktioniert aber ich werde mich mal in lxml einlesen und gucken ob ich es zustande bekommen. Ansonsten melde ich mich bestimmt nochmal.

Gruß

EDIT: hab sowas ähnliches wie deine xpath variante erstellt. funktioniert bestens. Danke
error1
User
Beiträge: 3
Registriert: Montag 1. Oktober 2012, 21:12

Hi,

ich stehe nun vor folgendem problem ich habe tags in derform von

<td class="ClassA"> Text <a href="..."> Zusatz </a></td>

wie kriege ich denn nur "Text Zusatz" raus.

Es würde funktionieren mit a = tree.xpath( //td[@class="ClassA"]/text())
was "Text" auswirft
+
b = tree.xpath(//td[@class="ClassA"]/a/text())
was "Zusatz" auswirft
und dann zusammenfügen

Nun kommt es aber vor das manchmal
<td class="ClassA"> Text1 <a href="..."> Zusatz1 </a></td>
...
<td class="ClassA"> Text2 </td>
...
<td class="ClassA"> Text3 <a href="..."> Zusatz3 </a></td>

im html steht.
Da würde ja dann 2 Listen mit ungleicher Länge ausgeben.

Gibt hier ne leichte Lösung?

Gruß


da steht
BlackJack

@error1: Suche nur nach den Knoten mit der gewünschten CSS-Klasse und rufe auf denen dann die `text_content()`-Methode auf.
Antworten