hh-applicant-tool 0.3.7__tar.gz → 0.3.8__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.7 → hh_applicant_tool-0.3.8}/PKG-INFO +8 -9
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/README.md +6 -7
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/api/client.py +5 -1
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/main.py +21 -4
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/apply_similar.py +9 -6
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/telemetry_client.py +0 -6
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/utils.py +2 -1
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/pyproject.toml +2 -2
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/__init__.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/__main__.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/api/__init__.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/api/errors.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/color_log.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/constants.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/__init__.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/authorize.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/call_api.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/clear_negotiations.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/list_resumes.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/refresh_token.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/update_resumes.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/whoami.py +0 -0
- {hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/types.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.8
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Senior YAML Developer
|
|
6
6
|
Author-email: yamldeveloper@proton.me
|
|
@@ -14,7 +14,7 @@ Provides-Extra: qt
|
|
|
14
14
|
Requires-Dist: prettytable (>=3.6.0,<4.0.0)
|
|
15
15
|
Requires-Dist: pyqt6 (>=6.7.1,<7.0.0) ; extra == "qt"
|
|
16
16
|
Requires-Dist: pyqt6-webengine (>=6.7.0,<7.0.0) ; extra == "qt"
|
|
17
|
-
Requires-Dist: requests (>=2.
|
|
17
|
+
Requires-Dist: requests[socks] (>=2.32.3,<3.0.0)
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
|
|
20
20
|
## HH Applicant Tool
|
|
@@ -168,13 +168,12 @@ $ hh-applicant-tool refresh-token
|
|
|
168
168
|
| **Linux** | `~/.config/hh-applicant-tool/config.json` |
|
|
169
169
|
|
|
170
170
|
|
|
171
|
-
Через
|
|
171
|
+
Через конфиг можно задать дополнительные настройки:
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```
|
|
173
|
+
| Имя атрибута | Описание |
|
|
174
|
+
| `user_agent` | Кастомный юзерагент, передаваемый при кажом запросе, например, `Mozilla/5.0 YablanBrowser` |
|
|
175
|
+
| `proxy_url` | Прокси, используемый для всех запросов, например, `socks5h://127.0.0.1:9050` |
|
|
176
|
+
| `reply_message` | Сообщение для ответа работодателю при отклике на вакансии, см. формат сообщений |
|
|
178
177
|
|
|
179
178
|
### Описание команд
|
|
180
179
|
|
|
@@ -261,7 +260,7 @@ https://hh.ru/employer/1918903
|
|
|
261
260
|
Эти плейсхолдеры могут быть использованы в сообщениях для отклика на вакансии, чтобы динамически подставлять соответствующие данные в текст сообщения. Например:
|
|
262
261
|
|
|
263
262
|
```
|
|
264
|
-
|
|
263
|
+
Меня заинтересовала ваша вакансия %(vacancy_name)s. Прошу рассмотреть мою кандидатуру. С уважением, %(first_name)s %(last_name)s.
|
|
265
264
|
```
|
|
266
265
|
|
|
267
266
|
Так же можно делать текст уникальным с помощью `{}`. Внутри них через `|` перечисляются варианты, один из которых будет случайно выбран:
|
|
@@ -149,13 +149,12 @@ $ hh-applicant-tool refresh-token
|
|
|
149
149
|
| **Linux** | `~/.config/hh-applicant-tool/config.json` |
|
|
150
150
|
|
|
151
151
|
|
|
152
|
-
Через
|
|
152
|
+
Через конфиг можно задать дополнительные настройки:
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
```
|
|
154
|
+
| Имя атрибута | Описание |
|
|
155
|
+
| `user_agent` | Кастомный юзерагент, передаваемый при кажом запросе, например, `Mozilla/5.0 YablanBrowser` |
|
|
156
|
+
| `proxy_url` | Прокси, используемый для всех запросов, например, `socks5h://127.0.0.1:9050` |
|
|
157
|
+
| `reply_message` | Сообщение для ответа работодателю при отклике на вакансии, см. формат сообщений |
|
|
159
158
|
|
|
160
159
|
### Описание команд
|
|
161
160
|
|
|
@@ -242,7 +241,7 @@ https://hh.ru/employer/1918903
|
|
|
242
241
|
Эти плейсхолдеры могут быть использованы в сообщениях для отклика на вакансии, чтобы динамически подставлять соответствующие данные в текст сообщения. Например:
|
|
243
242
|
|
|
244
243
|
```
|
|
245
|
-
|
|
244
|
+
Меня заинтересовала ваша вакансия %(vacancy_name)s. Прошу рассмотреть мою кандидатуру. С уважением, %(first_name)s %(last_name)s.
|
|
246
245
|
```
|
|
247
246
|
|
|
248
247
|
Так же можно делать текст уникальным с помощью `{}`. Внутри них через `|` перечисляются варианты, один из которых будет случайно выбран:
|
|
@@ -37,6 +37,7 @@ class BaseClient:
|
|
|
37
37
|
_: dataclasses.KW_ONLY
|
|
38
38
|
# TODO: сделать генерацию User-Agent'а как в приложении
|
|
39
39
|
user_agent: str | None = None
|
|
40
|
+
proxies: dict | None = None
|
|
40
41
|
session: Session | None = None
|
|
41
42
|
previous_request_time: float = 0.0
|
|
42
43
|
delay: float = 0.334
|
|
@@ -47,8 +48,8 @@ class BaseClient:
|
|
|
47
48
|
self.session = session = requests.session()
|
|
48
49
|
session.headers.update(
|
|
49
50
|
{
|
|
50
|
-
**self.additional_headers(),
|
|
51
51
|
"User-Agent": self.user_agent or self.default_user_agent(),
|
|
52
|
+
**self.additional_headers(),
|
|
52
53
|
}
|
|
53
54
|
)
|
|
54
55
|
logger.debug("Default Headers: %r", session.headers)
|
|
@@ -101,10 +102,13 @@ class BaseClient:
|
|
|
101
102
|
logger.debug("wait %fs before request", delay)
|
|
102
103
|
time.sleep(delay)
|
|
103
104
|
has_body = method in ["POST", "PUT"]
|
|
105
|
+
user_agent = self.user_agent or self.default_user_agent()
|
|
106
|
+
logger.debug(f"{user_agent = }")
|
|
104
107
|
response = self.session.request(
|
|
105
108
|
method,
|
|
106
109
|
url,
|
|
107
110
|
**{"data" if has_body else "params": params},
|
|
111
|
+
proxies=self.proxies,
|
|
108
112
|
allow_redirects=False,
|
|
109
113
|
)
|
|
110
114
|
try:
|
|
@@ -5,13 +5,13 @@ import logging
|
|
|
5
5
|
import sys
|
|
6
6
|
from abc import ABCMeta, abstractmethod
|
|
7
7
|
from importlib import import_module
|
|
8
|
-
from os import getenv
|
|
9
8
|
from pathlib import Path
|
|
10
9
|
from pkgutil import iter_modules
|
|
11
|
-
from typing import Sequence
|
|
10
|
+
from typing import Sequence, Literal
|
|
12
11
|
from .api import ApiClient
|
|
13
12
|
from .color_log import ColorHandler
|
|
14
13
|
from .utils import Config, get_config_path
|
|
14
|
+
from os import getenv
|
|
15
15
|
|
|
16
16
|
DEFAULT_CONFIG_PATH = (
|
|
17
17
|
get_config_path() / __package__.replace("_", "-") / "config.json"
|
|
@@ -34,6 +34,15 @@ class Namespace(argparse.Namespace):
|
|
|
34
34
|
config: Config
|
|
35
35
|
verbosity: int
|
|
36
36
|
delay: float
|
|
37
|
+
user_agent: str
|
|
38
|
+
proxy_url: str
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_proxies(args: Namespace) -> dict[Literal["http", "https"], str | None]:
|
|
42
|
+
return {
|
|
43
|
+
"http": args.config["proxy_url"] or getenv("HTTP_PROXY"),
|
|
44
|
+
"https": args.config["proxy_url"] or getenv("HTTPS_PROXY"),
|
|
45
|
+
}
|
|
37
46
|
|
|
38
47
|
|
|
39
48
|
def get_api(args: Namespace) -> ApiClient:
|
|
@@ -41,8 +50,9 @@ def get_api(args: Namespace) -> ApiClient:
|
|
|
41
50
|
api = ApiClient(
|
|
42
51
|
access_token=token.get("access_token"),
|
|
43
52
|
refresh_token=token.get("refresh_token"),
|
|
44
|
-
user_agent=args.config["user_agent"],
|
|
45
53
|
delay=args.delay,
|
|
54
|
+
user_agent=args.config["user_agent"],
|
|
55
|
+
proxies=get_proxies(args),
|
|
46
56
|
)
|
|
47
57
|
return api
|
|
48
58
|
|
|
@@ -87,6 +97,12 @@ class HHApplicantTool:
|
|
|
87
97
|
default=0.334,
|
|
88
98
|
help="Задержка между запросами к API HH",
|
|
89
99
|
)
|
|
100
|
+
parser.add_argument(
|
|
101
|
+
"--user-agent", help="User-Agent для каждого запроса"
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"--proxy-url", help="Прокси, используемый для запросов к API"
|
|
105
|
+
)
|
|
90
106
|
subparsers = parser.add_subparsers(help="commands")
|
|
91
107
|
package_dir = Path(__file__).resolve().parent / OPERATIONS
|
|
92
108
|
for _, module_name, _ in iter_modules([str(package_dir)]):
|
|
@@ -94,7 +110,8 @@ class HHApplicantTool:
|
|
|
94
110
|
op: BaseOperation = mod.Operation()
|
|
95
111
|
op_parser = subparsers.add_parser(
|
|
96
112
|
module_name.replace("_", "-"),
|
|
97
|
-
description=op.__doc__,
|
|
113
|
+
description=op.__doc__,
|
|
114
|
+
formatter_class=self.ArgumentFormatter,
|
|
98
115
|
)
|
|
99
116
|
op_parser.set_defaults(run=op.run)
|
|
100
117
|
op.setup_parser(op_parser)
|
{hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/apply_similar.py
RENAMED
|
@@ -9,10 +9,10 @@ from typing import TextIO, Tuple
|
|
|
9
9
|
from ..api import ApiClient, ApiError, BadRequest
|
|
10
10
|
from ..main import BaseOperation
|
|
11
11
|
from ..main import Namespace as BaseNamespace, get_api
|
|
12
|
-
from ..telemetry_client import TelemetryError
|
|
13
|
-
from ..telemetry_client import get_client as get_telemetry_client
|
|
12
|
+
from ..telemetry_client import TelemetryClient, TelemetryError
|
|
14
13
|
from ..types import ApiListResponse, VacancyItem
|
|
15
|
-
from ..utils import fix_datetime,
|
|
14
|
+
from ..utils import fix_datetime, truncate_string, random_text
|
|
15
|
+
from requests import Session
|
|
16
16
|
|
|
17
17
|
logger = logging.getLogger(__package__)
|
|
18
18
|
|
|
@@ -159,7 +159,11 @@ class Operation(BaseOperation):
|
|
|
159
159
|
search: str | None = None,
|
|
160
160
|
reply_message: str | None = None,
|
|
161
161
|
) -> None:
|
|
162
|
-
|
|
162
|
+
# TODO: вынести куда-нибудь в функцию
|
|
163
|
+
session = Session()
|
|
164
|
+
session.headers["User-Agent"] = "Mozilla/5.0 (HHApplicantTelemetry/1.0)"
|
|
165
|
+
session.proxies = dict(api.session.proxies)
|
|
166
|
+
telemetry_client = TelemetryClient(session=session)
|
|
163
167
|
telemetry_data = defaultdict(dict)
|
|
164
168
|
|
|
165
169
|
vacancies = self._get_vacancies(
|
|
@@ -346,8 +350,7 @@ class Operation(BaseOperation):
|
|
|
346
350
|
|
|
347
351
|
print("📝 Отклики на вакансии разосланы!")
|
|
348
352
|
|
|
349
|
-
# Я собираюсь
|
|
350
|
-
# считаю вселенским злом, так что телеметирию не трогайте
|
|
353
|
+
# Я собираюсь выложить контакты херок в общественный доступ
|
|
351
354
|
self._send_telemetry(telemetry_client, telemetry_data)
|
|
352
355
|
|
|
353
356
|
def _get_vacancies(
|
|
@@ -3,7 +3,6 @@ import json
|
|
|
3
3
|
from urllib.parse import urljoin
|
|
4
4
|
import requests
|
|
5
5
|
from typing import Optional, Dict, Any
|
|
6
|
-
from functools import cache
|
|
7
6
|
import logging
|
|
8
7
|
import base64
|
|
9
8
|
|
|
@@ -64,8 +63,3 @@ class TelemetryClient:
|
|
|
64
63
|
json.JSONDecodeError,
|
|
65
64
|
) as ex:
|
|
66
65
|
raise TelemetryError(str(ex)) from ex
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
@cache
|
|
70
|
-
def get_client() -> TelemetryClient:
|
|
71
|
-
return TelemetryClient()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "hh-applicant-tool"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.8"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Senior YAML Developer <yamldeveloper@proton.me>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -8,7 +8,7 @@ packages = [{include = "hh_applicant_tool"}]
|
|
|
8
8
|
|
|
9
9
|
[tool.poetry.dependencies]
|
|
10
10
|
python = "^3.10"
|
|
11
|
-
requests = "^2.
|
|
11
|
+
requests = {extras = ["socks"], version = "^2.32.3"}
|
|
12
12
|
prettytable = "^3.6.0"
|
|
13
13
|
pyqt6 = { version = "^6.7.1", optional = true }
|
|
14
14
|
pyqt6-webengine = { version = "^6.7.0", optional = true }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/__init__.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/authorize.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/call_api.py
RENAMED
|
File without changes
|
|
File without changes
|
{hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/list_resumes.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/refresh_token.py
RENAMED
|
File without changes
|
{hh_applicant_tool-0.3.7 → hh_applicant_tool-0.3.8}/hh_applicant_tool/operations/update_resumes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|