2016-07-06 6 views
1

Ich bin neu in der Verwendung von Xpath. Ich versuche, einige Daten in Python mit Xpath zu analysieren.Xpath folgende Geschwister bis zu einem anderen Geschwister

Parsen der folgende HTML:

<table> 
    <tr> 
     <td class="DT">29-04-14</td> 
     <td class="Regio">Text</td> 
     <td class="Md">Text</td> 
    </tr> 
    <tr> 
     <td></td> 
     <td></td> 
     <td class="SomeClass">Some other text</td> 
    </tr> 
    <tr> 
     <td></td> 
     <td></td> 
     <td class="SomeOtherClass">Some more text</td> 
    </tr> 
    <tr> 
     <td class="DT">22-04-14</td> 
     <td class="Regio">Text</td> 
     <td class="Md">Text</td> 
    </tr> 
    <tr> 
     <td></td> 
     <td></td> 
     <td class="OmsAm">more text</td> 
    </tr> 
    <tr> 
     <td class="DT">30-04-14</td> 
     <td class="Regio">Text</td> 
     <td class="Md">Text</td> 
    </tr> 
    <tr> 
     <td></td> 
     <td></td> 
     <td class="OmsBr">Some other Text</td> 
    </tr> 
    <tr> 
     <td></td> 
     <td></td> 
     <td class="OmsBr">More Text</td> 
    </tr> 
    <tr> 
     <td></td> 
     <td></td> 
     <td class="OmsBr">Some different text</td> 
    </tr> 
</table> 

Ich brauche alle <td> in folgenden Geschwister <tr> nach einem <tr> mit einigen Werten in seiner <td> s, aber bis die nächste <tr> mit einigen Werten in allen <td> s.

z. meine aktuelle Position einnimmt, wird die erste <tr>, würde ich diese Tabellenzellen benötigt:

<td class="SomeClass">Some other text</td> 
    <td class="SomeOtherClass">Some more text</td> 

meine aktuelle Position Angenommen wird, um die Tabellenzeile 4

<tr> 
    <td class="DT">22-04-14</td> 
    <td class="Regio">Text</td> 
    <td class="Md">Text</td> 
</tr> 

ich nur

<td class="OmsAm">more text</td> 
brauchen würde

Dies ist der Xpath, den ich benutze, um alle Geschwister zu bekommen <tr>, aber es bringt mich alle Follinwg Geschwister, und nicht Sie bis das Geschwister sollte es aufhören: ./following-sibling::tr/td[1][not(text()[1])]/..

Ich denke, ich muss die Kayesian Methode implementieren, aber ich verstehe das nicht in meinem Fall. Jede Hilfe würde wirklich geschätzt werden!

+0

ich nicht ernst 'Ich brauche alle in folgenden Geschwister nach einem mit einigen Werten in seiner s, aber bis zum nächsten mit einigen Werten in allen s.' – SomeDude

+0

Bitte zeigen Sie Ihren Python-Code. Ein XPath-Ausdruck, der dieses Problem löst, ist langatmig. Stattdessen sollten Sie einen relativ einfachen XPath-Ausdruck schreiben und die Ergebnisse dann mit Python verarbeiten. –

+0

Möchten Sie die '' s mit '' als Grenzen segmentieren? –

Antwort

0

ich die Frage werden, falsch interpretiert, aber wenn, für jede <tr><td class="DT">xx-xx-xx</td>, möchten Sie alle <tr> danach, und vor dem nächsten <tr><td class="DT">xx-xx-xx</td>, ein Muster, ist eine Schleife auf diese „Grenze“ <tr><td class="DT">xx-xx-xx</td> Elemente und Auswählen folgenden Geschwisterreihen mit eine Bedingung, wie viele "Grenzen" zuvor gefunden wurden.

Lassen Sie uns lxml verwenden, um zu veranschaulichen. Erstens haben wir ein Dokument von Ihrem Abtastwerteingang erstellen:

>>> import lxml.html 
>>> t = '''<table> 
...  <tr> 
...   <td class="DT">29-04-14</td> 
...   <td class="Regio">Text</td> 
...   <td class="Md">Text</td> 
...  </tr> 
...  <tr> 
...   <td></td> 
...   <td></td> 
...   <td class="SomeClass">Some other text</td> 
...  </tr> 
...  <tr> 
...   <td></td> 
...   <td></td> 
...   <td class="SomeOtherClass">Some more text</td> 
...  </tr> 
...  <tr> 
...   <td class="DT">22-04-14</td> 
...   <td class="Regio">Text</td> 
...   <td class="Md">Text</td> 
...  </tr> 
...  <tr> 
...   <td></td> 
...   <td></td> 
...   <td class="OmsAm">more text</td> 
...  </tr> 
...  <tr> 
...   <td class="DT">30-04-14</td> 
...   <td class="Regio">Text</td> 
...   <td class="Md">Text</td> 
...  </tr> 
...  <tr> 
...   <td></td> 
...   <td></td> 
...   <td class="OmsBr">Some other Text</td> 
...  </tr> 
...  <tr> 
...   <td></td> 
...   <td></td> 
...   <td class="OmsBr">More Text</td> 
...  </tr> 
...  <tr> 
...   <td></td> 
...   <td></td> 
...   <td class="OmsBr">Some different text</td> 
...  </tr> 
... </table>''' 
>>> doc = lxml.html.fromstring(t) 

