Scrapy, сдача данных в Javascript
Я использую scrapy
скринировать данные с веб-сайта. Тем не менее, данные, которые я хотел, находились не внутри самого html, а из javascript. Итак, мой вопрос:
Как получить значения (текстовые значения) таких случаев?
Это сайт, который я пытаюсь проверить на экране: https://www.mcdonalds.com.sg/locate-us/
Атрибуты, которые я пытаюсь получить: адрес, контакт, часы работы.
Если вы выполните "правый клик", "просмотр источника" в браузере Chrome, вы увидите, что такие значения сами по себе недоступны в HTML.
редактировать
Сэр Пол, я сделал то, что ты мне сказал, нашел admin-ajax.php
и увидел тело, но я действительно застрял сейчас.
Как извлечь значения из объекта json и сохранить его в собственном поле переменной? Было бы хорошо, если бы вы могли рассказать, как сделать только один атрибут для публики, а также для тех, кто только начал заниматься терапией.
Вот мой код до сих пор
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)
Прошу прощения за долгое редактирование, так вкратце, как мне сохранить значение json в моем атрибуте? например
*** пункт ['адрес'] = * как получить ****
PS, не уверен, что это помогает, но я запускаю эти сценарии в строке cmd, используя
scrapy crawl mcdonalds -o McDonalds.json -t json (чтобы сохранить все мои данные в файл json)
Я не могу не подчеркнуть, насколько я благодарен. Я знаю, что это немного неразумно спрашивать об этом, все будет хорошо, даже если у вас нет времени на это.
2 ответа
(Я отправил это scrapy-users
список рассылки, но по предложению Пола я публикую его здесь, поскольку он дополняет ответ shell
командное взаимодействие.)
Как правило, веб-сайты, которые используют сторонние службы для визуализации некоторых данных (карта, таблица и т. Д.), Должны каким-либо образом отправлять данные, и в большинстве случаев эти данные доступны из браузера.
В этом случае проверка (то есть изучение запросов, сделанных браузером) показывает, что данные загружаются из запроса POST на https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php
Итак, в основном у вас есть все нужные данные в хорошем формате json, готовые к использованию.
Scrapy обеспечивает shell
Команда, которая очень удобна для мыслителя с сайта перед написанием паука:
$ 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'}
Короче говоря: в вашем пауке вы должны вернуть FormRequest(...)
выше, затем в обратном вызове загрузите объект json из response.body
и, наконец, для данных каждого магазина в списке data['stores']['listing']
создать элемент с требуемыми значениями.
Что-то вроде этого:
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'])
Когда вы откроете https://www.mcdonalds.com.sg/locate-us/ в выбранном вами браузере, откройте инструмент "inspect" (надеюсь, он есть, например, Chrome или Firefox) и найдите "Сеть". вкладка
Вы можете дополнительно отфильтровать события "XHR" (XMLHttpRequest), и вы увидите POST
запросить https://www.mcdonalds.com.sg/wp-admin/admin-ajax.php
с этим телом
action=ws_search_store_location&store_name=0&store_area=0&store_type=0
Ответ на этот запрос POST представляет собой объект JSON со всей необходимой информацией.
import json
import pprint
...
class MySpider(BaseSpider):
...
def parse_json(self, response):
js = json.loads(response.body)
pprint.pprint(js)
Это выведет что-то вроде:
{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'}}
Я оставлю вас, чтобы извлечь поля, которые вы хотите.
В FormRequest(), который вы отправляете с помощью Scrapy, вам, вероятно, нужно добавить заголовок "X-Requested-With: XMLHttpRequest" (ваш браузер отправляет его, если вы просматриваете заголовки запросов в инструменте проверки)