2016-01-24 7 views
10

Dies ist eine Art von Follow-up-Frage zu one I asked earlier.InitSpider mit Splash verwenden: nur die Anmeldeseite analysieren?

Ich versuche, eine Webseite zu kratzen, die ich als Erster zu erreichen um sich einzuloggen. Aber nach der Authentifizierung benötigt die Webseite, die ich brauche, ein wenig Javascript, um ausgeführt zu werden, bevor Sie den Inhalt sehen können. Was ich getan habe, ist den Anweisungen here gefolgt, um Splash zu installieren, um zu versuchen, das Javascript zu rendern. Allerdings ...

Bevor ich spritzen geschaltet, die Authentifizierung mit Scrapy der InitSpider war in Ordnung. Ich kam durch die Login-Seite und kratzte die Zielseite in Ordnung (außer, ohne dass das Javascript funktionierte). Aber sobald ich den Code hinzufüge, um die Anfragen durch Splash zu übergeben, sieht es so aus, als würde ich die Zielseite nicht analysieren.

Spider unten. Der einzige Unterschied zwischen der Splash-Version (hier) und der Nicht-Splash-Version ist die Funktion def start_requests(). Alles andere ist zwischen den beiden gleich.

import scrapy 
from scrapy.spiders.init import InitSpider 
from scrapy.spiders import Rule 
from scrapy.linkextractors import LinkExtractor 

class BboSpider(InitSpider): 
    name = "bbo" 
    allowed_domains = ["bridgebase.com"] 
    start_urls = [ 
      "http://www.bridgebase.com/myhands/index.php" 
      ] 
    login_page = "http://www.bridgebase.com/myhands/myhands_login.php?t=%2Fmyhands%2Findex.php%3F" 

    # authentication 
    def init_request(self): 
     return scrapy.http.Request(url=self.login_page, callback=self.login) 

    def login(self, response): 
     return scrapy.http.FormRequest.from_response(
      response, 
      formdata={'username': 'USERNAME', 'password': 'PASSWORD'}, 
      callback=self.check_login_response) 

    def check_login_response(self, response): 
     if "recent tournaments" in response.body: 
      self.log("Login successful") 
      return self.initialized() 
     else: 
      self.log("Login failed") 
      print(response.body) 

    # pipe the requests through splash so the JS renders 
    def start_requests(self): 
     for url in self.start_urls: 
      yield scrapy.Request(url, self.parse, meta={ 
       'splash': { 
        'endpoint': 'render.html', 
        'args': {'wait': 0.5} 
       } 
      }) 

    # what to do when a link is encountered 
    rules = (
      Rule(LinkExtractor(), callback='parse_item'), 
      ) 

    # do nothing on new link for now 
    def parse_item(self, response): 
     pass 

    def parse(self, response): 
     filename = 'test.html' 
     with open(filename, 'wb') as f: 
      f.write(response.body) 

Was jetzt passiert, ist, dass test.html, das Ergebnis parse(), ist jetzt einfach die Login-Seite selbst, anstatt die Seite ich soll nach der Anmeldung umgeleitet werden.

Dies ist in der Log - normalerweise würde ich die "Login erfolgreich" -Linie von check_login_response() sehen, aber wie Sie unten sehen können, scheint es, als ob ich nicht einmal zu diesem Schritt. Liegt das daran, dass scrapy jetzt die Authentifizierungsanfragen auch überspritzt und dass es dort aufgelegt wird? Wenn das der Fall ist, gibt es eine Möglichkeit, Splash nur für den Authentifizierungsteil zu umgehen?

2016-01-24 14:54:56 [scrapy] INFO: Spider opened 
2016-01-24 14:54:56 [scrapy] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 
2016-01-24 14:54:56 [scrapy] DEBUG: Telnet console listening on 127.0.0.1:6023 
2016-01-24 14:55:02 [scrapy] DEBUG: Crawled (200) <POST http://localhost:8050/render.html> (referer: None) 
2016-01-24 14:55:02 [scrapy] INFO: Closing spider (finished) 

Ich bin mir ziemlich sicher, ich bin nicht spritzen funktioniert nicht richtig. Kann mir jemand auf eine Dokumentation hinweisen, in der ich herausfinden kann, was vor sich geht?

