2017-08-30 4 views
2

Ich versuche, this Website mit scrapy zu kratzen. Die Seitenstruktur sieht wie folgt aus:wie man Texte zwischen zwei Elementen auswählt und extrahiert?

<div class="list"> 
    <a id="follows" name="follows"></a> 
<h4 class="li_group">Follows</h4> 
<div class="soda odd"><a href="...">Star Trek</a></div> 
<div class="soda even"><a href="...</a></div> 
<div class="soda odd"><a href="..">Star Trek: The Motion Picture</a></div> 
<div class="soda even"><a href="..">Star Trek II: The Wrath of Khan</a></div> 
<div class="soda odd"><a href="..">Star Trek III: The Search for Spock</a></div> 
<div class="soda even"><a href="..">Star Trek IV: The Voyage Home</a></div> 
    <a id="followed_by" name="followed_by"></a> 
<h4 class="li_group">Followed by</h4> 
<div class="soda odd"><a href="..">Star Trek V: The Final Frontier</a></div> 
<div class="soda even"><a href="..">Star Trek VI: The Undiscovered Country</a></div> 
<div class="soda odd"><a href="..">Star Trek: Deep Space Nine</a></div> 
<div class="soda even"><a href="..">Star Trek: Generations</a></div> 
<div class="soda odd"><a href="..">Star Trek: Voyager</a></div> 
<div class="soda even"><a href="..">First Contact</a></div> 
    <a id="spin_off" name="spin_off"></a> 
<h4 class="li_group">Spin-off</h4> 
<div class="soda odd"><a href="..">Star Trek: The Next Generation - The Transinium Challenge</a></div> 
<div class="soda even"><a href="..">A Night with Troi</a></div> 
<div class="soda odd"><a href="..">Star Trek: Deep Space Nine</a></div 
</div> 

ich auswählen möchten und extrahieren Sie die Texte zwischen: <h4 class="li_group">Follows</h4> und <h4 class="li_group">Followed by</h4> dann Texte zwischen <h4 class="li_group">Followed by</h4> und <h4 class="li_group">Spin-off</h4>
ich diesen Code versucht:

def parse(self, response): 
    for sel in response.css("div.list"): 
     item = ImdbcoItem() 
     item['Follows'] = sel.css("a#follows+h4.li_group ~ div a::text").extract(), 
     item['Followed_by'] = sel.css("a#vfollowed_by+h4.li_group ~ div a::text").extract(), 
     item['Spin_off'] = sel.css("a#spin_off+h4.li_group ~ div a::text").extract(), 
    return item 

Aber die erster Artikel extrahiert alle Divs nicht nur divs zwischen <h4 class="li_group">Follows</h4> und <h4 class="li_group">Followed by</h4>
Jede Hilfe wäre wirklich Helpfu l !!

+0

nur in Fällen hilft es, imdb.com hat eine (un) offizielle API wo? Sie können alle diese Daten sauber bekommen, wenn ich mich gut erinnere. – Neil

Antwort

2

Ein Extraktionsmuster I für diese Fälle verwenden möchte, ist:

  • Schleife über die "Grenzen" (hier h4 Elemente)
  • , während sie von 1
  • beginnend Aufzählen
  • mit XPath following-sibling Achse, wie in @ Andersson Antwort, um Elemente vor der nächsten Grenze,
  • und sie Filterung durch die Anzahl des vorangehenden „Grenze“ Elemente zu zählen, da wir von unserer Aufzählung wissen, wo wir

Dies wäre die Schleife sind:

$ scrapy shell 'http://www.imdb.com/title/tt0092455/trivia?tab=mc&ref_=tt_trv_cnn' 
(...) 
>>> for cnt, h4 in enumerate(response.css('div.list > h4.li_group'), start=1): 
...  print(cnt, h4.xpath('normalize-space()').get()) 
... 
1 Follows  
2 Followed by  
3 Edited into  
4 Spun-off from  
5 Spin-off  
6 Referenced in  
7 Featured in  
8 Spoofed in  

Und dies ist ein Beispiel für die Verwendung die Aufzählungselemente zwischen den Grenzen zu erhalten (beachten Sie, dass diese Verwendung von XPath-Variablen mit $cnt im Ausdruck und Weitergabe cnt=cnt in .xpath()):

>>> for cnt, h4 in enumerate(response.css('div.list > h4.li_group'), start=1): 
...  print(cnt, h4.xpath('normalize-space()').get()) 
...  print(h4.xpath('following-sibling::div[count(preceding-sibling::h4)=$cnt]', 
         cnt=cnt).xpath(
          'string(.//a)').getall()) 
