2013-09-26 17 views
20

Sto usando scrapy per analizzare i dati di raschiatura da un sito web. Tuttavia, i dati che volevo non si trovavano all'interno dello stesso codice HTML, ma da un javascript. Quindi, la mia domanda è:Scrapy, rottamazione dei dati all'interno di un Javascript

Come ottenere i valori (valori di testo) di tali casi?

Questo, è il sito che sto cercando di raschiare schermo: https://www.mcdonalds.com.sg/locate-us/

Attributi Sto cercando di ottenere: ore Indirizzo, contatto, di funzionamento.

Se si fa un "clic destro", "visualizza sorgente" all'interno di un browser Chrome, si vedrà che tali valori non sono disponibili nel codice HTML.


Modifica

Sry Paolo, ho fatto quello che mi hai detto a, trovato il admin-ajax.php e ha visto il corpo, ma, sto veramente bloccato ora.

Come recuperare i valori dall'oggetto json e memorizzarli in un campo variabile di mia proprietà? Sarebbe bello, se potessi condividere come fare un solo attributo per il pubblico e anche per quelli che hanno appena iniziato a scricchiolare.

Ecco il mio codice finora

Items.py

class McDonaldsItem(Item): 
name = Field() 
address = Field() 
postal = Field() 
hours = Field() 

McDonalds.py

from scrapy.spider import BaseSpider 
from scrapy.selector import HtmlXPathSelector 
import re 

from fastfood.items import McDonaldsItem 

class McDonaldSpider(BaseSpider): 
name = "mcdonalds" 
allowed_domains = ["mcdonalds.com.sg"] 
start_urls = ["https://www.mcdonalds.com.sg/locate-us/"] 

def parse_json(self, response): 

    js = json.loads(response.body) 
    pprint.pprint(js) 

Sry a lungo modificare, così in breve, come faccio a memorizzare il valore JSON nel mio attributo? per esempio

*** voce [ 'indirizzo'] = * come recuperare ****

PS, non so se questo aiuta, ma, ho eseguito questi script sulla linea di cmd utilizzando

mcdonalds -o McDonalds.json -t json (per salvare tutti i miei dati in un file json)

Non riesco a sottolineare abbastanza quanto mi sento grato. So che è irragionevole chiedertelo, sarà assolutamente d'accordo anche se non hai tempo per questo.

risposta

18