+0

Warum rendern Sie nicht nach dem Login? –

+0

@PadraicCunningham I ... habe nicht herausgefunden, wie man das macht, wenn man die Dokumente liest. Würde das bedeuten, eine Downloader-Middleware beispielsweise mit PhantomJS einzurichten? – gogurt

+0

Was möchten Sie nach dem Login erhalten? http://www.bridgebase.com/myhands/index.php?offset=0 können Sie auch auf die "Klicken Sie hier für Ergebnisse .." Seite ohne js –

Antwort

3

Ich glaube nicht, Splash allein würde diesen speziellen Fall gut behandeln.Hier

ist die Arbeits Idee:

Der Code:

import scrapy 
from selenium import webdriver 
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait 
from selenium.webdriver.support import expected_conditions as EC 


class BboSpider(scrapy.Spider): 
    name = "bbo" 
    allowed_domains = ["bridgebase.com"] 
    login_page = "http://www.bridgebase.com/myhands/myhands_login.php?t=%2Fmyhands%2Findex.php%3F" 

    def start_requests(self): 
     driver = webdriver.PhantomJS() 
     driver.get(self.login_page) 

     driver.find_element_by_id("username").send_keys("user") 
     driver.find_element_by_id("password").send_keys("password") 

     driver.find_element_by_name("submit").click() 

     driver.save_screenshot("test.png") 
     WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.LINK_TEXT, "Click here for results of recent tournaments"))) 

     cookies = driver.get_cookies() 
     driver.close() 

     yield scrapy.Request("http://www.bridgebase.com/myhands/index.php", cookies=cookies) 

    def parse(self, response): 
     if "recent tournaments" in response.body: 
      self.log("Login successful") 
     else: 
      self.log("Login failed") 
     print(response.body) 

Drucke Login successful und die HTML der "Hände" Seite.

+0

Funktioniert für mich! Ich verstehe nicht ganz, was vor sich geht, aber das ist zumindest ein Anfang, damit ich anfangen kann zu lernen. Vielen Dank. – gogurt

+0

Hi @alecxe: Kann ich eine kurze Folgefrage stellen? Wenn ich die Seiten weiter scrappen möchte, scheint die Anmeldung nicht zu bestehen. Das heißt, wenn ich einem Link folge, der eine 'scrapy.Rule' verwendet, dann tritt es mich zurück. Ich habe versucht, den Cookie als globale Variable zu speichern und 'make_requests_from_url()' zu überschreiben, um den Cookie zu übergeben, aber es scheint nicht zu funktionieren. Irgendeine Idee was ist los? – gogurt

0

aktualisieren

So scheint es, dass start_requests Feuer vor der Anmeldung. Hier

ist der Code von InitSpider, minus Kommentare.

class InitSpider(Spider): 
    def start_requests(self): 
     self._postinit_reqs = super(InitSpider, self).start_requests() 
     return iterate_spider_output(self.init_request()) 

    def initialized(self, response=None): 
     return self.__dict__.pop('_postinit_reqs') 

    def init_request(self): 
     return self.initialized() 

InitSpider die Haupt start_requests mit initialized nennt.

Ihre start_requests ist eine modifizierte Version der Methode der Basisklasse. Also vielleicht wird so etwas funktionieren.

from scrapy.utils.spider import iterate_spider_output 

... 

def start_requests(self): 
    self._postinit_reqs = my_start_requests() 
    return iterate_spider_output(self.init_request()) 

def my_start_requests(self): 
    for url in self.start_urls: 
     yield scrapy.Request(url, self.parse, meta={ 
      'splash': { 
       'endpoint': 'render.html', 
       'args': {'wait': 0.5} 
      } 
     }) 

Sie müssen return self.initialized()

+0

Ich tat das tatsächlich, als ich Quys Antwort ausprobierte, aber es funktionierte immer noch nicht. Ich bin jetzt von einem Terminal entfernt, aber ich werde es erneut versuchen, um sicher zu gehen und das Protokoll zu teilen, wenn es informativ ist. – gogurt

+0

zu lang für einen Kommentar, siehe aktualisierte Antwort. –

+0

