Пишу статью для тех, у кого появилась похожая задача, но они не знают как ее решать. Не уверен что мой способ работает везде (недостаточно опытен), но считаю, что если бы я увидел эту статью, загуглив "как парсить webgl" или что-то типо такого, я бы потратил на несколько часов жизни меньше на поиск решения.

Задача (и как у меня НЕ получилось ее решить)

Мне пришел заказ от знакомого: он мне отправляет QR код, я парсю ссылку с куарки, и при переходе по этой ссылке в конце страницы будет карта. На ней нарисован маршрут.

Мне надо спарсить этот маршрут так, чтобы заказчик его мог использовать при составлении идентичного маршрута в своем специальном приложении-навигаторе (или что-то такое).

Парсинг QR-ки был реализован очень легко:

def qrParser(pathToImage):
    decoded = decode(Image.open(pathToImage))
    url = (decoded[0].data).decode("utf-8")
    return url

А дальше пошла жара.


Я сначала вообще представить не мог как это сделать. Так как это WebGL приложение, в полном подгруженном HTML-JS коде ничего не было. Там это выглядит просто как обьект типа холст (canvas), в который никаких ссылок, яваскриптов не передается. Даже проштудировав многие parent элементы, а также поискав по ключевым классам, ничего путного найдено не было.

В подгружаемых js скриптах тоже ничего понятного обнаружено не было

Сидел я так часа 2-3.

Решение (которое сработало в моем случае)

Далее я решил поискать в network. Это та вкладочка, где показываются по идее все get запросы.

Перезагрузил страницу, долистал до карты. Сбросил историю всех завершенных запросов. И начал отдалять и водить картой туда-сюда. Появились новые запросы, которые должны были подгружать данные карты. Я посмотрел что там: и да, о чудо! В пришедших json'ах были переданы всякие объекты по типу water, grass, road и тд. Я понял, что иду в правильном направлении.

Поизучав все приходящие с самого начала загрузки страницы запросы, я нашел один выделяющийся:

Исходная ссылка: "https://urm.safe-route.ru/check?uuid=ID_HERE"
Исходная ссылка: "https://urm.safe-route.ru/check?uuid=ID_HERE"

Он в аргументах содержал абсолютно точный id, который передавался в исходной ссылке, а также имел ключевое слово api, которое также меня зацепило и я решил посмотреть что же интересного мне возвращает этот запрос. БИНГО. Он возвращал json, в глубинах которого передавались точные координаты (вида Долгота/Широта) всех начальных и конечных точек всех линий, из которых строился графически маршрут, что нам и нужно было.

Вот и все, задача сводится к отправке запроса по ссылке "https://urm.safe-route.ru/api/claim/resolution/check?uuid=ID_HERE". Мы получаем json, в котором передается много всяких параметров, но мы выцепляем нужный нам раздел ["geom"]["features"][номеркоординаты]["geometry"]["coordinates"] и забираем из него списки списков координат, переворачиваем координаты, так как они передаются в виде Долгота/Широта, а правильно будет Широта/Долгота и дампим в json

Вот и все, задача сводится к отправке запроса по ссылке "https://urm.safe-route.ru/api/claim/resolution/check?uuid=ID_HERE". Мы получаем json, в котором передается много всяких параметров, но мы выцепляем нужный нам раздел ["geom"]["features"][номеркоординаты]["geometry"]["coordinates"] и забираем из него списки списков координат, переворачиваем координаты, так как они передаются в виде Долгота/Широта, а правильно будет Широта/Долгота и дампим в json.

Исходный response, который нам приходит (там сверху еще много параметров, нам не нужных)
Исходный response, который нам приходит (там сверху еще много параметров, нам не нужных)
Преобразованный json, в котором каждый элемент это координата точки маршрута (с превеликой точностью в пару метров)
Преобразованный json, в котором каждый элемент это координата точки маршрута (с превеликой точностью в пару метров)
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0"}
response = requests.get(url, headers=headers, verify=False) 
#url мы здесь передаем уже вида "https://urm.safe-route.ru/api/claim/resolution/check?uuid=ID_HERE"
#ведь именно он возвращает нам json с координатами
count = 0
answer = {}

for i in range(len(response.json()["geom"]["features"]) - 1, 0, -1):
  geometries = (response.json()["geom"]["features"][i]["geometry"]["coordinates"])
  for j in geometries:

    j = j[::-1]
    answer.setdefault(count, j)
    count += 1

json_object = json.dumps(answer, indent=4)
with open("coords.json", "w+") as file:
  file.write(json_object)

verify=False при get запросе был обязателен, без этого сайт не пропускал по причине отсутствия SSL сертификата у python-инициатора запроса.

Надеюсь, кому-то это сэкономило часы жизни.

P.S. Любые замечания и вопросы приветствуются и будут просмотрены автором.

Комментарии (5)


  1. zartdinov
    24.11.2021 13:51
    +6

    Формат называется GeoJSON, я бы его даже не парсил, а дальше везде использовал


  1. Alexandroppolus
    24.11.2021 14:14
    +3

    Довольно классический сюжет парсинга. Комфортный - все данные оказались в отдельном json. Бывает хуже, когда всё зашито в здоровенный исходный html, особенно если там вокруг хреновая верстка с inline-стилями вместо классов, нагромождениями div, и т.д.

    На одной из прошлых работ как раз такими вещами занимался.


  1. unibasil
    24.11.2021 15:18

    Преобразованный json, в котором каждый элемент это координата точки маршрута (с превеликой точностью в пару метров)

    Вы не правы, семь знаков после запятой — это околосантиметровая точность (различается по широте). Поэтому даже в Google Maps координаты с шестью знаками после запятой (а в отдельных задачах — например, polyline'ах — даже пять).

    И как выше справедливо заметили, формат называется GeoJSON, и файл в таком формате можно непосредственно сразу подключить в виде слоя в любых распространённых движках карт.


    1. Zickam Автор
      24.11.2021 20:24

      На счет околосантиметровой точности у вас правильный вывод, но я, видимо, не совсем правильно выразился. Я имел в виду расстояние между двумя ближайшими точками маршрута, которые мы можем спарсить


  1. Nehc
    24.11.2021 15:56

    Автору читать статью Как спарсить любой сайт, что бы не наступать на те же грабли, и успехов изысканиях! )