{"id":18298247,"url":"https://github.com/s3rgeym/hh-applicant-tool","last_synced_at":"2025-04-05T14:03:16.634Z","repository":{"id":124708551,"uuid":"610119456","full_name":"s3rgeym/hh-applicant-tool","owner":"s3rgeym","description":"Автоматизация дейcтвий на HH.RU: отклик на подходящие вакансии, обновление всех резюме...","archived":false,"fork":false,"pushed_at":"2025-03-11T13:51:54.000Z","size":483,"stargazers_count":73,"open_issues_count":5,"forks_count":8,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-03-29T13:04:43.924Z","etag":null,"topics":["api","cli","headhunter","hh"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/s3rgeym.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-06T06:01:55.000Z","updated_at":"2025-03-23T04:06:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"f272c96b-31d5-46ca-a0c3-3157b20b4964","html_url":"https://github.com/s3rgeym/hh-applicant-tool","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rgeym%2Fhh-applicant-tool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rgeym%2Fhh-applicant-tool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rgeym%2Fhh-applicant-tool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/s3rgeym%2Fhh-applicant-tool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/s3rgeym","download_url":"https://codeload.github.com/s3rgeym/hh-applicant-tool/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247345849,"owners_count":20924102,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","cli","headhunter","hh"],"created_at":"2024-11-05T15:05:34.830Z","updated_at":"2025-04-05T14:03:16.611Z","avatar_url":"https://github.com/s3rgeym.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## HH Applicant Tool\n\n![Publish to PyPI](https://github.com/s3rgeym/hh-applicant-tool/actions/workflows/publish.yml/badge.svg) \n[![PyPi Version](https://img.shields.io/pypi/v/hh-applicant-tool)]() \n[![Python Versions](https://img.shields.io/pypi/pyversions/hh-applicant-tool.svg)]() \n[![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/s3rgeym/hh-applicant-tool)]()\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/hh-applicant-tool)]()\n[![Total Downloads](https://static.pepy.tech/badge/hh-applicant-tool)]()\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/user-attachments/assets/29d91490-2c83-4e3f-a573-c7a6182a4044\" width=\"500\"\u003e\n\u003c/div\u003e\n\n### Описание\n\n\u003e Утилита для генерации сопроводительного письма может использовать AI\n\nУтилита для успешных волчат и старых волков с опытом, служащая для автоматизации действий на HH.RU таких как рассылка откликов на подходящие вакансии и обновление всех резюме (бесплатный аналог услуги на HH). Утилита позволяет получить контактные данные работодателя, даже если тот не присылал приглашения. Для этого собираются данные о работодателях и их вакансиях (персональные данные пользователя не передаются ни в каком виде, а данные работодателя сами по себе персональными данными не являются, так как часто указаны на сайтах и так же доступны неограниченному кругу лиц на hh). Отправку этих данных на сервер разработчика можно отключить. У утилиты есть группа, с которой я еще не придумал, что делать: [Отзывы о работодателях с HH.RU](https://t.me/otzyvy_headhunter). Там сейчас постятся ссылки для отзывов на отказников.\n\nРаботает с Python \u003e= 3.10. Нужную версию Python можно поставить через\nasdf/pyenv/conda и что-то еще.\n\nДанная утилита написана для Linux, но будет работать и на Ga..Mac OS, и в Windows, но с WSL не будет, так как для авторизации требуются оконный сервер X11 либо Wayland — только прямая установка пакета через pip в Windows. После авторизации вы можете перенести конфиг на сервер и запускать утилиту через systemd или cron. Столь странный процесс связан с тем, что на странице авторизации запускается море скриптов, которые шифруют данные на клиенте перед отправкой на сервер, а так же выполняется куча запросов чтобы проверить не бот ли ты. Хорошо, что после авторизации никаких проверок по факту нет, даже айпи не проверяется на соответсвие тому с какого была авторизация. В этой лапше мне лень разбираться. Так же при наличии рутованного телефона можно вытащить `access` и `refresh` токены из официального приложения и добавить их в конфиг.\n\nПример работы:\n\n![image](https://github.com/user-attachments/assets/a0cce1aa-884b-4d84-905a-3bb207eba4a3)\n\n\u003e Если в веб-интерфейсе выставить фильтры, то они будут применяться в скрипте при отклике на подходящие\n\n### Предыстория\n\nДолгое время я делал массовые заявки с помощью консоли браузера:\n\n```js\n$$('[data-qa=\"vacancy-serp__vacancy_response\"]').forEach((el) =\u003e el.click());\n```\n\nОно работает, хоть и не идеально. Я даже пробовал автоматизировать рассылки через `p[yu]ppeeter`, пока не прочитал [документацию](https://github.com/hhru/api). И не обнаружил, что **API** (интерфейс) содержит все необходимые мне методы. Headhunter позволяет создать свое приложение, но там ручная модерация, и наврядли кто-то разрешит мне создать приложение для спама заявками. Я [декомпилировал](https://gist.github.com/s3rgeym/eee96bbf91b04f7eb46b7449f8884a00) официальное приложение для **Android** и получил **CLIENT_ID** и **CLIENT_SECRET**, необходимые для работы через **API**.\n\n### Установка\n\n```bash\n# Версия с поддержкой авторизации через запуск окна с браузером (эта версия очень много весит)\n# Можно использовать обычный pip\n$ pipx install 'hh-applicant-tool[qt]'\n\n# Если хочется использовать самую последнюю версию, то можно установить ее через git\n$ pipx install git+https://github.com/s3rgeym/hh-applicant-tool\n\n# Для обновления до новой версии\n$ pipx upgrade hh-applicant-tool\n```\n\nОтдельно я распишу процесс установки в **Windows** в подробностях:\n\n* Для начала поставьте последнюю версию **Python 3** любым удобным способом.\n* Запустите **Terminal** или **PowerShell** от Администратора и выполните:\n  ```ps\n  Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted\n  ```\n  Данная политика разрешает текущему пользователю (от которого зашли) запускать скрипты. Без нее не будут работать виртуальные окружения.\n* Создайте и активируйте виртуальное окружение:\n  ```ps\n  PS\u003e python -m pip venv hh-applicant-venv\n  PS\u003e .\\hh-applicant-venv\\Scripts\\activate\n  ```\n* Поставьте все пакеты в виртуальное окружение `hh-applicant-venv`:\n  ```ps\n  (hh-applicant-venv) PS\u003e pip install hh-applicant-tool[qt]\n  ```\n* Проверьте работает ли оно:\n  ```ps\n  (hh-applicant-venv) PS\u003e hh-applicant-tool -h\n  ```\n* В случае неудачи вернитесь к первому шагу.\n* Для последующих запусков сначала активируйте виртуальное окружение.\n\n### Авторизация\n\n```bash\n$ hh-applicant-tool -vv authorize\n```\n\n![image](https://github.com/user-attachments/assets/88961e31-4ea3-478f-8c43-914d6785bc3b)\n\n\u003e В Windows не забудьте разрешить доступ к сети (Allow access) в всплывающем окне.\n\nПроверка авторизации:\n\n```bash\n$ hh-applicant-tool whoami\n{\n  \"auth_type\": \"applicant\",\n  \"counters\": {\n    \"new_resume_views\": 1488,\n    \"resumes_count\": 1,\n    \"unread_negotiations\": 228\n  },\n  \"email\": \"vasya.pupkin@gmail.com\",\n  \"employer\": null,\n  \"first_name\": \"Вася\",\n  \"id\": \"1234567890\",\n  \"is_admin\": false,\n  \"is_anonymous\": false,\n  \"is_applicant\": true,\n  \"is_application\": false,\n  \"is_employer\": false,\n  \"is_in_search\": true,\n  \"last_name\": \"Пупкин\",\n  \"manager\": null,\n  \"mid_name\": null,\n  \"middle_name\": null,\n  \"negotiations_url\": \"https://api.hh.ru/negotiations\",\n  \"personal_manager\": null,\n  \"phone\": \"79012345678\",\n  \"profile_videos\": {\n    \"items\": []\n  },\n  \"resumes_url\": \"https://api.hh.ru/resumes/mine\"\n}\n```\n\nВ случае успешной авторизации токены будут сохранены в `config.json`:\n\n```json\n{\n  \"token\": {\n    \"access_token\": \"...\",\n    \"created_at\": 1678151427,\n    \"expires_in\": 1209599,\n    \"refresh_token\": \"...\",\n    \"token_type\": \"bearer\"\n  }\n}\n```\n\nТокен доступа выдается на две недели. После его нужно обновить:\n\n```bash\n$ hh-applicant-tool refresh-token\n```\n\n### Пути до файла config.json\n\n| OS                         | Путь                                                                |\n|----------------------------|---------------------------------------------------------------------|\n| **Windows**                | `C:\\Users\\%username%\\AppData\\Roaming\\hh-applicant-tool\\config.json` |\n| **macOS**                  | `~/Library/Application Support/hh-applicant-tool/config.json`       |\n| **Linux**                  | `~/.config/hh-applicant-tool/config.json`                           |\n\nПолный путь до конфигурационного файла можно вывести с помощью команды:\n\n```bash\nhh-applicant-tool config -p\n```\n\nЧерез конфиг можно задать дополнительные настройки:\n\n| Имя атрибута | Описание |\n| --- | --- |\n| `user_agent` | Кастомный юзерагент, передаваемый при кажом запросе, например, `Mozilla/5.0 YablanBrowser` |\n| `proxy_url` | Прокси, используемый для всех запросов, например, `socks5h://127.0.0.1:9050` |\n| `reply_message` | Сообщение для ответа работодателю при отклике на вакансии, см. формат сообщений |\n\n### Описание команд\n\n```bash\n$ hh-applicant-tool [ GLOBAL_FLAGS ] [ OPERATION [ OPERATION_FLAGS  ] ]\n\n# Справка по глобальным флагам и список операций\n$ hh-applicant-tool -h\n\n# Справка по операции\n$ hh-applicant-tool apply-similar -h\n\n# Авторизуемся\n$ hh-applicant-tool authorize\n\n# Рассылаем заявки\n$ hh-applicant-tool apply-similar\n\n# Поднимаем резюме\n$ hh-applicant-tool update-resumes\n\n# Чистим заявки и баним за отказы говноконторы\n$ hh-applicant-tool clear-negotiations --blacklist-discard\n```\n\nМожно вызвать любой метод API:\n\n```bash\n$ hh-applicant-tool call-api /employers text=\"IT\" only_with_vacancies=true | jq -r '.items[].alternate_url'\nhttps://hh.ru/employer/1966364\nhttps://hh.ru/employer/4679771\nhttps://hh.ru/employer/8932785\nhttps://hh.ru/employer/9451699\nhttps://hh.ru/employer/766478\nhttps://hh.ru/employer/4168187\nhttps://hh.ru/employer/9274777\nhttps://hh.ru/employer/1763330\nhttps://hh.ru/employer/5926815\nhttps://hh.ru/employer/1592535\nhttps://hh.ru/employer/9627641\nhttps://hh.ru/employer/4073857\nhttps://hh.ru/employer/2667859\nhttps://hh.ru/employer/4053700\nhttps://hh.ru/employer/5190600\nhttps://hh.ru/employer/607484\nhttps://hh.ru/employer/9386615\nhttps://hh.ru/employer/80660\nhttps://hh.ru/employer/6078902\nhttps://hh.ru/employer/1918903\n```\n\nДанная возможность полезна для написания Bash-скриптов.\n\nГлобальные флаги:\n\n- `-v` используется для вывода отладочной информации. Два таких флага, например, выводят запросы к **API**.\n- `-c \u003cpath\u003e` можно создать путь до конфига. С помощью этого флага можно одновременно использовать несколько профилей.\n\n| Операция               | Описание                                                                                            |\n| ---------------------- | --------------------------------------------------------------------------------------------------- |\n| **authorize**          | Открывает сайт hh.ru для авторизации и перехватывает перенаправление на `hhadnroid://oauthresponse` |\n| **whoami**             | Выводит информацию об авторизованном пользователе                                                   |\n| **list-resumes**       | Список резюме                                                                                       |\n| **update-resumes**     | Обновить все резюме. Аналогично нажатию кнопки «Обновить дату».                                     |\n| **apply-similar**      | Откликнуться на все подходящие вакансии. Лимит = 200 в день. На HH есть спам-фильтры, так что лучше не рассылайте отклики со ссылками, иначе рискуете попасть в теневой бан. |\n| **reply-employers** | Ответить во все чаты с работодателями, где нет ответа либо не прочитали ваш предыдущий ответ |\n| **clear-negotiations** | Удаляет отказы и отменяет заявки, которые долго висят                                               |\n| **call-api**           | Вызов произвольного метода API с выводом результата.                                                |\n| **refresh-token**      | Обновляет access_token.                                                                             |\n| **config**      | Редактировать конфигурационный файл. |\n| **get-employer-contacts** | Получить список контактов работодателя, даже если тот не высылал приглашения. В группе есть бесплатный бот с тем же функционалом. |\n\n### Формат текста сообщений\n\nКоманда `apply-similar` поддерживает специальный формат сообщений.\n\nТак же в сообщении можно использовать плейсхолдеры:\n\n- **`%(vacancy_name)s`**: Название вакансии.\n- **`%(employer_name)s`**: Название работодателя.\n- **`%(first_name)s`**: Имя пользователя.\n- **`%(last_name)s`**: Фамилия пользователя.\n- **`%(email)s`**: Email пользователя.\n- **`%(phone)s`**: Телефон пользователя.\n\nЭти плейсхолдеры могут быть использованы в сообщениях для отклика на вакансии, чтобы динамически подставлять соответствующие данные в текст сообщения. Например:\n\n```\nМеня заинтересовала ваша вакансия %(vacancy_name)s. Прошу рассмотреть мою кандидатуру. С уважением, %(first_name)s %(last_name)s.\n```\n\nТак же можно делать текст уникальным с помощью `{}`. Внутри них через `|` перечисляются варианты, один из которых будет случайно выбран:\n\n```\n{Здоров|Привет}, {как {ты|сам}|что делаешь}?\n```\n\nВ итоге получится что-то типа:\n\n```\nПривет, как ты?\n```\n\n### Использование AI для генерации сопроводительного письма\n\n* Перейдите на сайт [blackbox.ai](https://www.blackbox.ai) и создайте чат. \n* В первом сообщении опишите свой опыт и тп. \n* Далее откройте devtools, нажав `F12`. \n* Во вкладке `Network` последним должен быть POST-запрос на `https://www.blackbox.ai/api/chat`. \n* Запустите редактирование конфига:\n    ```sh\n    hh-applicant-tool config\n    ```\n* Измените конфиг:\n    ```json\n    {\n        // ...\n        \"blackbox\": {\n            \"session_id\": \"\u003cВ заголовках запроса найдите Cookie, скопируйте сюда значение sessionId до ;\u003e\",\n            \"chat_payload\": \u003cСюда вставьте тело запроса типа {\"messages\":[{\"id\":\"IXqdOx9\",\"content\":\"Я программист fullstack-разработчик...\",\"role\":\"user\"}],\"id\":\"IXqdOx9\",\"previewToken\":null,\"userId\":null,...,\"webSearchModePrompt\":false,\"deepSearchMode\":false}\u003e\n        }\n    }\n    ```\n* Пример рассылки откликов с генерированным письмом:\n    ```sh\n    hh-applicant-tool apply-similar -f --ai\n    ```\n\n### Написание плагинов\n\nУтилита использует систему плагинов. Все они лежат в [operations](https://github.com/s3rgeym/hh-applicant-tool/tree/main/hh_applicant_tool/operations). Модули расположенные там автоматически добавляются как доступные операции. За основу для своего плагина можно взять [whoami.py](https://github.com/s3rgeym/hh-applicant-tool/tree/main/hh_applicant_tool/operations/whoami.py).\n\nОтдельные замечания у меня к API HH. Оно пиздец какое кривое. Например, при создании заявки возвращается пустой ответ либо редирект, хотя по логике должен возвраться созданный объект. Так же в ответах сервера нет `Content-Length`. Из-за этого нельзя узнать есть тело у ответа сервера нужно его пробовать прочитать. Я так понял там какой-то прокси оборачивает все запросы и отдает всегда `Transfer-Encoding: Chunked`. А еще он возвращает 502 ошибку, когда бекенд на Java падает либо долго отвечает (таймаут)? А вот [язык запросов](https://hh.ru/article/1175) мне понравился. Можно что-то типа этого использовать `NOT (!ID:123 OR !ID:456 OR !ID:789)` что бы отсеить какие-то вакансии.\n\nДля создания своих плагинов прочитайте документацию:\n\n* [HH.RU OpenAPI](https://api.hh.ru/openapi/redoc)\n\nДля тестирования запросов к API используйте команду `call-api` и `jq` для вывода JSON в удобочитаемом формате.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs3rgeym%2Fhh-applicant-tool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fs3rgeym%2Fhh-applicant-tool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fs3rgeym%2Fhh-applicant-tool/lists"}