Nun lassen Sie uns zählen diese <tr><td class="DT">xx-xx-xx</td>:

>>> doc.xpath('//table/tr[td/@class="DT"]') 
[<Element tr at 0x7f948ab00548>, <Element tr at 0x7f948ab005e8>, <Element tr at 0x7f948ab00638>] 
>>> doc.xpath('count(//table/tr[td/@class="DT"])') 
3.0 
>>> list(enumerate(doc.xpath('//table/tr[td/@class="DT"]'), start=1)) 
[(1, <Element tr at 0x7f948ab00548>), (2, <Element tr at 0x7f948ab005e8>), (3, <Element tr at 0x7f948ab00638>)] 

Wir können auf diesen Reihen Schleife und die Zeilen auswählen, die nach dem in dem Dokument (wir kommen ‚ll Textknoten auswählen zu‚sehen‘, welche Zeile diese sind:

>>> for cnt, row in enumerate(doc.xpath('//table/tr[td/@class="DT"]'), start=1): 
...  print(row.xpath('./following-sibling::tr/td/text()')) 
... 
['Some other text', 'Some more text', '22-04-14', 'Text', 'Text', 'more text', '30-04-14', 'Text', 'Text', 'Some other Text', 'More Text', 'Some different text'] 
['more text', '30-04-14', 'Text', 'Text', 'Some other Text', 'More Text', 'Some different text'] 
['Some other Text', 'More Text', 'Some different text'] 

Wir Auswahl zu viele Zeilen in jeder Iteration alle Zeilen bis zum Ende des <table>. Wir benötigen eine zusätzliche "Ende" -Bedingung für die folgenden Zeilen.

Wir sind die tr[td/@class="DT"] in der Schleife zu zählen, so können wir überprüfen, wie viele vorhergehenden tr[td/@class="DT"] jede Zeile hat:

Für den 1. Satz:

row.xpath('./following-sibling::tr[count(./preceding-sibling::tr[td/@class="DT"])=1] 

Für die 2.:

row.xpath('./following-sibling::tr[count(./preceding-sibling::tr[td/@class="DT"])=2] 

usw.

Also, in der Schleife, können wir die aktuelle Zählung mit einem XPath-Variable mit lxml (an underrated XPath feature supported by lxml) verwenden:

>>> for cnt, row in enumerate(doc.xpath('//table/tr[td/@class="DT"]'), start=1): 
...  print(row.xpath('./following-sibling::tr[count(./preceding-sibling::tr[td/@class="DT"])=$count]', count=cnt)) 
... 
[<Element tr at 0x7f948ab00548>, <Element tr at 0x7f948ab005e8>, <Element tr at 0x7f948ec02f98>] 
[<Element tr at 0x7f948ab00548>, <Element tr at 0x7f948ab00638>] 
[<Element tr at 0x7f948ab00548>, <Element tr at 0x7f948ab005e8>, <Element tr at 0x7f948ab00688>] 
>>> 

Hm, wir dir 1 Zeile zu viel in jeder Iteration.

Das ist, weil <tr><td class="DT">30-04-14</td> auch 1 <tr><td class="DT"> vorhergehenden hat

Wir können ein zusätzliches Prädikat hinzufügen zum Auswählen von Zeilen, die ein Recht sieht <td class="DT">

>>> for cnt, row in enumerate(doc.xpath('//table/tr[td/@class="DT"]'), start=1): 
...  print(row.xpath(''' 
...   ./following-sibling::tr[count(./preceding-sibling::tr[td/@class="DT"])=$count] 
...        [not(td/@class="DT")]''', count=cnt)) 
... 
[<Element tr at 0x7f948ab00548>, <Element tr at 0x7f948ab005e8>] 
[<Element tr at 0x7f948ab00548>] 
[<Element tr at 0x7f948ab00548>, <Element tr at 0x7f948ab005e8>, <Element tr at 0x7f948ab00688>] 
>>> 

Die Anzahl der Ergebnisse pro Iteration nicht haben. Lassen Sie uns schließlich Textknoten mit überprüfen:

>>> for cnt, row in enumerate(doc.xpath('//table/tr[td/@class="DT"]'), start=1): 
...  print(row.xpath(''' 
...   ./following-sibling::tr[count(./preceding-sibling::tr[td/@class="DT"])=$count] 
...        [not(td/@class="DT")] 
...    /td/text()''', count=cnt)) 
... 
['Some other text', 'Some more text'] 
['more text'] 
['Some other Text', 'More Text', 'Some different text'] 
>>> 
+0

Wow, tolle Erklärung und funktioniert perfekt! Danke vielmals! – Gino

Verwandte Themen