2013-09-26 6 views
20

Ich verwende scrapy, um Daten von einer Website scrape screenen. Allerdings waren die Daten, die ich wollte, nicht im HTML selbst enthalten, sondern von einem Javascript. Also, meine Frage ist:Scrapy, Verschrottung von Daten in einem Javascript

Wie erhalten Sie die Werte (Textwerte) solcher Fälle?

Dies ist die Seite, die ich zu Screen Scrape bin versucht: https://www.mcdonalds.com.sg/locate-us/

Attribute Ich versuche zu bekommen: Adresse, Kontakt, Betriebsstunden.

Wenn Sie einen "Rechtsklick", "Quelltext anzeigen" in einem Chrom-Browser ausführen, werden Sie sehen, dass solche Werte nicht im HTML selbst verfügbar sind.


bearbeiten

Sry paul, tat ich, was du mir gesagt hast gefunden, die admin-ajax.php und sah den Körper, aber ich bin jetzt wirklich stecken.

Wie kann ich die Werte aus dem JSON-Objekt abrufen und in einem eigenen Variablenfeld speichern? Es wäre gut, wenn Sie teilen könnten, wie man nur ein Attribut für die Öffentlichkeit und für diejenigen, die gerade erst begonnen haben, zu scrapieren. so weit

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 für lange bearbeiten

meinen Code Hier ist, so kurz, wie kann ich speichern der JSON-Wert in mein Attribut? für zB

*** item [ 'Adresse'] = * wie abrufen ****

PS, nicht sicher, ob dies hilft aber, ich laufe diese Skripte auf der cmd Linie

mit scrapy crawl mcdonalds -o McDonalds.json -t json (um alle meine Daten in eine JSON-Datei zu speichern)

Ich kann nicht genug betonen, wie dankbar ich mich fühle. Ich weiß, es ist etwas unvernünftig, das von dir zu verlangen, es wird völlig in Ordnung sein, auch wenn du keine Zeit dafür hast.

Antwort

18

(ich dies scrapy-users Mailing-Liste geschrieben, sondern von Paul Vorschlag hier ich poste wie es die Antwort mit der shell Befehl Interaktion ergänzt.)

Allgemeinen Websites, die einen dritten Service verwenden, um einige Daten-Visualisierung zu rendern (Karte, Tabelle, usw.) müssen die Daten irgendwie senden, und in den meisten Fällen sind diese Daten vom Browser zugänglich.

Für diesen Fall eine Inspektion (dh die Erforschung der durch den Browser gemacht Anfragen) zeigt, dass die Daten von einer POST-Anforderung an https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php

Also, Sie im Grunde die Daten wollen alle geladen wird Sie in einem netten haben es JSON-Format bereit für den Konsum.

Scrapy bietet den shell Befehl, die sehr bequem ist mit der Website Denker vor der Spinne zu schreiben:

$ 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'} 

Kurz gesagt: in Ihren Spinnen müssen Sie die FormRequest(...) oben zurück, dann in dem Rückruf laden die Json-Objekt von response.body und schließlich für jedes Geschäft Daten in der Liste data['stores']['listing'] erstellen Sie ein Element mit den gewünschten Werten.

Etwas wie folgt aus:

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

Danke für die Hilfe Rho es ist informativ und es hat funktioniert! * Für diejenigen, die das gleiche Problem haben wie ich, überprüfe diesen Post * – HeadAboutToExplode

7

Wenn Sie in Ihrem Browser Ihrer Wahl https://www.mcdonalds.com.sg/locate-us/ öffnen, öffnen Sie das "inspect" -Tool (hoffentlich hat es eines, z. B. Chrome oder Firefox), und suchen Sie nach der Registerkarte "Netzwerk".

Sie weiter für „XHR“ (XMLHttpRequest) Ereignisse filtern können, und Sie werden eine POST Anfrage an https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php mit diesem Körper

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

Die Antwort auf diese POST-Anforderung ist ein JSON-Objekt mit allen sehen Informationen, die Sie wollen

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

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

Dies würde die Ausgabe so etwas wie:

{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'}} 

Ich überlasse es Ihnen, die gewünschten Felder zu extrahieren.

Im FormRequest() Sie mit Scrapy senden müssen Sie wahrscheinlich ein hinzufügen "X-Requested-With: XMLHttpRequest" Header (Ihr Browser sendet, wenn Sie die Request-Header zu buchen, in dem Werkzeug inspiziert)

+0

schnelle Antwort! thx paul, 2. mal hast du mir geholfen: DDD – HeadAboutToExplode

+0

Gern geschehen. Darum geht es bei SO: teilen und helfen. –

+0

bump, bearbeitet. Kann ich noch mehr Ratschläge haben? – HeadAboutToExplode