(ho postato questo per scrapy-users mailing list, ma per suggerimento di Paul sto postando qui in quanto integra la risposta con l'interazione shell comando.)

in generale, i siti web che utilizzano un servizio di terze parti per rendere un po 'di visualizzazione dei dati (mappa, tabella, ecc.) devono inviare i dati in qualche modo, e nella maggior parte dei casi questi dati sono accessibili dal browser.

Per questo caso, un controllo (vale a dire esplorare le richieste avanzate dal browser) mostra che i dati vengono caricati da una richiesta POST a https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php

Quindi, in pratica si ci sono tutti i dati che si desidera in un bel formato json pronto per il consumo.

Scrapy fornisce il comando shell che è molto comodo per pensatore con il sito web prima di scrivere il ragno:

$ scrapy shell https://www.mcdonalds.com.sg/locate-us/ 
2013-09-27 00:44:14-0400 [scrapy] INFO: Scrapy 0.16.5 started (bot: scrapybot) 
... 

In [1]: from scrapy.http import FormRequest 

In [2]: url = 'https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php' 

In [3]: payload = {'action': 'ws_search_store_location', 'store_name':'0', 'store_area':'0', 'store_type':'0'} 

In [4]: req = FormRequest(url, formdata=payload) 

In [5]: fetch(req) 
2013-09-27 00:45:13-0400 [default] DEBUG: Crawled (200) <POST https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php> (referer: None) 
... 

In [6]: import json 

In [7]: data = json.loads(response.body) 

In [8]: len(data['stores']['listing']) 
Out[8]: 127 

In [9]: data['stores']['listing'][0] 
Out[9]: 
{u'address': u'678A Woodlands Avenue 6<br/>#01-05<br/>Singapore 731678', 
u'city': u'Singapore', 
u'id': 78, 
u'lat': u'1.440409', 
u'lon': u'103.801489', 
u'name': u"McDonald's Admiralty", 
u'op_hours': u'24 hours<br>\r\nDessert Kiosk: 0900-0100', 
u'phone': u'68940513', 
u'region': u'north', 
u'type': [u'24hrs', u'dessert_kiosk'], 
u'zip': u'731678'} 

In breve: nel vostro ragno è necessario restituire il FormRequest(...) sopra, quindi nella richiamata caricare il json object from response.body e infine per i dati di ciascun negozio nell'elenco data['stores']['listing'] creare un elemento con i valori desiderati.

Qualcosa di simile a questo:

class McDonaldSpider(BaseSpider): 
    name = "mcdonalds" 
    allowed_domains = ["mcdonalds.com.sg"] 
    start_urls = ["https://www.mcdonalds.com.sg/locate-us/"] 

    def parse(self, response): 
     # This receives the response from the start url. But we don't do anything with it. 
     url = 'https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php' 
     payload = {'action': 'ws_search_store_location', 'store_name':'0', 'store_area':'0', 'store_type':'0'} 
     return FormRequest(url, formdata=payload, callback=self.parse_stores) 

    def parse_stores(self, response): 
     data = json.loads(response.body) 
     for store in data['stores']['listing']: 
      yield McDonaldsItem(name=store['name'], address=store['address']) 
+0

Thx per l'aiuto Rho è informativo e ha funzionato! * Per chi ha lo stesso problema con me, controlla questo post * – HeadAboutToExplode

7

Quando apri https://www.mcdonalds.com.sg/locate-us/ nel tuo browser di scelta, apri lo strumento "controlla" (si spera ne abbia uno, ad esempio Chrome o Firefox) e cerca la scheda "Rete".

Si può ulteriormente filtrare eventi "XHR" (XMLHttpRequest), e vedrete una richiesta POST-https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php con questo corpo

action=ws_search_store_location&store_name=0&store_area=0&store_type=0 

La risposta a tale richiesta POST è un oggetto JSON con tutte le informazioni che si desidera

import json 
import pprint 
... 
class MySpider(BaseSpider): 
... 
    def parse_json(self, response): 

     js = json.loads(response.body) 
     pprint.pprint(js) 

Questo sarebbe uscita una cosa del genere:

{u'flagicon': u'https://www.mcdonalds.com.sg/wp-content/themes/mcd/images/storeflag.png', 
u'stores': {u'listing': [{u'address': u'678A Woodlands Avenue 6<br/>#01-05<br/>Singapore 731678', 
          u'city': u'Singapore', 
          u'id': 78, 
          u'lat': u'1.440409', 
          u'lon': u'103.801489', 
          u'name': u"McDonald's Admiralty", 
          u'op_hours': u'24 hours<br>\r\nDessert Kiosk: 0900-0100', 
          u'phone': u'68940513', 
          u'region': u'north', 
          u'type': [u'24hrs', u'dessert_kiosk'], 
          u'zip': u'731678'}, 
          {u'address': u'383 Bukit Timah Road<br/>#01-09B<br/>Alocassia Apartments<br/>Singapore 259727', 
          u'city': u'Singapore', 
          u'id': 97, 
          u'lat': u'1.319752', 
          u'lon': u'103.827398', 
          u'name': u"McDonald's Alocassia", 
          u'op_hours': u'Daily: 0630-0100', 
          u'phone': u'68874961', 
          u'region': u'central', 
          u'type': [u'24hrs_weekend', 
            u'drive_thru', 
            u'mccafe'], 
          u'zip': u'259727'}, 

         ... 
          {u'address': u'60 Yishuan Avenue 4 <br/>#01-11<br/><br/>Singapore 769027', 
          u'city': u'Singapore', 
          u'id': 1036, 
          u'lat': u'1.423924', 
          u'lon': u'103.840628', 
          u'name': u"McDonald's Yishun Safra", 
          u'op_hours': u'24 hours', 
          u'phone': u'67585632', 
          u'region': u'north', 
          u'type': [u'24hrs', 
            u'drive_thru', 
            u'live_screening', 
            u'mccafe', 
            u'bday_party'], 
          u'zip': u'769027'}], 
      u'region': u'all'}} 

Ti lascio per estrarre i campi che vuoi.

Nel FormRequest() si invia con Scrapy probabilmente è necessario aggiungere un "X-richiesta-Con: XMLHttpRequest" intestazione (il vostro browser invia che se si guardano le intestazioni di richiesta nello strumento ispezionare)

+0

risposta veloce! grazie Paul, seconda volta che mi hai aiutato: DDD – HeadAboutToExplode

+0

Prego. Ecco di cosa si tratta SO: condivisione e aiuto. –

+0

urto, modificato. posso avere qualche altro consiglio? – HeadAboutToExplode