2016-01-24 37 views
10

To jest kolejne pytanie uzupełniające do one I asked earlier.Korzystanie z funkcji InitSpider z splash: czy parsowanie strony logowania?

Próbuję zeskrobać stronę internetową, która mam się zalogować, aby osiągnąć pierwszy. Ale po uwierzytelnieniu strona, której potrzebuję, wymaga trochę kodu Javascript, zanim będzie można wyświetlić zawartość. To, co zrobiłem, było zgodne z instrukcjami here, aby zainstalować splash, aby spróbować renderować JavaScript. Jednak ...

Zanim przeszedłem na zachlapanie, uwierzytelnianie z Scrapy na InitSpider było w porządku. Przechodziłem przez stronę logowania i zdrapywałem stronę docelową w porządku (oczywiście bez działającej Javascript, oczywiście). Ale po dodaniu kodu, aby przekazać żądania za pomocą powitania, wygląda na to, że nie analizuję strony docelowej.

Pająk poniżej. Jedyną różnicą między wersją splash (tutaj) a wersją inną niż splash jest funkcja def start_requests(). Wszystko inne jest takie samo między nimi.

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) 

Co się dzieje teraz jest to, że test.html, wynik parse(), jest teraz po prostu sama strona logowania zamiast strony mam być przekierowany po zalogowaniu.

Mówi się w dzienniku, zobaczyłbym linię "Zalogowanie się powiodło" z check_login_response(), ale jak widać poniżej, wydaje się, że nie mam nawet dostępu do tego kroku. Czy to dlatego, że scrapy przesyłają również żądania uwierzytelnienia przez splash i że jest on zawieszany? Jeśli tak, to czy istnieje sposób obejścia splash tylko dla części uwierzytelniania?

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) 

Jestem prawie pewien, że nie używam poprawnie splasha. Czy ktoś może wskazać mi jakąś dokumentację, w której mogę dowiedzieć się, co się dzieje?

+0

Dlaczego nie renderujesz się po zalogowaniu? –

+0

@PadraicCunningham Ja ... nie zorientowałem się, jak to zrobić, czytając dokumenty. Czy oznacza to na przykład skonfigurowanie oprogramowania pośredniczącego do pobierania za pomocą PhantomJS? – gogurt

+0

Co chcesz uzyskać po zalogowaniu? http://www.bridgebase.com/myhands/index.php?offset=0 pozwoli ci również przejść do strony "Kliknij tutaj, aby zobaczyć wyniki" bez żadnych js –

Odpowiedz

3

Nie sądzę Splash sam będzie obsługiwać tym konkretnym przypadku również.

Oto idea pracy:

kodu:

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) 

Drukuje Login successful oraz kod HTML strony "ręce".

+0

Działa u mnie! Nie do końca rozumiem, co się dzieje, ale to jest przynajmniej początek, więc mogę zacząć uczyć się. Dzięki wielkie. – gogurt

+0

Witam serdecznie: czy mogę zadać szybkie pytanie uzupełniające? Jeśli nadal będę chciał dalej udostępniać witryny, logowanie nie będzie się utrzymywać. Oznacza to, że jeśli podążę za odnośnikiem za pomocą 'scrapy.Rule', to kopie mnie z powrotem. Próbowałem zapisać plik cookie jako zmienną globalną i nadpisać 'make_requests_from_url()', aby przekazać plik cookie, ale wydaje się, że nie działa. Masz pojęcie, co się dzieje? – gogurt

0

Aktualizacja

Więc wydaje się, że start_requests pożarów przed logowania.

Oto kod z InitSpider, minus komentarzach.

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 nazywa główny start_requests z initialized.

Twój start_requests to zmodyfikowana wersja metody klasy bazowej. Może coś takiego zadziała.

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} 
      } 
     }) 

Trzeba return self.initialized()

+0

Tak naprawdę to zrobiłem, próbując odpowiedzi Quy, ale nadal nie działało. Jestem teraz z dala od terminala, ale spróbuję go ponownie dla bezpiecznej miary i udostępnię dziennik, jeśli ma on charakter informacyjny. – gogurt

+0

Zbyt długi komentarz, patrz zaktualizowana odpowiedź. –

+0

Dzięki za to. To ma sens, ale po prostu wypróbowałem to z uruchomionym plusem i nadal kończyło się indeksowaniem "Twoja przeglądarka albo nie ma obsługi Javascript, albo ma wyłączoną obsługę". strona. Coś jest nie tak z pluskiem lub z tym, jak to skonfigurowałem ... – gogurt

0

Możesz uzyskać wszystkie dane bez potrzeby korzystania z js, istnieją linki dostępne dla przeglądarek, które nie mają włączonego javascript, adresy URL są tym samym paskiem ?offset=0. Wystarczy, że przeanalizujesz zapytania z URL-a turnieju, który Cię interesuje i utworzysz Formularz zapytania.

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() 

Istnieje wiele linków w wyjściu na ręce masz tview.php?-t=...., można zażądać każdy dołączeniem do http://webutil.bridgebase.com/v2/ i to daje tabelę z wszystkimi danymi, które jest łatwe do analizowania, istnieje również linki do tourney=4796-1455303720-&username=... związane z każdej strony w tabelach, urywek wyjściu z linkiem tview:

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> 

reszta parsowania zostawię dla siebie.

Powiązane problemy