Кто тут жадный?

Начать хотелось бы прежде всего с того зачем и почему, а ответ весьма банальный и очевидный к сожалению, hh api не доступен простым смертным человекам. И ладно бы дали возможность производить какие-то простейшие манипуляции с своим аккаунтом, а на остальные методы наложить квоты как это сделали например в google.. Но нет, ребята из hh очевидно считают себя умнее других. Я честно пытался получить ключ через заявку, и описал весь альтруизм своих намерений, однако ответа так и не получил.

Задачи

Первоочередной задачей было автоматизировать обновление своего резюме, как побочный квест естественно ещё и автопоиск и рассылка резюме на подходящие вакансии. Конечно же в начале своего пути я рассчитывал что смогу реализовать всё это с помощью api, и буду счастлив, однако жадные господа из hh быстро приземлили меня на землю нищебродов.

Трудности

Как это не банально но всё же, ассортимент инструментов для решения подобных задач не так уж и велик. Я бы мог попробовать обмануть хитрую лису, и самостоятельно написать запросы на авторизацию,.. ну что же, я попробовал))) и мягко говоря был неприятно удивлён тому что буквально на третей успешной авторизации я получил капчу :3 причем не за что, вот просто так, от доброты душевной, даже при успешной авторизации *(с верными данными), ну естественно решение было приятно в пользу selenium который так часто меня выручал.

Почему selenium

Начнём с того что задача довольно специфическая, и сложность её в первую очередь обусловлена наличием капчи на авторизации. Естественно что селениум не убирает магическим образом капчу, однако он позволяет нам очень легко работать с произведённой авторизацией. Второй момент это естественно отсутствие доступа к api как бы это не было очевидно на первый взгляд, но силами selenium можно было-бы реализовать свой собственный, альтернативный api (посмотрим как пойдёт с работай, может и запилю). Кто-то очевидно возмутиться, мол “Это всё равно что стрелять из пушки по воробьям”, но в конечно счёте этот инструмент помогает решать задачу, если у Вас есть идея лучше, жду в комментариях.

Немного советов

Перед началом работы очень бы хотелось поделиться своим взглядом на принципы работы с selenium, поскольку работаю с ним уже больше года, и перепробовал различные схемы взаимодействия с веб драйвером. Пробовал и в качестве тест кейсов, и классов, и объектов, и функций, но самым удобным (на мой взгляд) оказался именно контекстный менеджер. Вообще на моей практики я не разу не создавал свой собственной менеджер контекста, как-то вот совсем не было такой необходимости, но вот в данном случае я считаю это идеальный пример, и вот почему:

  • Веб драйвер необходимо всегда закрывать, причём делать это правильно!
  • Один контекст = одна копия бразуера.
  • Предсказуемый отлов исключений.
  • Масштабируемость.
  • Объём кода.

Вот как это выглядит

О хранении сессии

Есть несколько существенно различных подходов к реализации и хранения текущей сессии экземпляра браузера. Я расскажу о них более подробно в образовательных целях, но в своём коде я реализовал подход с использованием библиотеки pickle и подключения куков напрямую в сессию браузер.

Глобальное сохранение

Данный подход имеет ряд преимуществ, однако не обошлось и без недостатков. Основная идея заключаться в том что бы сохранять все настройки браузера, в том числе и активные сессии (они же куки), и настройки браузера, и даже настройки плагинов. К слову если веб драйверу не передать аргумент “user-data-dir=”, в таком случае при каждом запуске экземпляра браузера, он будет открываться абсолютно новым не помня истории, или каких либо настроек. Минусом данного подхода является занимаемое место самой папкой с профилем, она весит около 50мб, и содержит Файлов: 519; папок: 69 что довольно не мало.

Локальное сохранение

Данный метод более распространён, потому что генерирует всего один файл расширения .pkl, хранящий в себе куки непосредственно нужного нам сайта. Реализации такого подхода тоже довольна проста, но имеет небольшой минус в виде того что страницу обязательно нужно перезагрузить, что бы настройки применялись и подхватились сайтом.

cookies

Зачем тут del и что это за expiry? Да чтоб я знал ещё) гугление ничего путного не дало, но если не удалять то будет выпадать исключение, так-как веб драйвер не умеет работать с такой печенкой.

Практичность

