Или как я тупой болван, но JavaScript - это хорошо.

TL;DR: 💯

Я не назначил важную встречу, и в следующем месяце ее не было ... Поэтому я использовал JavaScript, чтобы найти ее в течение нескольких дней! Я использовал Chrome DevTools, чтобы выяснить, как работает сайт бронирования встреч, и написал код JavaScript, чтобы отправить мне электронное письмо, когда записи станут доступны!

Сюрприз Сюрприз. Я испортил. 🤪

Я недавно переехал из Новой Зеландии 🇳🇿 в Швецию 🇸🇪, и, честно говоря, это было довольно просто! Мне посчастливилось получить роль, где агентство по переезду организовывало почти весь мой переезд. Пришлось заполнить несколько форм и упаковать вещи. На самом деле, мне пришлось сделать так много всего, что я не выполнил свою одну очень важную задачу - записаться на прием по биометрии в Migrationsverket в Стокгольме. Это назначение - важный шаг в процессе миграции, который позволит мне получить персональный номер. Этот номер позволит мне открыть счет в шведском банке и начать получать деньги! Люди заказывают эти встречи за недели и недели заранее, поэтому я не мог подойти и разобраться.

Чтобы мне было немного неловко, моя девушка пыталась найти время для своей встречи. Когда она спросила меня, нужно ли мне сделать то же самое, я заверил ее (ошибочно), что агентство по переезду разберутся с моим. У нее были проблемы с поиском записи на сайте. Мы думали, что сайт не работает, но на самом деле записи очень редкие. Их раскупают, как только они становятся доступными!

Я хотел разобраться как можно скорее (деньги)! Я проверил, могу ли я записаться на прием в другом городе или поехать в другую страну. Мой консультант по переезду заверил меня, что люди часто отменяют свои встречи, поэтому я должен продолжать проверять. В Швеции есть 14 разных мест для встреч, и для просмотра списка доступных часов нужно шесть щелчков мышью! Это означает, что потребуется немного времени, чтобы просмотреть все варианты. Я слишком ленив для этого и боюсь пропустить, потому что смотрел не в то место не в то время.

Я могу это автоматизировать! 🤖

К счастью для меня, я пишу код так же, как живу - плохо. Я стараюсь понять, как все работает. Мне пришлось создать набор инструментов, чтобы выбраться из подобных ситуаций. Я был почти уверен, что смогу перепроектировать веб-сайт и автоматизировать этот процесс. Я рассматривал возможность использования Puppeteer для управления браузером и заполнения форм, но я подумал, что может быть более простой способ. Я решил использовать HTTP-запросы, чтобы получать данные с веб-сайта Migrationsverket и отправлять себе электронное письмо, когда появляется новая встреча.

Разобраться в этом казалось довольно простым делом, но оказалось, что это далеко не так. Давайте рассмотрим шаги, которые я предпринял, чтобы понять, что происходит.

Шаг 1) Откуда берутся данные?

Сначала я использовал вкладку Сеть, чтобы посмотреть, какие запросы делает браузер, когда я его использую. Я зашел на веб-сайт, заполнил форму и щелкнул календарь, чтобы просматривать каждую неделю. Вкладка Сеть позволяет мне отслеживать запросы по мере их поступления. Каждый щелчок инициировал запрос к “BehaviorListener.1-form-kalendar":

Когда я изучал каждый индивидуальный ответ, я увидел, что данные JSON для списка встреч возвращаются! Woohoo 🎉!

Я подумал, что смогу сделать запрос по этому URL-адресу, и все готово 😎… Это выглядело примерно так:

Увы, если бы это было так просто. Когда я запустил приведенный выше код, я получил фрагмент HTML, содержащий следующее 😔:

«Срок действия запрашиваемой страницы истек. Чтобы продолжить бронирование, попробуйте вернуться, используя кнопки навигации в веб-браузере ».

(Да, в реальном ответе «countinue»)

Шаг 2) Как мне получить реальные данные?

Я знал, откуда берутся данные, но на самом деле не мог их получить. Так что же происходило? У меня было несколько подсказок. В ответе было сказано «просрочено». Это подразумевало, что есть какое-то государство. Это намекало мне, что здесь могут быть файлы cookie, и я знал, что могу легко это подтвердить. Используя инструмент «копировать как cURL» в DevTools, я мог воспроизвести запрос, включая все файлы cookie, и посмотреть, что я получил:

Когда я воспроизвел весь запрос, включая файлы cookie и другие заголовки, я получил ожидаемый ответ!

Шаг 3) Как мне получить данные для разных мест?

Следующая проблема заключалась в том, что исходный URL-адрес запроса не содержал фактического «запроса». Там есть даты start и end, но как насчет местоположения? Мне нужна была дополнительная информация.

Я прошел через процесс назначения еще несколько раз, ища зацепки. Я заметил, что независимо от того, какое место я выбрал, я всегда получал URL в следующем формате:

Немного повозившись, я обнаружил, что последний параметр запроса не имеет значения. Это была просто текущая отметка времени. Из остальных параметров важны start и end, но они не дали никакой новой информации. Но первый параметр интересен - он меняется с каждым запросом новой страницы. Откуда это взялось? Сервер должен его сгенерировать, но как?

Следующее, что я попробовал, - это снова взглянуть на вкладку Сеть, на этот раз глядя на более широкую картину. Какие запросы делает сайт на протяжении всего процесса? Я включил параметры «Сохранить журнал» и «Отключить кеш», чтобы видеть запросы по течение:

