-
Notifications
You must be signed in to change notification settings - Fork 0
Заметка: "Оригинальный JSON"
При нажатии на значок остановки Яндекс делает AJAX-запрос, и получает в ответ данные со всей информацией об остановке в формате JSON. Эти данные потом преобразуются JS-скриптами в браузере клиента, так, например, в "Оригинальном JSON" отсутствует время до прибытия автобуса на остановку, вместо него там стоит "расчетное время прибытия", и браузер клиента уже сам преобразует эти данные в необходимый формат.
Ссылка имеет вот такой вид:
Просто так данные она не отдает, если пройти по ней сейчас, то ответ будет вот такой:
{
"csrfToken": "df24291a07dffd785a875772023f09fc72344e6f:1552240616159",
"error": {
"code": 403,
"message": "Invalid csrf token"
}
}
Браузер кэширует подобные запросы, так что если нажать на значок остановки, через Developer Tools посмотреть последние запросы, найти этот и выполнить еще раз, можно посмотреть настоящие данные которые были получены (приличных таких размеров кусок данных):
Нажать вот сюда чтобы увидеть большой и очень толстый JSON
{
"data": {
"type": "Feature",
"geometries": [
{
"type": "Point",
"coordinates": [
37.742991076,
55.651473063
]
}
],
"geometry": {
"type": "Point",
"coordinates": [
37.742991076,
55.651473063
]
},
"properties": {
"name": "Метро Марьино (северная)",
"description": "Метро Марьино (северная)",
"currentTime": "Sun Mar 10 2019 20:50:47 GMT+0300 (MSK)",
"StopMetaData": {
"id": "stop__9647487",
"name": "Метро Марьино (северная)",
"type": "urban",
"region": {
"id": 213,
"ename": "moscow",
"name": "moscow",
"names": {
"ablative": "",
"accusative": "Москву",
"dative": "Москве",
"directional": "",
"genitive": "Москвы",
"instrumental": "Москвой",
"locative": "",
"nominative": "Москва",
"preposition": "в",
"prepositional": "Москве"
}
},
"Transport": [
{
"id": "2036927530",
"lineId": "2036925691",
"name": "Ашан - Братиславская",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__9648350",
"name": "Братиславская улица"
},
{
"id": "stop__10130286",
"name": "ТЦ Ашан"
}
],
"BriefSchedule": {
"Frequency": {
"text": "20 мин",
"value": 1200,
"begin": {
"value": 1552193303,
"text": "7:48"
},
"end": {
"value": 1552246103,
"text": "22:28"
}
}
}
},
{
"id": "2070379926",
"lineId": "2070378676",
"name": "897",
"Types": [
"minibus"
],
"type": "minibus",
"EssentialStops": [
{
"id": "stop__9648895",
"name": "Люблинская улица, 96"
},
{
"id": "stop__9686587",
"name": "Развилка, 38"
}
],
"BriefSchedule": {
"Frequency": {
"text": "15 мин",
"value": 900,
"begin": {
"value": 1552195880,
"text": "8:31"
},
"end": {
"value": 1552266080,
"text": "4:01"
}
}
}
},
{
"id": "213A_141m_minibus_default",
"lineId": "213_141m_minibus_default",
"name": "541",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__9649003",
"name": "14-й микрорайон Марьинского Парка"
},
{
"id": "stop__10049137",
"name": "Южные Ворота"
}
],
"BriefSchedule": {
"Frequency": {
"text": "22 мин",
"value": 1320,
"begin": {
"value": 1552186342,
"text": "5:52"
},
"end": {
"value": 1552256542,
"text": "1:22"
}
}
}
},
{
"id": "213A_280_bus_mosgortrans",
"lineId": "213_280_bus_mosgortrans",
"name": "280",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__9648085",
"name": "Метро Каширская"
},
{
"id": "stop__9646275",
"name": "Метро Каширская"
}
],
"BriefSchedule": {
"Events": [
{
"Scheduled": {
"value": 1552241580,
"text": "21:13"
},
"Estimated": {
"value": 1552241670,
"text": "21:14"
},
"vehicleId": "codd%5Fnew|63204%5F160705"
},
{
"Scheduled": {
"value": 1552276140,
"text": "6:49"
}
},
{
"Scheduled": {
"value": 1552277520,
"text": "7:12"
}
}
],
"departureTime": "21:13"
}
},
{
"id": "213B_517m_minibus_default",
"lineId": "213_517m_minibus_default",
"name": "517",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__9649686",
"name": "Цимлянская улица, 1"
},
{
"id": "stop__9646191",
"name": "Метро Орехово"
}
],
"BriefSchedule": {
"Frequency": {
"text": "30 мин",
"value": 1800,
"begin": {
"value": 1552185721,
"text": "5:42"
},
"end": {
"value": 1552255921,
"text": "1:12"
}
}
}
},
{
"id": "213A_623_bus_mosgortrans",
"lineId": "213_623_bus_mosgortrans",
"name": "623",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__9646126",
"name": "Метро Красногвардейская"
},
{
"id": "stop__9646125",
"name": "Метро Красногвардейская"
}
],
"BriefSchedule": {
"Events": [
{
"Scheduled": {
"value": 1552240920,
"text": "21:02"
},
"Estimated": {
"value": 1552241094,
"text": "21:04"
},
"vehicleId": "codd%5Fnew|63080%5F160317"
},
{
"Scheduled": {
"value": 1552241760,
"text": "21:16"
},
"Estimated": {
"value": 1552241629,
"text": "21:13"
},
"vehicleId": "codd%5Fnew|164162%5F160571"
},
{
"Scheduled": {
"value": 1552242600,
"text": "21:30"
}
}
],
"departureTime": "21:02"
}
},
{
"id": "6e5bB_511_bus_default",
"lineId": "6e5b_511_bus_default",
"name": "511",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__9649686",
"name": "Цимлянская улица, 1"
},
{
"id": "stop__9646125",
"name": "Метро Красногвардейская"
}
],
"BriefSchedule": {
"Events": [
{
"Estimated": {
"value": 1552240320,
"text": "20:52"
},
"vehicleId": "codd%5Fnew|35306%5F9598"
}
],
"Frequency": {
"text": "22 мин",
"value": 1320,
"begin": {
"value": 1552186004,
"text": "5:46"
},
"end": {
"value": 1552256804,
"text": "1:26"
}
}
}
},
{
"id": "965B_bus_default",
"lineId": "965_bus_default",
"name": "965",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "3265365007",
"name": "Рынок Садовод"
},
{
"id": "stop__9646104",
"name": "Метро Красногвардейская"
}
],
"BriefSchedule": {
"Events": [
{
"Estimated": {
"value": 1552240444,
"text": "20:54"
},
"vehicleId": "codd%5Fnew|35267%5F9255114"
},
{
"Estimated": {
"value": 1552240910,
"text": "21:01"
},
"vehicleId": "codd%5Fnew|43174%5F1020109"
}
],
"Frequency": {
"text": "25 мин",
"value": 1500,
"begin": {
"value": 1552190557,
"text": "7:02"
},
"end": {
"value": 1552249717,
"text": "23:28"
}
}
}
},
{
"id": "N5G_bus_default",
"lineId": "N5_bus_default",
"name": "н5",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__10187979",
"name": "Метро Китай-город"
},
{
"id": "stop__9649035",
"name": "Каширское шоссе, 148"
}
],
"BriefSchedule": {
"Events": [
{
"Scheduled": {
"value": 1552258500,
"text": "1:55"
}
},
{
"Scheduled": {
"value": 1552260300,
"text": "2:25"
}
},
{
"Scheduled": {
"value": 1552262100,
"text": "2:55"
}
}
],
"departureTime": "1:55"
}
},
{
"id": "f254B_415_bus_default",
"lineId": "f254_415_bus_default",
"name": "415",
"Types": [
"bus"
],
"type": "bus",
"EssentialStops": [
{
"id": "stop__9649686",
"name": "Цимлянская улица, 1"
},
{
"id": "stop__9646269",
"name": "Метро Каширская"
}
],
"BriefSchedule": {
"Events": [
{
"Estimated": {
"value": 1552240420,
"text": "20:53"
},
"vehicleId": "codd%5Fnew|38385%5F9885512"
},
{
"Estimated": {
"value": 1552240990,
"text": "21:03"
},
"vehicleId": "codd%5Fnew|38308%5F9885508"
}
],
"Frequency": {
"text": "18 мин",
"value": 1080,
"begin": {
"value": 1552186004,
"text": "5:46"
},
"end": {
"value": 1552256804,
"text": "1:26"
}
}
}
}
]
}
},
"toponymSearchResponse": {
"requestId": "1552240247563918-2886555134-vla1-4115",
"requestSerpId": "1552240247563918-2886555134-vla1-4115",
"requestContext": "ZAAAAAgAEAAaKAoSCQAAAAAAkHZAEQAAAAAAoGZAEhIJAAAAAAAA8L8RAAAAAAAA8L8iAQAoCjAAOIfTip/O9Lup4QFA/v//////////AUgBVQAAgL9Y////////////AWoAcACdAc3MzD2gAQCoAQA=",
"requestQuery": "55.651473,37.742991",
"requestCorrectedQuery": "55.651473,37.742991",
"requestPoint": {
"type": "Point",
"coordinates": [
37.742991,
55.651473
]
},
"requestBounds": [
[
37.04842675,
55.43644829
],
[
38.17590226,
56.04690124
]
],
"displayType": "single",
"totalResultCount": 9,
"items": [
{
"requestId": "1552240247563918-2886555134-vla1-4115",
"title": "Люблинская улица, 102А",
"description": "Москва, Россия",
"address": "Россия, Москва, Люблинская улица, 102А",
"coordinates": [
37.742223,
55.652314
],
"bounds": [
[
37.738117,
55.649992
],
[
37.746328,
55.654635
]
],
"displayCoordinates": [
37.742991,
55.651473
],
"type": "toponym",
"id": "56655096",
"kind": "house",
"postalCode": "109369",
"seoname": "lyublinskaya_ulitsa_102a",
"geoId": 213,
"uri": "ymapsbm1://geo?ll=37.742%2C55.652&spn=0.001%2C0.001&text=%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D1%8F%2C%20%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0%2C%20%D0%9B%D1%8E%D0%B1%D0%BB%D0%B8%D0%BD%D1%81%D0%BA%D0%B0%D1%8F%20%D1%83%D0%BB%D0%B8%D1%86%D0%B0%2C%20102%D0%90",
"entrances": [
{
"coordinates": [
37.742627,
55.651389
],
"azimuth": 168,
"tilt": 0
},
{
"coordinates": [
37.741881,
55.653218
],
"azimuth": 348,
"tilt": 0
},
{
"coordinates": [
37.742726,
55.651963
],
"azimuth": 78,
"tilt": 0
},
{
"coordinates": [
37.742016,
55.651851
],
"azimuth": 258,
"tilt": 0
}
],
"metro": [
{
"id": "station__9858849",
"name": "Марьино",
"distance": "270 м",
"coordinates": [
37.74347222,
55.65002868
],
"type": "metro",
"color": "#99cc33"
},
{
"id": "station__9858793",
"name": "Братиславская",
"distance": "940 м",
"coordinates": [
37.75045439,
55.659407072
],
"type": "metro",
"color": "#99cc33"
},
{
"id": "station__9858953",
"name": "Борисово",
"distance": "2,1 км",
"coordinates": [
37.74381741,
55.633586768
],
"type": "metro",
"color": "#99cc33"
}
],
"stops": [
{
"id": "stop__9769232",
"name": "Метро Марьино",
"distance": "46 м",
"coordinates": [
37.742851339,
55.652094844
],
"type": "common"
},
{
"id": "stop__9647487",
"name": "Метро Марьино (северная)",
"distance": "110 м",
"coordinates": [
37.742991076,
55.651473063
],
"type": "common"
},
{
"id": "stop__9647789",
"name": "Центр защиты",
"distance": "250 м",
"coordinates": [
37.742760449,
55.654572877
],
"type": "common"
},
{
"id": "stop__9648659",
"name": "Поликлиника",
"distance": "260 м",
"coordinates": [
37.745672855,
55.650955107
],
"type": "common"
},
{
"id": "stop__9647304",
"name": "Улица Перерва, 50",
"distance": "390 м",
"coordinates": [
37.739179178,
55.655408532
],
"type": "common"
}
],
"photos": {
"count": 3,
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/900870/2a0000015f59218730cc53f05692dc7f6683/%s",
"items": [
{
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/900870/2a0000015f59218730cc53f05692dc7f6683/%s"
},
{
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/397694/2a0000015f5863289bb21150c01e20a617a9/%s"
},
{
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/786911/2a0000015f58634e60014493c77c9b5f41fc/%s"
}
],
"panoramas": []
},
"logId": "dHlwZT1nZW9jb2RlcjthZGRyZXNzPdCg0L7RgdGB0LjRjywg0JzQvtGB0LrQstCwLCDQm9GO0LHQu9C40L3RgdC60LDRjyDRg9C70LjRhtCwLCAxMDLQkC8zNy43NDIyMjMsNTUuNjUyMzE0LzE=",
"sources": [],
"analyticsId": "1"
}
],
"exactResult": {
"requestId": "1552240247563918-2886555134-vla1-4115",
"title": "Люблинская улица, 102А",
"description": "Москва, Россия",
"address": "Россия, Москва, Люблинская улица, 102А",
"coordinates": [
37.742223,
55.652314
],
"bounds": [
[
37.738117,
55.649992
],
[
37.746328,
55.654635
]
],
"displayCoordinates": [
37.742991,
55.651473
],
"type": "toponym",
"id": "56655096",
"kind": "house",
"postalCode": "109369",
"seoname": "lyublinskaya_ulitsa_102a",
"geoId": 213,
"uri": "ymapsbm1://geo?ll=37.742%2C55.652&spn=0.001%2C0.001&text=%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D1%8F%2C%20%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0%2C%20%D0%9B%D1%8E%D0%B1%D0%BB%D0%B8%D0%BD%D1%81%D0%BA%D0%B0%D1%8F%20%D1%83%D0%BB%D0%B8%D1%86%D0%B0%2C%20102%D0%90",
"entrances": [
{
"coordinates": [
37.742627,
55.651389
],
"azimuth": 168,
"tilt": 0
},
{
"coordinates": [
37.741881,
55.653218
],
"azimuth": 348,
"tilt": 0
},
{
"coordinates": [
37.742726,
55.651963
],
"azimuth": 78,
"tilt": 0
},
{
"coordinates": [
37.742016,
55.651851
],
"azimuth": 258,
"tilt": 0
}
],
"metro": [
{
"id": "station__9858849",
"name": "Марьино",
"distance": "270 м",
"coordinates": [
37.74347222,
55.65002868
],
"type": "metro",
"color": "#99cc33"
},
{
"id": "station__9858793",
"name": "Братиславская",
"distance": "940 м",
"coordinates": [
37.75045439,
55.659407072
],
"type": "metro",
"color": "#99cc33"
},
{
"id": "station__9858953",
"name": "Борисово",
"distance": "2,1 км",
"coordinates": [
37.74381741,
55.633586768
],
"type": "metro",
"color": "#99cc33"
}
],
"stops": [
{
"id": "stop__9769232",
"name": "Метро Марьино",
"distance": "46 м",
"coordinates": [
37.742851339,
55.652094844
],
"type": "common"
},
{
"id": "stop__9647487",
"name": "Метро Марьино (северная)",
"distance": "110 м",
"coordinates": [
37.742991076,
55.651473063
],
"type": "common"
},
{
"id": "stop__9647789",
"name": "Центр защиты",
"distance": "250 м",
"coordinates": [
37.742760449,
55.654572877
],
"type": "common"
},
{
"id": "stop__9648659",
"name": "Поликлиника",
"distance": "260 м",
"coordinates": [
37.745672855,
55.650955107
],
"type": "common"
},
{
"id": "stop__9647304",
"name": "Улица Перерва, 50",
"distance": "390 м",
"coordinates": [
37.739179178,
55.655408532
],
"type": "common"
}
],
"photos": {
"count": 3,
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/900870/2a0000015f59218730cc53f05692dc7f6683/%s",
"items": [
{
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/900870/2a0000015f59218730cc53f05692dc7f6683/%s"
},
{
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/397694/2a0000015f5863289bb21150c01e20a617a9/%s"
},
{
"urlTemplate": "https://avatars.mds.yandex.net/get-ugc/786911/2a0000015f58634e60014493c77c9b5f41fc/%s"
}
],
"panoramas": []
},
"logId": "dHlwZT1nZW9jb2RlcjthZGRyZXNzPdCg0L7RgdGB0LjRjywg0JzQvtGB0LrQstCwLCDQm9GO0LHQu9C40L3RgdC60LDRjyDRg9C70LjRhtCwLCAxMDLQkC8zNy43NDIyMjMsNTUuNjUyMzE0LzE=",
"sources": [],
"analyticsId": "1"
},
"bounds": [
[
37.73811729,
55.64999233
],
[
37.74632789,
55.6546348
]
],
"requestEnd": 1552240247584,
"requestStart": 1552240247556,
"requestSelfDuration": 28
}
}
}
!!! А НУ ПРЕКРАТИ СКРОЛЛИТЬ СТРАНИЦУ !!!
По сути это ответ от метода getStopInfo "masstransit API", который у Яндекса недоступен сторонним разработчикам. Что особенно приятно, он не требует географических координат остановки и оперирует по сути одним лишь stopId.
Данные о прогнозе прибытия можно увидеть вот в этой части:
"BriefSchedule": {
"Events": [
{
"Scheduled": {
"value": 1552241580,
"text": "21:13"
},
"Estimated": {
"value": 1552241670,
"text": "21:14"
},
"vehicleId": "codd%5Fnew|63204%5F160705"
},
{
"Scheduled": {
"value": 1552276140,
"text": "6:49"
}
},
{
"Scheduled": {
"value": 1552277520,
"text": "7:12"
}
}
],
"departureTime": "21:13"
}
}
Запрос использует механизм CSRF-токенов для защиты, что делает невозможным просто так получить эти данные, например через cUrl. Можно попробовать выполнить cUrl с сохранением Cookies, пройдя просто по адресу https://yandex.ru/maps, и "вычленить" CRSF-токен, который уже потом использовать для получения "Оригинального JSON":
- Получаем и сохраняем первую страничку (пользователь "зашел" на Яндекс).
curl -L --cookie-jar cookies.txt https://yandex.ru/maps > output.txt
- Вытаскиваем CSRF-токен, парся HTML с̶̯͖͕͙̟̳ ̥͕̤п҉͎о͢м͓̠о͏̠̯̙щ̛̖ь̟̮̯̪̀ю͉̪͕̜͜ ̲͖̭̳̙R̝̩̭e̺g̰̺̺̭͕E̯̺͢x̞̞̦̳p̙͉̭:
cat output.txt | grep -o -P "(?<=\"csrfToken\":\").*?(?=\",)"
CSRF-токен будет выглядеть как-то так, они одноразовые:
7aa53abc9389809a8c2737d41dbf71ffa01a62be:1552242236909
- Теперь попробуем получить "Оригинальный JSON", подставив полученный токен после "csrfToken=":
curl -b cookies.txt "https://yandex.ru/maps/api/masstransit/getStopInfo?ajax=1&csrfToken=7aa53abc9389809a8c2737d41dbf71ffa01a62be:1552242236909&id=stop__9647487&lang=ru&locale=ru_RU&mode=prognosis&sessionId=1552240160531_146625&uri=ymapsbm1%3A%2F%2Ftransit%2Fstop%3Fid%3Dstop__9647487" > original.json
В целом это работает, пару раз. Потом подобный подход нарывается на "бан", и Яндекс начинает показывать CAPTCHA. Вместо того чтобы гадать, какие именно параметры тут нужны, и что вообще "смотрит" Яндекс у пользователя при подобных запросах (например, sessionId вызывает явные подозрения), проще автоматизировать браузер с помощью WebDriver и Selenium, хоть такой способ и будет потреблять гораздо больше ресурсов.
Идея: попробовать использовать Selenium и заставить Chromium выполнить этот запрос, вытащив его из своего кэша после клика на остановку (или вообще без него).
UPD 14.03.2018 : Это работает. Это ошизительно работает.