2013-09-26 13 views
20

Używam scrapy do przeglądania danych o skrobaniu ze strony internetowej. Jednak dane, których szukałem, nie znajdowały się w samym html, ale pochodzą z javascriptu. Moje pytanie brzmi:Złomowanie, złomowanie danych w skrypcie Javascript

Jak uzyskać wartości (wartości tekstowe) takich przypadków?

To jest strona Próbuję zeskrobać ekranu: https://www.mcdonalds.com.sg/locate-us/

Atrybuty Próbuję dostać: godziny adres, dane kontaktowe, operacyjne.

Jeśli wykonasz "kliknięcie prawym przyciskiem", "wyświetl źródło" w przeglądarce Chrome, zobaczysz, że takie wartości nie są dostępne w kodzie HTML.


Edit

Sry Paul, zrobiłem to, co mi powiedziano, znalazł admin-ajax.php i zobaczył ciało, ale ja naprawdę tkwi teraz.

Jak pobrać wartości z obiektu Json i zapisać je w osobnym polu zmiennym? Byłoby dobrze, gdybyś mógł podzielić się tym, jak zrobić tylko jeden atrybut dla publiczności i dla tych, którzy właśnie rozpoczęli scrapy.

Oto mój kod tak daleko

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 długotrwały edycji, więc w skrócie, jak mogę zapisać wartość json do mojego atrybutu? Np

*** pozycja [ 'adres'] = * Jak odzyskać ****

PS, nie wiem, czy to pomoże, ale ja uruchomić te skrypty na linii cmd przy użyciu

scrapy crawl mcdonalds -o McDonalds.json -t json (aby zapisać wszystkie moje dane w pliku json)

Nie mogę wystarczająco podkreślić, jak bardzo jestem wdzięczny. Wiem, że to nierozsądne, aby zapytać o to, będzie całkowicie w porządku, nawet jeśli nie masz na to czasu.

Odpowiedz

18

(I napisali to scrapy-users listy ale sugestia Pawła jestem umieszczenie go tutaj, gdyż uzupełnia odpowiedź z interakcji komend shell.)

Ogólnie, strony internetowe, które korzystają z usług firm trzecich, aby uczynić pewną wizualizację danych (mapa, tabela itp.) muszą jakoś wysłać dane, w większości przypadków dane te są dostępne z poziomu przeglądarki.

W tym przypadku kontrola (tj odkrywania żądań zgłaszanych przez przeglądarkę) pokazuje, że dane są ładowane z żądania POST do https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php

Więc w zasadzie masz tam wszystkie dane, które chcesz w miły Format json gotowy do konsumpcji.

Scrapy zapewnia polecenia shell co jest bardzo wygodne, aby myśliciel ze strony przed napisaniem pająka:

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

W skrócie: w pająka trzeba zwrócić FormRequest(...) powyżej, a następnie w zwrotnego załadować Obiekt json z response.body i na końcu dla danych każdego sklepu na liście data['stores']['listing'] utwórz element z pożądanymi wartościami.

coś takiego:

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 za pomoc Rho to informacja i zadziałało! * Dla tych, którzy mają ten sam problem co ja, sprawdź ten wpis * – HeadAboutToExplode

7

Po otwarciu https://www.mcdonalds.com.sg/locate-us/ w wybranej przeglądarce, otwórz narzędzie "inspect" (mam nadzieję, że ma ono taką opcję, np. Chrome lub Firefox) i znajdź zakładkę "Network".

można dodatkowo filtrować za "XHR" (XMLHttpRequest) wydarzeń, a zobaczysz prośbę POST do https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php z tym ciałem

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

Odpowiedź na to żądanie POST jest obiekt JSON ze wszystkimi informacje chcesz

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

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

co zmieni coś jak:

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

Zostawię cię, aby wyodrębnić pola, które chcesz.

W FormRequest() wysyłanie z Scrapy prawdopodobnie trzeba dodać „X-Requested-With: XMLHttpRequest” header (przeglądarka wysyła, że ​​jeśli spojrzeć na nagłówki żądań w narzędziu do wglądu)

+0

szybka odpowiedź! thx paul, drugi raz mi pomogłeś: DDD – HeadAboutToExplode

+0

Nie ma za co. Na tym polega SO: dzielenie się i pomaganie. –

+0

bump, edytowane. Czy mogę uzyskać więcej porad? – HeadAboutToExplode

Powiązane problemy