Короткий ответ: запросов много . К сожалению, ничего полезного здесь найти не удалось, пришлось попробовать что-то другое ...

Следующей моей идеей 💡 было отключить JavaScript. Вы можете сделать это, перейдя в настройки DevTools (три вертикальные точки для «Настройка и управление DevTools», за которыми следует «настройки» ) и установив флажок «Отключить JavaScript»:

Теперь, когда я попытался повторить процесс еще раз, кнопка «Продолжить» не сработала! Google Translate тоже был сломан 🤪! Это подтвердило, что отправка формы обрабатывалась JavaScript! Теперь мне нужно было исследовать и увидеть, что именно он делает. Я использовал инструмент «Проверить элемент», чтобы лучше рассмотреть:

Осмотр элемента показал, что у него есть id, а это значит, что у меня есть еще одна подсказка! Я использовал DevTools «Search», чтобы просмотреть весь сайт на предмет каких-либо ссылок на это id:

Поиск показал, что к этой кнопке прикреплен обработчик кликов. Этот конкретный код выглядел так:

Я добавил точку останова, чтобы увидеть, куда пойдет реальное перенаправление:

И теперь у меня появилось больше подсказок! Новый URL-адрес с новой страницей и новыми параметрами запроса. Что произойдет, если мы сделаем запрос по этому URL-адресу?

На этот раз получил реальный ответ 🥳:

Du har valt att boka tid for 2 personer for att lämna fingeravtryck och bli fotograferad hos NATIONELLT SERVICECENTER 1 STOCKHOLM

or

Вы решили забронировать время для 2 человек, чтобы они оставили отпечатки пальцев и сфотографировались в НАЦИОНАЛЬНОМ СЕРВИСНОМ ЦЕНТРЕ 1 СТОКГОЛЬМ.

Ответ также содержал URL-адрес “BehaviorListener.1-form-kalendar". Он даже включил параметр запроса с изменяющимися числовыми значениями. Выглядело неплохо!

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

На данный момент у меня было три важных фрагмента информации:

  1. Формат URL-адреса для запроса созданной страницы календаря. Запросы к этому URL-адресу также возвращают необходимые файлы cookie сеанса.
  2. Формат URL-адреса для запроса данных JSON для встреч.
  3. Список различных мест для параметра enhet.

Шаг 4) Как мне все это собрать?

Мой маленький скрипт node.js стал немного сложнее. Он создает первый запрос на основе местоположения, затем просматривает ответ, чтобы найти URL-адрес для IBehaviorListener. Затем он берет из этого случайные числа, а затем создает второй запрос на основе случайного числа. Ответ - это набор встреч!

Вот несколько маленьких хитростей, которые заставят его работать:

  1. Включая { jar: true }, он сообщает модулю request хранить файлы cookie. Это означает, что второй запрос не дает нам сообщения «Срок действия истек».
  2. Крошечное маленькое регулярное выражение для поиска нужных данных в теле первого запроса. Это особенно хрупко и может сломаться, если их код изменится (😢).

Шаг 5) Как заставить его работать автоматически?

У меня уже есть базовая функциональность. Все, что мне нужно было сделать, - это перебрать каждое из мест и проверить, есть ли новые встречи. Это включало грубый код (🤢), но эй, это сработало!

Каждые пять секунд сценарий отправлял запрос в следующее место и сохранял список встреч в объекте ALL_APPOINTMENTS. К сожалению, конечная точка встреч иногда ничего не возвращает, даже если встречи доступны. В конечном итоге данные появляются, поэтому у нас есть еще один тайм-аут, который ждет несколько минут, прежде чем скрипт начнет отправлять электронные письма. К сожалению, это необходимо, но на самом деле это объясняет, почему у моей девушки были такие тяжелые времена с сайтом! Через две минуты информация должна быть стабильной, и любые «новые» встречи должны быть действительно новыми. Это означает, что мы можем отправить уведомление по электронной почте.

Шаг 6) Как отправить электронное письмо?

Благодаря замечательной экосистеме node.js этот шаг оказался действительно простым! Я использовал nodemailer, и он отлично работал:

Он отправляет мне электронные письма с небольшим псевдонимом (+biometrics-appointment), чтобы я мог их фильтровать. SENDER_EMAIL и SENDER_PASSWORD устанавливаются как переменные среды. SENDER_PASSWORD должен был быть сгенерированный пароль приложения, чтобы обойти мои два фактора.

Это означало, что каждую ночь я получал довольно много писем 😅:

Все это:

И, сложив все это вместе, весь сценарий выглядел так:

Эти 123 строки кода означали, что вместо того, чтобы ждать встречи почти месяц, я забронировал ее в Стокгольме в течение трех дней. Я также мог найти встречу для своей девушки на свидании, которое совпало с ее визитом ко мне. В общем, успех получился!

Подведение итогов:

Я пришла на встречу! Я немного опоздал (конечно 🙄), но все прошло нормально, и теперь у меня есть биометрическая карта и банковский счет. JavaScript не может решить большинство моих повседневных проблем, но, конечно, приятно, когда это возможно! DevTools очень полезен, и уловки, которые мы используем для отладки наших собственных сайтов, также можно использовать, чтобы выяснить, как работают другие сайты 🚧.

В любом случае, это было немного глупо, но также и весело, и я надеюсь, что вы нашли это интересным / полезным. Пожалуйста, напишите мне в Твиттере (@phenomnominal) и дайте мне знать, что вы думаете!

❤️️️❤️️️❤️️️🦄