... 
1 Follows  
['Star Trek', 'Star Trek: The Animated Series', 'Star Trek: The Motion Picture', 'Star Trek II: The Wrath of Khan', 'Star Trek III: The Search for Spock', 'Star Trek IV: The Voyage Home'] 
2 Followed by  
['Star Trek V: The Final Frontier', 'Star Trek VI: The Undiscovered Country', 'Star Trek: Deep Space Nine', 'Star Trek: Generations', 'Star Trek: Voyager', 'First Contact', 'Star Trek: Insurrection', 'Star Trek: Enterprise', 'Star Trek: Nemesis', 'Star Trek', 'Star Trek Into Darkness', 'Star Trek Beyond', 'Star Trek: Discovery', 'Untitled Star Trek Sequel'] 
3 Edited into  
['Reading Rainbow: The Bionic Bunny Show', 'The Unauthorized Hagiography of Vincent Price'] 
4 Spun-off from  
['Star Trek'] 
5 Spin-off  
['Star Trek: The Next Generation - The Transinium Challenge', 'A Night with Troi', 'Star Trek: Deep Space Nine', "Star Trek: The Next Generation - Future's Past", 'Star Trek: The Next Generation - A Final Unity', 'Star Trek: The Next Generation: Interactive VCR Board Game - A Klingon Challenge', 'Star Trek: Borg', 'Star Trek: Klingon', 'Star Trek: The Experience - The Klingon Encounter'] 
6 Referenced in  
(...) 

Hier ist, wie Sie, dass zu füllen und Artikel verwenden könnten (hier, ich bin für Abbildung nur eine einfache DIKT):

>>> item = {} 
>>> for cnt, h4 in enumerate(response.css('div.list > h4.li_group'), start=1): 
...  key = h4.xpath('normalize-space()').get().strip() # there are some non-breaking spaces 
...  if key in ['Follows', 'Followed by', 'Spin-off']: 
...   values = h4.xpath('following-sibling::div[count(preceding-sibling::h4)=$cnt]', 
...      cnt=cnt).xpath(
...       'string(.//a)').getall() 
...   item[key] = values 
... 

>>> from pprint import pprint 
>>> pprint(item) 
{'Followed by': ['Star Trek V: The Final Frontier', 
       'Star Trek VI: The Undiscovered Country', 
       'Star Trek: Deep Space Nine', 
       'Star Trek: Generations', 
       'Star Trek: Voyager', 
       'First Contact', 
       'Star Trek: Insurrection', 
       'Star Trek: Enterprise', 
       'Star Trek: Nemesis', 
       'Star Trek', 
       'Star Trek Into Darkness', 
       'Star Trek Beyond', 
       'Star Trek: Discovery', 
       'Untitled Star Trek Sequel'], 
'Follows': ['Star Trek', 
      'Star Trek: The Animated Series', 
      'Star Trek: The Motion Picture', 
      'Star Trek II: The Wrath of Khan', 
      'Star Trek III: The Search for Spock', 
      'Star Trek IV: The Voyage Home'], 
'Spin-off': ['Star Trek: The Next Generation - The Transinium Challenge', 
       'A Night with Troi', 
       'Star Trek: Deep Space Nine', 
       "Star Trek: The Next Generation - Future's Past", 
       'Star Trek: The Next Generation - A Final Unity', 
       'Star Trek: The Next Generation: Interactive VCR Board Game - A ' 
       'Klingon Challenge', 
       'Star Trek: Borg', 
       'Star Trek: Klingon', 
       'Star Trek: The Experience - The Klingon Encounter']} 
>>> 
+0

Danke, funktioniert wie ein Zauber. aber ich konnte nicht herausfinden, wie man das in meinem Code benutzt. kannst du mir bitte einen Tipp geben oder mir einen Code zur Verfügung stellen? – haben

+0

Siehe meine bearbeitete Antwort. –

3

Sie können versuchen, unter XPath-Ausdrücke verwenden

  • alle Textknoten für "Folgt" Block zu holen:

    //div[./preceding-sibling::h4[1]="Follows"]//text() 
    
  • alle Textknoten für den Block "gefolgt von":

    //div[./preceding-sibling::h4[1]="Followed by"]//text() 
    
  • Alle Textknoten für "Spin off" -Block:

    //div[./preceding-sibling::h4[1]="Spin-off"]//text() 
    
+1

Sie könnten sogar '[./preceding-sibling::h4[1] [. =" Follows "]] in' [./preceding-sibling::h4[1] = "Follows"] ' –

+0

Yep, das macht Sinn. Danke – Andersson

+0

Sie sind einfach genial Sir Andersson. Was für ein Ausdruck !!! Ist es möglich, css selector mit den gleichen Elementen zu erstellen, um dasselbe zu finden?Ein Beispiel würde genügen. Vielen Dank. – SIM

Verwandte Themen