2013-09-26 62 views
20

Tôi đang sử dụng scrapy để sàng lọc dữ liệu cạo từ một trang web. Tuy nhiên, dữ liệu tôi muốn không phải bên trong chính html, thay vào đó, nó là từ một javascript. Vì vậy, câu hỏi của tôi là:Phế liệu, tháo dỡ dữ liệu bên trong Javascript

Cách lấy giá trị (giá trị văn bản) của các trường hợp như vậy?

này, là trang web tôi đang cố gắng để màn cạo: https://www.mcdonalds.com.sg/locate-us/

Attributes Tôi đang cố gắng để có được: giờ Địa chỉ, liên hệ, điều hành.

Nếu bạn thực hiện "nhấp chuột phải", "nguồn xem" bên trong trình duyệt chrome, bạn sẽ thấy rằng các giá trị đó không có sẵn trong HTML.


Sửa

Sry paul, tôi đã làm những gì bạn nói với tôi đến, thấy admin-ajax.php và thấy cơ thể nhưng, tôi thực sự bị mắc kẹt ngay bây giờ.

Làm cách nào để truy xuất các giá trị từ đối tượng json và lưu nó vào trường biến của riêng tôi? Nó sẽ là tốt, nếu bạn có thể chia sẻ làm thế nào để làm chỉ là một thuộc tính cho công chúng và cho những người chỉ cần bắt đầu cạo là tốt.

Dưới đây là mã của tôi cho đến nay

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 cho chỉnh sửa dài, do đó trong ngắn hạn, làm thế nào để tôi lưu trữ giá trị json vào thuộc tính của tôi? cho ví dụ

*** mục [ 'địa chỉ'] = * Làm thế nào để lấy ****

PS, không chắc chắn nếu điều này giúp nhưng, tôi chạy các kịch bản trên dòng cmd sử dụng

scrapy crawl mcdonalds -o McDonalds.json -t json (để lưu tất cả dữ liệu của tôi vào một tệp json)

Tôi không thể nhấn mạnh vào cảm giác biết ơn của mình. Tôi biết nó không hợp lý khi hỏi điều này của bạn, sẽ hoàn toàn ổn cả cho dù bạn không có thời gian cho việc này.

Trả lời

18

(tôi đăng này để scrapy-users mailing list nhưng theo gợi ý của Paul của tôi đăng nó ở đây vì nó bổ sung cho câu trả lời với sự tương tác shell lệnh.)

Nói chung, các trang web có sử dụng một dịch vụ của bên thứ ba để làm cho một số hình dung dữ liệu (bản đồ, bảng, vv) phải gửi dữ liệu bằng cách nào đó và trong hầu hết các trường hợp, dữ liệu này có thể truy cập được từ trình duyệt.

Đối với trường hợp này, một thanh tra (tức là khám phá những yêu cầu thực hiện bởi các trình duyệt) cho thấy các dữ liệu được nạp từ một yêu cầu POST để https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php

Vì vậy, về cơ bản bạn đã có tất cả các dữ liệu bạn muốn trong một đẹp định dạng json sẵn sàng để tiêu thụ.

Scrapy cung cấp lệnh shell đó là rất thuận tiện để nhà tư tưởng với các trang web trước khi viết nhện:

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

Tóm lại: trong nhện của bạn, bạn phải trả lại FormRequest(...) trên, sau đó trong callback nạp đối tượng json từ response.body và cuối cùng cho dữ liệu của từng cửa hàng trong danh sách data['stores']['listing'] tạo một mục có giá trị mong muốn.

Something như thế này:

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 để được trợ giúp Rho, đó là thông tin và nó hoạt động! * Đối với những người phải đối mặt với cùng một vấn đề với tôi, hãy kiểm tra bài đăng này * – HeadAboutToExplode

7

Khi bạn mở https://www.mcdonalds.com.sg/locate-us/ trong trình duyệt bạn chọn, hãy mở công cụ "kiểm tra" (hy vọng nó có một công cụ, ví dụ: Chrome hoặc Firefox) và tìm tab "Mạng".

Bạn có thể lọc cho "XHR" (XMLHttpRequest) các sự kiện, và bạn sẽ thấy một yêu cầu POST-https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php với cơ thể này

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

Các phản ứng với yêu cầu POST là một đối tượng JSON với tất cả các thông tin mà bạn muốn

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

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

này sẽ ra một cái gì đó như:

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

Tôi sẽ để bạn trích xuất các trường bạn muốn.

Trong FormRequest() bạn gửi với Scrapy có lẽ bạn cần phải thêm một chữ "X-yêu cầu-Với: XMLHttpRequest" tiêu đề (trình duyệt của bạn gửi rằng nếu bạn nhìn vào tiêu đề yêu cầu trong công cụ kiểm tra)

+0

câu trả lời nhanh chóng! thx paul, lần thứ hai u đã giúp tôi: DDD – HeadAboutToExplode

+0

Bạn được chào đón. Đó là những gì SO là tất cả về: chia sẻ và giúp đỡ. –

+0

vết sưng, đã chỉnh sửa. tôi có thể có thêm lời khuyên không? – HeadAboutToExplode