hh-applicant-tool 0.3.4__py3-none-any.whl → 0.3.5__py3-none-any.whl

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.

@@ -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, resume_id, page_min_interval, page_max_interval, per_page=100
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hh-applicant-tool
3
- Version: 0.3.4
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` (я не знаю, где винда что хранит) на сервер и запускать утилиту через systemd или cron. Столь странный процесс связан с тем, что на странице авторизации запускается море скриптов, которые шифруют данные на клиенте перед отправкой на сервер, а так же выполняется куча запросов чтобы проверить не бот ли ты. Хорошо, что после авторизации никаких проверок по факту нет, даже айпи не проверяется на соответсвие тому с какого была авторизация. В этой лапше мне лень разбираться. Так же при наличии рутованного телефона можно вытащить `access` и `refresh` токены из официального приложения и добавить их в конфиг.
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 'hh-applicant-tool'
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
  ![image](https://github.com/user-attachments/assets/88961e31-4ea3-478f-8c43-914d6785bc3b)
148
173
 
174
+ > В Windows не забудьте разрешить доступ к сети (Allow access) в всплывающем окне.
175
+
176
+
177
+
149
178
  В случае успешной авторизации токены будут сохранены в `~/.config/hh-applicant-tool/config.json`:
150
179
 
151
180
  ```json
@@ -7,7 +7,7 @@ hh_applicant_tool/color_log.py,sha256=gN6j1Ayy1G7qOMI_e3WvfYw_ublzeQbKgsVLhqGg_3
7
7
  hh_applicant_tool/constants.py,sha256=YdNz0CF4swJ9OO5vVpOZ39RP-05xSU0Ghw4Y6BhISoE,468
8
8
  hh_applicant_tool/main.py,sha256=XLKsd8mpCKuFoP3ESMpgJKdGL3m6tOQ8kKrOzCN-dwA,3075
9
9
  hh_applicant_tool/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- hh_applicant_tool/operations/apply_similar.py,sha256=V8oLm200m_QCtnjgJ0gY86hBKwec1GDUP8R0Cm5yv_U,10838
10
+ hh_applicant_tool/operations/apply_similar.py,sha256=RUV-hVyZZGEBBM7sfi7Ssg5c4plyc2JNETlL5PoDpPY,12875
11
11
  hh_applicant_tool/operations/authorize.py,sha256=TyUTCSOGwSYVJMEd5vSI981LRRI-RZf8hnlVYhtRVwA,3184
12
12
  hh_applicant_tool/operations/call_api.py,sha256=oWAfvy4LwbsQ8HsgI_3en3sMTlu3ZWU7NzpxssrUNSU,1472
13
13
  hh_applicant_tool/operations/clear_negotiations.py,sha256=5ybdJMUfV9XYxnn2y4zvWdS_ZE8yXAbFJoXOMyqetw8,4041
@@ -18,7 +18,7 @@ hh_applicant_tool/operations/whoami.py,sha256=kdLQ_FjYzpJPKxFlocxf7vgXhW1zocb0bd
18
18
  hh_applicant_tool/telemetry_client.py,sha256=TlsNKlclPyJqLPO0xHkHKBIhT8bmgx1ZBup4PjE8w5E,2296
19
19
  hh_applicant_tool/types.py,sha256=q3yaIcq-UOkPzjxws0OFa4w9fTty-yx79_dic70_dUM,843
20
20
  hh_applicant_tool/utils.py,sha256=wXcxs5IinK7PH6ipCCpngw7faUiboEpi9a8j1wDEPKw,2282
21
- hh_applicant_tool-0.3.4.dist-info/METADATA,sha256=0z_iJf0g4i9SGWTLmNd9zlOEGrWV5JonQwoyviXhykM,15881
22
- hh_applicant_tool-0.3.4.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
23
- hh_applicant_tool-0.3.4.dist-info/entry_points.txt,sha256=Vb7M2YaYLMtKYJZh8chIrXZApMzSRFT1-rQw-U9r10g,65
24
- hh_applicant_tool-0.3.4.dist-info/RECORD,,
21
+ hh_applicant_tool-0.3.5.dist-info/METADATA,sha256=qUVl-yMhKOXWP6AhIIwdu5AFYX05npx9lQvsRMXYbx8,17247
22
+ hh_applicant_tool-0.3.5.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
23
+ hh_applicant_tool-0.3.5.dist-info/entry_points.txt,sha256=Vb7M2YaYLMtKYJZh8chIrXZApMzSRFT1-rQw-U9r10g,65
24
+ hh_applicant_tool-0.3.5.dist-info/RECORD,,