Danke dafür. Das macht Sinn, aber ich habe es gerade mit dem Ausführen von Splash probiert und es hat immer noch gecrawlt: "Dein Browser hat entweder keine Javascript-Unterstützung oder diese Unterstützung ist deaktiviert." Seite. So etwas läuft immer noch entweder mit Splash oder wie ich es konfiguriert habe ... – gogurt

0

Sie können alle Daten ohne die Notwendigkeit für js überhaupt erhalten, es gibt Links für Browser, die Javascript nicht aktiviert haben, die URLs sind die gleichen bar ?offset=0. Sie müssen nur die Abfragen der für Sie interessanten Turnier-URL analysieren und einen Formularantrag erstellen.

import scrapy 
from scrapy.spiders.init import InitSpider 
from urlparse import parse_qs, urlparse 


class BboSpider(InitSpider): 
    name = "bbo" 
    allowed_domains = ["bridgebase.com"] 
    start_urls = [ 
     "http://www.bridgebase.com/myhands/index.php" 
    ] 

    login_page = "http://www.bridgebase.com/myhands/myhands_login.php?t=%2Fmyhands%2Findex.php%3F" 

    def start_requests(self): 
     return [scrapy.FormRequest(self.login_page, 
            formdata={'username': 'foo', 'password': 'bar'}, callback=self.parse)] 

    def parse(self, response): 
     yield scrapy.Request("http://www.bridgebase.com/myhands/index.php?offset=0", callback=self.get_all_tournaments) 

    def get_all_tournaments(self, r): 
     url = r.xpath("//a/@href[contains(., 'tourneyhistory')]").extract_first() 
     yield scrapy.Request(url, callback=self.chosen_tourney) 

    def chosen_tourney(self, r): 
     url = r.xpath("//a[contains(./text(),'Speedball')]/@href").extract_first() 
     query = urlparse(url).query 
     yield scrapy.FormRequest("http://webutil.bridgebase.com/v2/tarchive.php?offset=0", callback=self.get_tourney_data_links, 
           formdata={k: v[0] for k, v in parse_qs(query).items()}) 

    def get_tourney_data_links(self, r): 
     print r.xpath("//a/@href").extract() 

Es gibt zahlreiche Verbindungen in der Ausgabe, für die Hände Sie die tview.php?-t=.... erhalten, können Sie jeder zu http://webutil.bridgebase.com/v2/ Beitritt beantragen, und es wird Ihnen eine Tabelle mit allen Daten geben, zu analysieren leicht zu ist, gibt es auch Links zu tourney=4796-1455303720-&username=... mit jeder Hand in den Tabellen zugeordnet ist, ein Ausschnitt aus der Ausgabe von dem TView Link:

class="bbo_tr_t"> 
    <table class="bbo_t_l"> 
    <tr><td class="bbo_tll" align="left">Title</td><td class="bbo_tlv">#4796 Ind. ACBL Fri 2pm</td></tr> 
    <tr><td class="bbo_tll" align="left">Host</td><td class="bbo_tlv">ACBL</td></tr> 
    <tr><td class="bbo_tll" align="left">Tables</td><td class="bbo_tlv">9</td></tr> 



    </table> 

    </div><div class='sectionbreak'>Section 1 </div><div class='onesection'> <table class='sectiontable' ><tr><th>Name</th><th>Score (IMPs)</th><th class='rank'>Rank</th><th>Prize</th><th>Points</th></tr> 
<tr class='odd'><td>colt22</td><td><a href="http://www.bridgebase.com/myhands/hands.php?tourney=4796-1455303720-&username=colt22" target="_blank">42.88</a></td><td class='rank' >1</td><td></td><td>0.90</td></tr> 
<tr class='even'><td>francha</td><td><a href="http://www.bridgebase.com/myhands/hands.php?tourney=4796-1455303720-&username=francha" target="_blank">35.52</a></td><td class='rank' >2</td><td></td><td>0.63</td></tr> 
<tr class='odd'><td>MSMK</td><td><a href="http://www.bridgebase.com/myhands/hands.php?tourney=4796-1455303720-&username=MSMK" target="_blank">34.38</a></td><td class='rank' >3</td><td></td><td>0.45</td></tr> 

der Rest des Parsing selbst ich verlassen werde.

Verwandte Themen