Актуальный вопрос для многих кто понимает что такое selenium и как он работает, отвечу сразу что данная реализация вполне себе прекрасно работает на севере без GUI и потребляет около 150-200мб оперативной памяти, время работы скрипта около минуты, и то потому что задержки необходимы в целях безопастности, при желании время можно сократить до нескольких секунд *на ваш страх и риск.

headless режим

Для тех кто не использует PhantomJS, а например так же как я chrome, то данный параметр необходим для запуска экземпляра браузера без окна, в фоновом режиме. Безусловно это мешает вам визуально отслеживать прогресс работы самого кода, однако вы можете использовать скриншоты) пример моей конфигурации для серверного запуска я естественно оставлю на гитхабе

Стабильность/Воспроизводимость

Безусловно в нашем деле важность имеет фактор стабильности, и сложно назвать опыт работы с hh таковым. В процессе написания сценариев я столкнулся с тем что вёрстка сайта имеет свойство меняться. Возможно это сделано с целью предотвращения подобного поведения, а возможно это какой-то хитрый трюк системы, смысл которого почему-то ускользнул от моего понимания. Так или иначе, мне несколько раз доводилось видеть тот как кнопка “обновить резюме” меня название своего класса, а так же общий вид, с словесного описания до символьного. Всё это заставило менять искать альтернативные методы ориентации в DOM. Мной были обнаружены два подхода, первый заключается в всеми любимой мобильной версии сайта (этот метод был реализован и работает отлично), не знаю почему, но сайт выглядит значительно иначе, и использует свой уникальный набор классов, именно по этому я сумел написать стабильный код который всегда даёт ожидаемый результат. Второй метод я описывать не буду по причине того что данную статью могут прочитать ребята из hh и скорее всего пофиксят фишечку, а я хочу оставить себе небольшую лазейку для эксплуатации. Но подсказку для пылевых всё же оставлю)), метод завязан за вложенности элементов, следовательно что бы предотвратить эксплуатацию данного подхода, ребятам из hh пришлось бы каждый раз усложнять вёрстку :3 либо делать какие-то неведомые динамические и фантомные блоки, которые я естественно так же бы смог вызвать, ведь мы имеем дело с великим selenium =)

Реализация

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

Авторизация

Как уже было писано ранее, в данной реализации я буду использовать подход прямого переиспользования печенья, но его ещё и получать нужно для начала =) а в связи с жадностью hh делать это нужно крайне осторожно и по науке)

safety_get

Зачем оно надо? Начнём с set_page_load_timeout(7), это вынужденная мера по обходу очередной пассивной защиты сайта. Данный метод служит для принудительной перезагрузки страницы в случае её “залипания”. Защита работает таким образом что не позволяет загрузить страницу до конца, вызывая бесконечную загрузку. Для человека данная ситуация даже не заметна, однако для селениума это больное препятствие, так-как он не может продолжить исполнение кода, из-за того что думает что страница ещё не загружена на 100%, и подобная реализация это единственный способ “сморгнуть” данную блокировку.

Здоровый сон

У любого человека не имеющего большого опыта в работе с selenium наверняка возникает вопрос, а зачем тут столько ожиданий? На самом деле это очередная вынужденная мера по спасению от капчи, и она в действительности работает как нужно. Если убрать задержки между вводом информации, тогда она будет записана практически мгновенно после загрузки страницы что может вызвать подозрение у антирбота.

Обновление

Самая просто пожалуй часть проекта, посольскую я нашел лёгкий способ делать это через мобильную версию сайта, однако есть момент который я оставлю на вас, это контроль продолжительности интервала задержки обновлений. Поскольку в мобильной версии сайта вообще нет никакого упоминания о времени следующего обновления, его можно конечно вытаскивать через обычную версию, но как я понял, самая большая задержка это 4 часа, по крайней мере у меня не поднимается выше этого числа.

Планы

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

Разумеется я хочу реализовать систему интеллектуальной рассылки своего резюме тем компаниям которые подходят под фильтр ключевых слов. Реализация будет довольно простой, в json документе будут храниться тем компании кому я уже отправил отклик, и те которые не подходят совсем. Собственно при парсинге бот будет проверять каждого работодателя на наличие в списке, и принимать решение об отправки моего резюме. Всё это будет происходить каждые 4 часа вместе с обновление резюме, что позволит мне не отвлекаться на hh вообще :3

Исходный код можно взять в моё гитхабе, но если есть желание доработать я не буду против