hh-applicant-tool 0.3.4__tar.gz → 0.3.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hh-applicant-tool might be problematic. Click here for more details.
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/PKG-INFO +33 -4
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/README.md +32 -3
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/apply_similar.py +56 -11
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/pyproject.toml +1 -1
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/__init__.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/__main__.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/api/__init__.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/api/client.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/api/errors.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/color_log.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/constants.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/main.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/__init__.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/authorize.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/call_api.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/clear_negotiations.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/list_resumes.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/refresh_token.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/update_resumes.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/whoami.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/telemetry_client.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/types.py +0 -0
- {hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hh-applicant-tool
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Senior YAML Developer
|
|
6
6
|
Author-email: yamldeveloper@proton.me
|
|
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
|
|
|
37
37
|
Работает с Python >= 3.10. Нужную версию Python можно поставить через
|
|
38
38
|
asdf/pyenv/conda и что-то еще...
|
|
39
39
|
|
|
40
|
-
Данная утилита написана для Linux, но будет работать и на Ga..Mac OS, и в Windows, но с WSL не будет, так как для авторизации требуются оконный сервер X11 либо Wayland — только прямая установка пакета через pip в Windows. После авторизации вы можете перенести `~/.config/hh-applicant-tool/config.json` (
|
|
40
|
+
Данная утилита написана для Linux, но будет работать и на Ga..Mac OS, и в Windows, но с WSL не будет, так как для авторизации требуются оконный сервер X11 либо Wayland — только прямая установка пакета через pip в Windows. После авторизации вы можете перенести `~/.config/hh-applicant-tool/config.json` (`C:\Users\%username%\AppData\Roaming\hh-applicant-tool\config.json` — в Windows) на сервер и запускать утилиту через systemd или cron. Столь странный процесс связан с тем, что на странице авторизации запускается море скриптов, которые шифруют данные на клиенте перед отправкой на сервер, а так же выполняется куча запросов чтобы проверить не бот ли ты. Хорошо, что после авторизации никаких проверок по факту нет, даже айпи не проверяется на соответсвие тому с какого была авторизация. В этой лапше мне лень разбираться. Так же при наличии рутованного телефона можно вытащить `access` и `refresh` токены из официального приложения и добавить их в конфиг.
|
|
41
41
|
|
|
42
42
|
Пример работы:
|
|
43
43
|
|
|
@@ -67,9 +67,34 @@ $ pipx install 'hh-applicant-tool[qt]'
|
|
|
67
67
|
$ pipx install git+https://github.com/s3rgeym/hh-applicant-tool
|
|
68
68
|
|
|
69
69
|
# Для обновления до новой версии
|
|
70
|
-
$ pipx upgrade
|
|
70
|
+
$ pipx upgrade hh-applicant-tool
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Отдельно я распишу процесс установки в **Windows** в подробностях:
|
|
74
|
+
|
|
75
|
+
* Для начала поставьте Python 3 любым удобным способом.
|
|
76
|
+
* Запустите терминал/консоль от Администратора и выполните:
|
|
77
|
+
```ps
|
|
78
|
+
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
|
|
79
|
+
```
|
|
80
|
+
Без этой настройки не будут работать виртуальные окружения.
|
|
81
|
+
* Создайте и активируйте виртуальное окружение:
|
|
82
|
+
```ps
|
|
83
|
+
PS> python -m pip venv hh-applicant-venv
|
|
84
|
+
PS> .\hh-applicant-venv\Scripts\activate
|
|
85
|
+
```
|
|
86
|
+
* Поставьте все пакеты в виртуальное окружение `hh-applicant-tool`:
|
|
87
|
+
```ps
|
|
88
|
+
(hh-applicant-venv) PS> pip install hh-applicant-tool[qt]
|
|
89
|
+
```
|
|
90
|
+
* Проверьте работает ли оно:
|
|
91
|
+
```ps
|
|
92
|
+
(hh-applicant-venv) PS> hh-applicant-tool -h
|
|
93
|
+
```
|
|
94
|
+
* В случае неудачи, вернитесь к первому шагу. Для последующих запусков сперва активируйте виртуальное окружение.
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
73
98
|
Использование:
|
|
74
99
|
|
|
75
100
|
```bash
|
|
@@ -135,7 +160,7 @@ https://hh.ru/employer/1918903
|
|
|
135
160
|
| **update-resumes** | Обновить все резюме. Аналогично нажатию кнопки «Обновить дату». |
|
|
136
161
|
| **apply-similar** | Откликнуться на все подходящие вакансии. Лимит = 200 в день |
|
|
137
162
|
| **clear-negotiations** | Удаляет отказы и отменяет заявки, которые долго висят |
|
|
138
|
-
| **call-api** | Вызов произвольного метода API с выводом результата.
|
|
163
|
+
| **call-api** | Вызов произвольного метода API с выводом результата. |
|
|
139
164
|
| **refresh-token** | Обновляет access_token. |
|
|
140
165
|
|
|
141
166
|
Авторизуемся:
|
|
@@ -146,6 +171,10 @@ $ hh-applicant-tool -vv authorize
|
|
|
146
171
|
|
|
147
172
|

|
|
148
173
|
|
|
174
|
+
> В Windows не забудьте разрешить доступ к сети (Allow access) в всплывающем окне.
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
149
178
|
В случае успешной авторизации токены будут сохранены в `~/.config/hh-applicant-tool/config.json`:
|
|
150
179
|
|
|
151
180
|
```json
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
Работает с Python >= 3.10. Нужную версию Python можно поставить через
|
|
19
19
|
asdf/pyenv/conda и что-то еще...
|
|
20
20
|
|
|
21
|
-
Данная утилита написана для Linux, но будет работать и на Ga..Mac OS, и в Windows, но с WSL не будет, так как для авторизации требуются оконный сервер X11 либо Wayland — только прямая установка пакета через pip в Windows. После авторизации вы можете перенести `~/.config/hh-applicant-tool/config.json` (
|
|
21
|
+
Данная утилита написана для Linux, но будет работать и на Ga..Mac OS, и в Windows, но с WSL не будет, так как для авторизации требуются оконный сервер X11 либо Wayland — только прямая установка пакета через pip в Windows. После авторизации вы можете перенести `~/.config/hh-applicant-tool/config.json` (`C:\Users\%username%\AppData\Roaming\hh-applicant-tool\config.json` — в Windows) на сервер и запускать утилиту через systemd или cron. Столь странный процесс связан с тем, что на странице авторизации запускается море скриптов, которые шифруют данные на клиенте перед отправкой на сервер, а так же выполняется куча запросов чтобы проверить не бот ли ты. Хорошо, что после авторизации никаких проверок по факту нет, даже айпи не проверяется на соответсвие тому с какого была авторизация. В этой лапше мне лень разбираться. Так же при наличии рутованного телефона можно вытащить `access` и `refresh` токены из официального приложения и добавить их в конфиг.
|
|
22
22
|
|
|
23
23
|
Пример работы:
|
|
24
24
|
|
|
@@ -48,9 +48,34 @@ $ pipx install 'hh-applicant-tool[qt]'
|
|
|
48
48
|
$ pipx install git+https://github.com/s3rgeym/hh-applicant-tool
|
|
49
49
|
|
|
50
50
|
# Для обновления до новой версии
|
|
51
|
-
$ pipx upgrade
|
|
51
|
+
$ pipx upgrade hh-applicant-tool
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
Отдельно я распишу процесс установки в **Windows** в подробностях:
|
|
55
|
+
|
|
56
|
+
* Для начала поставьте Python 3 любым удобным способом.
|
|
57
|
+
* Запустите терминал/консоль от Администратора и выполните:
|
|
58
|
+
```ps
|
|
59
|
+
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
|
|
60
|
+
```
|
|
61
|
+
Без этой настройки не будут работать виртуальные окружения.
|
|
62
|
+
* Создайте и активируйте виртуальное окружение:
|
|
63
|
+
```ps
|
|
64
|
+
PS> python -m pip venv hh-applicant-venv
|
|
65
|
+
PS> .\hh-applicant-venv\Scripts\activate
|
|
66
|
+
```
|
|
67
|
+
* Поставьте все пакеты в виртуальное окружение `hh-applicant-tool`:
|
|
68
|
+
```ps
|
|
69
|
+
(hh-applicant-venv) PS> pip install hh-applicant-tool[qt]
|
|
70
|
+
```
|
|
71
|
+
* Проверьте работает ли оно:
|
|
72
|
+
```ps
|
|
73
|
+
(hh-applicant-venv) PS> hh-applicant-tool -h
|
|
74
|
+
```
|
|
75
|
+
* В случае неудачи, вернитесь к первому шагу. Для последующих запусков сперва активируйте виртуальное окружение.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
54
79
|
Использование:
|
|
55
80
|
|
|
56
81
|
```bash
|
|
@@ -116,7 +141,7 @@ https://hh.ru/employer/1918903
|
|
|
116
141
|
| **update-resumes** | Обновить все резюме. Аналогично нажатию кнопки «Обновить дату». |
|
|
117
142
|
| **apply-similar** | Откликнуться на все подходящие вакансии. Лимит = 200 в день |
|
|
118
143
|
| **clear-negotiations** | Удаляет отказы и отменяет заявки, которые долго висят |
|
|
119
|
-
| **call-api** | Вызов произвольного метода API с выводом результата.
|
|
144
|
+
| **call-api** | Вызов произвольного метода API с выводом результата. |
|
|
120
145
|
| **refresh-token** | Обновляет access_token. |
|
|
121
146
|
|
|
122
147
|
Авторизуемся:
|
|
@@ -127,6 +152,10 @@ $ hh-applicant-tool -vv authorize
|
|
|
127
152
|
|
|
128
153
|

|
|
129
154
|
|
|
155
|
+
> В Windows не забудьте разрешить доступ к сети (Allow access) в всплывающем окне.
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
130
159
|
В случае успешной авторизации токены будут сохранены в `~/.config/hh-applicant-tool/config.json`:
|
|
131
160
|
|
|
132
161
|
```json
|
{hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/apply_similar.py
RENAMED
|
@@ -25,8 +25,9 @@ class Namespace(BaseNamespace):
|
|
|
25
25
|
page_interval: Tuple[float, float]
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
# https://api.hh.ru/openapi/redoc
|
|
28
29
|
class Operation(BaseOperation):
|
|
29
|
-
"""Откликнуться на все подходящие
|
|
30
|
+
"""Откликнуться на все подходящие вакансии. По умолчанию применяются значения, которые были отмечены галочками в форме для поиска на сайте"""
|
|
30
31
|
|
|
31
32
|
def setup_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
32
33
|
parser.add_argument("--resume-id", help="Идентефикатор резюме")
|
|
@@ -53,6 +54,24 @@ class Operation(BaseOperation):
|
|
|
53
54
|
default="1-3",
|
|
54
55
|
type=self._parse_interval,
|
|
55
56
|
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--order-by",
|
|
59
|
+
help="Сортировка вакансий",
|
|
60
|
+
choices=[
|
|
61
|
+
"publication_time",
|
|
62
|
+
"salary_desc",
|
|
63
|
+
"salary_asc",
|
|
64
|
+
"relevance",
|
|
65
|
+
"distance",
|
|
66
|
+
],
|
|
67
|
+
default="relevance",
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--search",
|
|
71
|
+
help="Строка поиска для фильтрации вакансий, например, 'москва бухгалтер 100500', те можно и город указать, и ожидаемую зряплату",
|
|
72
|
+
type=str,
|
|
73
|
+
default=None,
|
|
74
|
+
)
|
|
56
75
|
|
|
57
76
|
@staticmethod
|
|
58
77
|
def _parse_interval(interval: str) -> Tuple[float, float]:
|
|
@@ -84,6 +103,8 @@ class Operation(BaseOperation):
|
|
|
84
103
|
apply_max_interval,
|
|
85
104
|
page_min_interval,
|
|
86
105
|
page_max_interval,
|
|
106
|
+
args.order_by,
|
|
107
|
+
args.search,
|
|
87
108
|
)
|
|
88
109
|
|
|
89
110
|
def _get_resume_id(self, args: Namespace, api: ApiClient) -> str:
|
|
@@ -119,12 +140,20 @@ class Operation(BaseOperation):
|
|
|
119
140
|
apply_max_interval: float,
|
|
120
141
|
page_min_interval: float,
|
|
121
142
|
page_max_interval: float,
|
|
143
|
+
order_by: str,
|
|
144
|
+
search: str | None = None,
|
|
122
145
|
) -> None:
|
|
123
146
|
telemetry_client = get_telemetry_client()
|
|
124
147
|
telemetry_data = defaultdict(dict)
|
|
125
148
|
|
|
126
149
|
vacancies = self._get_vacancies(
|
|
127
|
-
api,
|
|
150
|
+
api,
|
|
151
|
+
resume_id,
|
|
152
|
+
page_min_interval,
|
|
153
|
+
page_max_interval,
|
|
154
|
+
per_page=100,
|
|
155
|
+
order_by=order_by,
|
|
156
|
+
search=search,
|
|
128
157
|
)
|
|
129
158
|
|
|
130
159
|
self._collect_vacancy_telemetry(telemetry_data, vacancies)
|
|
@@ -173,13 +202,23 @@ class Operation(BaseOperation):
|
|
|
173
202
|
params = {
|
|
174
203
|
"resume_id": resume_id,
|
|
175
204
|
"vacancy_id": vacancy["id"],
|
|
176
|
-
"message":
|
|
177
|
-
random.choice(application_messages) % vacancy
|
|
178
|
-
if force_message or vacancy["response_letter_required"]
|
|
179
|
-
else ""
|
|
180
|
-
),
|
|
205
|
+
"message": "",
|
|
181
206
|
}
|
|
182
207
|
|
|
208
|
+
if vacancy.get("response_letter_required"):
|
|
209
|
+
message_template = random.choice(application_messages)
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
params["message"] = template_message % vacancy
|
|
213
|
+
except TypeError as ex:
|
|
214
|
+
# TypeError: not enough arguments for format string
|
|
215
|
+
# API HH все кривое, иногда нет идентификатора работодателя, иногда у вакансии нет названия.
|
|
216
|
+
# И это типа рашн хайлоад, где из-за дрочки на аджайл слепили кривую говнину.
|
|
217
|
+
logger.error(
|
|
218
|
+
f"Ошибка форматирования шаблона сообщения {template_message!r} для {vacancy = }"
|
|
219
|
+
)
|
|
220
|
+
continue
|
|
221
|
+
|
|
183
222
|
res = api.post("/negotiations", params)
|
|
184
223
|
assert res == {}
|
|
185
224
|
print(
|
|
@@ -205,14 +244,20 @@ class Operation(BaseOperation):
|
|
|
205
244
|
page_min_interval: float,
|
|
206
245
|
page_max_interval: float,
|
|
207
246
|
per_page: int,
|
|
247
|
+
order_by: str,
|
|
248
|
+
search: str | None = None,
|
|
208
249
|
) -> list[VacancyItem]:
|
|
209
250
|
rv = []
|
|
210
251
|
for page in range(20):
|
|
252
|
+
params = {
|
|
253
|
+
"page": page,
|
|
254
|
+
"per_page": per_page,
|
|
255
|
+
"order_by": order_by,
|
|
256
|
+
}
|
|
257
|
+
if search:
|
|
258
|
+
params["text"] = search
|
|
211
259
|
res: ApiListResponse = api.get(
|
|
212
|
-
f"/resumes/{resume_id}/similar_vacancies",
|
|
213
|
-
page=page,
|
|
214
|
-
per_page=per_page,
|
|
215
|
-
order_by="relevance",
|
|
260
|
+
f"/resumes/{resume_id}/similar_vacancies", params
|
|
216
261
|
)
|
|
217
262
|
rv.extend(res["items"])
|
|
218
263
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/__init__.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/authorize.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/call_api.py
RENAMED
|
File without changes
|
|
File without changes
|
{hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/list_resumes.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/refresh_token.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.4 → hh_applicant_tool-0.3.5}/hh_applicant_tool/operations/update_resumes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|