2014-12-12 11 views
5

Ich habe diesen HTML:Wie wähle ich alle untergeordneten Texte aus, aber ohne ein Tag mit Scapys XPath?

<div id="content"> 
    <h1>Title 1</h1><br><br> 

    <h2>Sub-Title 1</h2> 
    <br><br> 
    Description 1.<br><br>Description 2. 
    <br><br> 

    <h2>Sub-Title 2</h2> 
    <br><br> 
    Description 1<br>Description 2<br> 
    <br><br> 

    <div class="infobox"> 
     <font style="color:#000000"><b>Information Title</b></font> 
     <br><br>Long Information Text 
    </div> 
</div> 

Ich möchte alle Texte in <div id="content"> mit XPath in Scrapy zu bekommen, aber <div class="infobox"> ‚s Inhalt auszuschließen, so ist das erwartete Ergebnis wie folgt aus:

Title 1 


Sub-Title 1 


Descripton 1. 

Descripton 2. 


Sub-Title 2 


Descripton 1. 
Descripton 2. 

Aber ich Ich habe noch nicht den ausschliessenden Teil erreicht, ich kämpfe immer noch um den Text von <div id="content">.

Ich habe dies versucht:

response.xpath('//*[@id="content"]/text()').extract() 

Aber es gibt nur Description 1. und Description 2. von beiden Sub-Titel.

Dann habe ich versucht:

response.xpath('//*[@id="content"]//*/text()').extract() 

Es nur Title 1 zurückkehrt, Sub-Title 1, Sub-Title 2, Information Title und Long Information Text.


So gibt es zwei Fragen hier:

  1. Wie kann ich alle von Kindern Text von content div bekommen?
  2. Wie kann das div von der Auswahl ausgeschlossen werden?

Antwort

10

Verwenden Sie die descendant:: Achse geordneten Textknoten und Staat ausdrücklich feststellen, dass die Eltern dieser Textknoten darf kein div[@class='infobox'] Element sein.

Drehen der oben in einen XPath-Ausdruck:

//div[@id = 'content']/descendant::text()[not(parent::div/@class='infobox')] 

Dann wird das Ergebnis ähnlich ist (I mit einem Online-XPath-Tool getestet) den folgenden. Wie Sie sehen, erscheint der Textinhalt von div[@class='infobox'] nicht mehr im Ergebnis.

----------------------- 
Title 1 
----------------------- 
----------------------- 
Sub-Title 1 
----------------------- 
----------------------- 
Description 1. 
----------------------- 
Description 2. 
----------------------- 
----------------------- 
Sub-Title 2 
----------------------- 
----------------------- 
Description 1 
----------------------- 
Description 2 
----------------------- 
----------------------- 
----------------------- 

Was mit Ihrem Ansatz falsch?

Ihr erster Versuch:

//*[@id="content"]/text() 

in einfachem Englisch bedeutet:

Geben Sie für jedes Element (nicht unbedingt ein div) überall in dem Dokument, das ein Attribut @id hat, seine Wert ist "Inhalt". Geben Sie für dieses Element alle unmittelbaren untergeordneten Textknoten zurück.

Problem: Sie verlieren die Textknoten, die keine unmittelbares Kind der äußeren div sind, da sie in einem untergeordneten Elemente dieser div sind.


Ihr zweiter Versuch:

//*[@id="content"]//*/text() 

Verschiebt zu:

Geben Sie für jedes Element (nicht unbedingt einen div) überall in dem Dokument, das ein Attribut @id, hat seinen Wert "Inhalt" sein. Suchen Sie für dieses Element einen Knoten eines untergeordneten Elements und geben Sie alle Textknoten dieses untergeordneten Elements zurück.

Problem: Sie sind die unmittelbaren Kind Textknoten des div zu verlieren, da Sie nur an Textknoten suchen, die Kinder von Elementen sind die Nachkommen der div sind.


EDIT:

auf Ihren Kommentar Antwort:

//div[@id = 'content']/descendant::text()[not(ancestor::div/@class='infobox')] 

Für Ihre zukünftigen Fragen wenden Sie sich bitte sicher, dass die HTML machen zeigen Sie Vertreter Ihrer tatsächlichen Probleme ist.

+0

Hallo, danke für deine Antwort. Aber Ihre Ausschlusslösung funktioniert nicht, wenn das 'infobox'-div ein anderes untergeordnetes Element enthält, siehe mein editiertes HTML-Beispiel oben. – null

+1

@suud Ich habe meine Antwort bearbeitet. Wenn Sie 'ancestor ::' anstelle von 'parent :: 'verwenden, ignoriert der Ausdruck jeglichen Text innerhalb der Infobox, egal ob er sich in einem anderen Element befindet. –

+0

Danke, das hat mein Problem gelöst. Was ich brauchte, war '// div [@ class =" body "]/descendant :: text() [nicht (ancestor :: script)]' (als Beispiel) – saeedgnu

Verwandte Themen