tags: android
Собираем базу водителей такси Indriver + скрипт
Intro
Впервые я про это рассказал на 2600 (7.12.2018), KHS Community в Караганде (27.03.2019), KHS Community в Алматы (13.04.2019). Публикую, так как InDriver поменял API и теперь этот функционал недоступен.
Эта статья собрана из презентации, которую вы можете скачать:
Анализ
Для анализа, нам потребуется apk. Существует два способа сделать это:
Скачать, используя онлайн сервисы (apkpure.com, apkcombo.com, apkgk.com, …)
- apk может быть не самой последней версии
- предназначена для другой страны
- вредоносные модификации
Установить на телефон через Google Play. Экспортировать, с помощью adb
- безопасный способ
- последняя версия
- для своего региона
Для анализа трафика приложения на понадобится:
- Эмулятор Android девайса (BlueStacks, Android Studio, …)
- Прокси (Burp Suite, ZAP proxy, …)
- Установить сертификат прокси на эмулятор, предварительно экспортировав его
- Установить apk на эмулятор
Основные экраны приложения:
Запросы приложения при обычной работе:
Если мы просто откроем приложение и ничего не будем делать, то InDriver переодически шлет запросы по поиску водителей рядом с вами:
Запрос выглядит так:
POST /api/getfreedrivers?cid=150&locale=en_US HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x8664) AppleWebKit/537.36 (KHTML like Gecko) Chrome/29.0.1547.65 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Content-Length: 141
Host: indriver.ru
Connection: close
Accept-Encoding: gzip, deflate
phone=XXXXXXXX&token=YYYYYYYYYY&v=2&stream_id=1&source=map&longitude=71.40331149101257&latitude=51.14208076245961
Если вы заметили, то в запросе приложение отправляет вашу текущую геолокация (longitude=71.40331149101257&latitude=51.14208076245961
), на основе которой формируется список водителей.
Ответ на запрос содержит много данных, в том числе и ссылку на фото:
По ссылке в ответе можно получить фото водителя:
Пишем парсер
Как вы поняли, мы можем манипулировать значением текущей геолокации, чтобы получать данные водителей в любой точке мира, где существует Indriver. Чтобы спарсить все города, собираем значения геолокации, например омск.
На основе этого составляем массив:
coords = {
'Astana':{'lon_min' : 71.39, 'lon_max' : 71.50, 'lat_min' : 51.12, 'lat_max' : 51.17, 'cid':150},
'Almaty':{'lon_min' : 76.86, 'lon_max' : 76.95, 'lat_min' : 43.22, 'lat_max' : 43.25, 'cid' : 169},
'Kokshetau':{'lon_min' : 69.35, 'lon_max' : 69.40, 'lat_min' : 53.26, 'lat_max' : 53.28, 'cid' : 151},
'Kostanay':{'lon_min' : 63.60, 'lon_max' : 63.64, 'lat_min' : 53.19, 'lat_max' : 53.22, 'cid' : 252},
'Aktobe':{'lon_min' : 57.16, 'lon_max' : 57.25, 'lat_min' : 50.25, 'lat_max' : 50.30,'cid' : 213},
'Atyrau':{'lon_min' : 51.88, 'lon_max' : 51.94, 'lat_min' : 47.10, 'lat_max' : 47.13, 'cid' : 221},
'Aktau':{'lon_min' : 51.12, 'lon_max' : 51.20, 'lat_min' : 43.64, 'lat_max' : 43.68, 'cid' : 258},
'Kyzylorda': {'lon_min' : 65.44, 'lon_max' : 65.56, 'lat_min' : 44.79, 'lat_max' : 44.88, 'cid' : 257},
'Taraz': {'lon_min' : 71.32, 'lon_max' : 71.40, 'lat_min' : 42.85, 'lat_max' : 42.91, 'cid' : 235},
'Shymkent': {'lon_min' : 69.53, 'lon_max' : 69.65, 'lat_min' : 42.29, 'lat_max' : 42.35, 'cid' : 277},
'Taldykorgan': {'lon_min' : 78.32, 'lon_max' : 78.41, 'lat_min' : 44.98, 'lat_max' : 45.10, 'cid' : 177},
'Karaganda': {'lon_min' : 73.06, 'lon_max' : 73.15, 'lat_min' : 49.77, 'lat_max' : 49.82, 'cid' : 242},
'Pavlodar': {'lon_min' : 76.93, 'lon_max' : 76.99, 'lat_min' : 52.25, 'lat_max' : 52.30, 'cid' : 262},
'Petropavl': {'lon_min' : 69.10, 'lon_max' : 69.16, 'lat_min' : 54.85, 'lat_max' : 54.88, 'cid' : 266},
'Semei': {'lon_min' : 80.21, 'lon_max' : 80.28, 'lat_min' : 50.40, 'lat_max' : 50.44, 'cid' : 228},
'Ustkaman': {'lon_min' : 82.56, 'lon_max' : 82.64, 'lat_min' : 49.94, 'lat_max' : 49.97, 'cid' : 230},
'Tashkent': {'lon_min' : 69.20, 'lon_max' : 69.35, 'lat_min' : 41.27, 'lat_max' : 41.34, 'cid' : 638},
'Bishkek': {'lon_min' : 74.51, 'lon_max' : 74.65, 'lat_min' : 42.83, 'lat_max' : 42.89, 'cid' : 639},
'Omsk': {'lon_min' : 73.21, 'lon_max' : 73.51, 'lat_min' : 54.90, 'lat_max' : 55.04, 'cid' : 578},
'Barnaul': {'lon_min' : 83.66, 'lon_max' : 83.80, 'lat_min' : 53.33, 'lat_max' : 53.40, 'cid' : 279},
'Tomsk': {'lon_min' : 84.92, 'lon_max' : 84.92, 'lat_min' : 56.46, 'lat_max' : 56.54, 'cid' : 12},
'Yakutsk': {'lon_min' : 129.70, 'lon_max' : 129.75, 'lat_min' : 62.00, 'lat_max' : 62.04, 'cid' : 1},
'Ekibastuz': {'lon_min' : 75.28, 'lon_max' : 75.35, 'lat_min' : 51.69, 'lat_max' : 51.74, 'cid' : 263},
'Balhash': {'lon_min' : 74.95, 'lon_max' : 75.00, 'lat_min' : 46.83, 'lat_max' : 46.85, 'cid' : 240},
'Temirtau': {'lon_min' : 72.92, 'lon_max' : 73.00, 'lat_min' : 50.04, 'lat_max' : 50.06, 'cid' : 248},
'Pyatigorsk': {'lon_min' : 43.11, 'lon_max' : 42.99, 'lat_min' : 44.00, 'lat_max' : 44.05, 'cid' : 742},
'Vladivostok': {'lon_min' : 131.87, 'lon_max' : 131.95, 'lat_min' : 43.11, 'lat_max' : 43.14, 'cid' : 11},
'Krasnoyarsk': {'lon_min' : 92.80, 'lon_max' : 92.96, 'lat_min' : 55.98, 'lat_max' : 56.02, 'cid' : 182},
'Surgut': {'lon_min' : 73.35, 'lon_max' : 73.44, 'lat_min' : 61.23, 'lat_max' : 61.27, 'cid' : 87},
'Tumen': {'lon_min' : 65.47, 'lon_max' : 65.60, 'lat_min' : 57.11, 'lat_max' : 57.17, 'cid' : 146},
'Perm': {'lon_min' : 57.95, 'lon_max' : 58.00, 'lat_min' : 56.12, 'lat_max' : 56.30, 'cid' : 110},
'Habarovsk': {'lon_min' : 135.03, 'lon_max' : 135.13, 'lat_min' : 48.45, 'lat_max' : 48.51, 'cid' : 79},
'Ulan-Ude': {'lon_min' : 107.53, 'lon_max' : 107.70, 'lat_min' : 51.80, 'lat_max' : 51.85, 'cid' : 10}
}
Значение cid
- это id города. Достать его было не так просто, так как он
- Уникален для каждого города
- Само приложение получает его только тогда, когда мы руками меняем свой город нахождения.
Выдергивать каждый город отдельно было больно и долго, поэтому я покопался в приложении и нашел неочевидный API запрос на получения id по имени города, который приложение не использовало вообще (во всяком случае, в трафике я его не видел). Этот запрос, к сожалению, сохранить не удалось =(.
Суть скрипта в брутфорсе API получения водителей рядом, с координатами из разных городов. Перед тем, как вы будете делать запрос к новому город, вам надо уведомить об этом приложение (как будто вы выбрали город ручками в приложении):
def change_city(new_cid):
body = {'phone':'+7xxxxxxxxxx', 'token':'xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'v':'4','stream_id':'1540382596387750', 'city_id':new_cid}
r = requests.post('http://indriver.ru/api/profileedit?cid=150&locale=ru', data = body,
headers={'Content-Type':'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:22.0) Gecko/20100101 Firefox/22.0'})
Собственно сам скрипт лежит тут
Вот такие данные мы могли получить (имя, фамилия, год рождения, марка автомобиля, номер, год автомобиля, цвет):
Вверх