hh-applicant-tool 0.3.7__py3-none-any.whl → 0.3.9__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.
- hh_applicant_tool/api/client.py +3 -1
- hh_applicant_tool/main.py +21 -4
- hh_applicant_tool/operations/apply_similar.py +5 -6
- hh_applicant_tool/telemetry_client.py +28 -27
- hh_applicant_tool/utils.py +2 -1
- {hh_applicant_tool-0.3.7.dist-info → hh_applicant_tool-0.3.9.dist-info}/METADATA +9 -9
- {hh_applicant_tool-0.3.7.dist-info → hh_applicant_tool-0.3.9.dist-info}/RECORD +9 -9
- {hh_applicant_tool-0.3.7.dist-info → hh_applicant_tool-0.3.9.dist-info}/WHEEL +0 -0
- {hh_applicant_tool-0.3.7.dist-info → hh_applicant_tool-0.3.9.dist-info}/entry_points.txt +0 -0
hh_applicant_tool/api/client.py
CHANGED
|
@@ -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)
|
|
@@ -105,6 +106,7 @@ class BaseClient:
|
|
|
105
106
|
method,
|
|
106
107
|
url,
|
|
107
108
|
**{"data" if has_body else "params": params},
|
|
109
|
+
proxies=self.proxies,
|
|
108
110
|
allow_redirects=False,
|
|
109
111
|
)
|
|
110
112
|
try:
|
hh_applicant_tool/main.py
CHANGED
|
@@ -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)
|
|
@@ -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,7 @@ class Operation(BaseOperation):
|
|
|
159
159
|
search: str | None = None,
|
|
160
160
|
reply_message: str | None = None,
|
|
161
161
|
) -> None:
|
|
162
|
-
telemetry_client =
|
|
162
|
+
telemetry_client = TelemetryClient(proxies=api.proxies)
|
|
163
163
|
telemetry_data = defaultdict(dict)
|
|
164
164
|
|
|
165
165
|
vacancies = self._get_vacancies(
|
|
@@ -346,8 +346,7 @@ class Operation(BaseOperation):
|
|
|
346
346
|
|
|
347
347
|
print("📝 Отклики на вакансии разосланы!")
|
|
348
348
|
|
|
349
|
-
# Я собираюсь
|
|
350
|
-
# считаю вселенским злом, так что телеметирию не трогайте
|
|
349
|
+
# Я собираюсь выложить контакты херок в общественный доступ
|
|
351
350
|
self._send_telemetry(telemetry_client, telemetry_data)
|
|
352
351
|
|
|
353
352
|
def _get_vacancies(
|
|
@@ -3,9 +3,11 @@ 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
|
-
import
|
|
7
|
+
from functools import partialmethod
|
|
8
|
+
import warnings
|
|
9
|
+
|
|
10
|
+
warnings.filterwarnings('ignore', message='Unverified HTTPS request')
|
|
9
11
|
|
|
10
12
|
logger = logging.getLogger(__package__)
|
|
11
13
|
|
|
@@ -19,40 +21,42 @@ class TelemetryError(Exception):
|
|
|
19
21
|
class TelemetryClient:
|
|
20
22
|
"""Клиент для отправки телеметрии на сервер."""
|
|
21
23
|
|
|
22
|
-
server_address =
|
|
23
|
-
"aHR0cDovLzMxLjEzMS4yNTEuMTA3OjU0MTU2"
|
|
24
|
-
).decode()
|
|
24
|
+
server_address: str = "https://hh-applicant-tool.mooo.com:54157/"
|
|
25
25
|
|
|
26
26
|
def __init__(
|
|
27
27
|
self,
|
|
28
28
|
server_address: Optional[str] = None,
|
|
29
|
+
*,
|
|
29
30
|
session: Optional[requests.Session] = None,
|
|
31
|
+
user_agent: str = "Mozilla/5.0 (HHApplicantTelemetry/1.0)",
|
|
32
|
+
proxies: dict | None = None,
|
|
30
33
|
) -> None:
|
|
31
|
-
"""
|
|
32
|
-
Инициализация клиента.
|
|
33
|
-
|
|
34
|
-
:param server_address: Адрес сервера для отправки телеметрии.
|
|
35
|
-
:param session: Сессия для повторного использования соединения.
|
|
36
|
-
"""
|
|
37
|
-
self.session = session or requests.Session()
|
|
38
34
|
self.server_address = os.getenv(
|
|
39
35
|
"TELEMETRY_SERVER", server_address or self.server_address
|
|
40
36
|
)
|
|
37
|
+
self.session = session or requests.Session()
|
|
38
|
+
self.user_agent = user_agent
|
|
39
|
+
self.proxies = proxies
|
|
41
40
|
|
|
42
|
-
def
|
|
43
|
-
self,
|
|
41
|
+
def request(
|
|
42
|
+
self,
|
|
43
|
+
method: str,
|
|
44
|
+
endpoint: str,
|
|
45
|
+
data: Dict[str, Any] | None = None,
|
|
44
46
|
) -> Dict[str, Any]:
|
|
45
|
-
|
|
46
|
-
Отправка телеметрии на сервер.
|
|
47
|
-
|
|
48
|
-
:param endpoint: Конечная точка на сервере.
|
|
49
|
-
:param data: Данные для отправки.
|
|
50
|
-
:return: Ответ сервера в формате JSON.
|
|
51
|
-
:raises TelemetryError: Если произошла ошибка при отправке или декодировании JSON.
|
|
52
|
-
"""
|
|
47
|
+
method = method.upper()
|
|
53
48
|
url = urljoin(self.server_address, endpoint)
|
|
49
|
+
has_body = method in ["POST", "PUT", "PATCH"]
|
|
54
50
|
try:
|
|
55
|
-
response = self.session.
|
|
51
|
+
response = self.session.request(
|
|
52
|
+
method,
|
|
53
|
+
url,
|
|
54
|
+
headers={"User-Agent": self.user_agent},
|
|
55
|
+
proxies=self.proxies,
|
|
56
|
+
params=data if not has_body else None,
|
|
57
|
+
json=data if has_body else None,
|
|
58
|
+
verify=False, # Игнорирование истекшего сертификата
|
|
59
|
+
)
|
|
56
60
|
# response.raise_for_status()
|
|
57
61
|
result = response.json()
|
|
58
62
|
if "error" in result:
|
|
@@ -65,7 +69,4 @@ class TelemetryClient:
|
|
|
65
69
|
) as ex:
|
|
66
70
|
raise TelemetryError(str(ex)) from ex
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
@cache
|
|
70
|
-
def get_client() -> TelemetryClient:
|
|
71
|
-
return TelemetryClient()
|
|
72
|
+
send_telemetry = partialmethod(request, "POST")
|
hh_applicant_tool/utils.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hh-applicant-tool
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
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,13 @@ $ 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
|
+
| --- | --- |
|
|
175
|
+
| `user_agent` | Кастомный юзерагент, передаваемый при кажом запросе, например, `Mozilla/5.0 YablanBrowser` |
|
|
176
|
+
| `proxy_url` | Прокси, используемый для всех запросов, например, `socks5h://127.0.0.1:9050` |
|
|
177
|
+
| `reply_message` | Сообщение для ответа работодателю при отклике на вакансии, см. формат сообщений |
|
|
178
178
|
|
|
179
179
|
### Описание команд
|
|
180
180
|
|
|
@@ -261,7 +261,7 @@ https://hh.ru/employer/1918903
|
|
|
261
261
|
Эти плейсхолдеры могут быть использованы в сообщениях для отклика на вакансии, чтобы динамически подставлять соответствующие данные в текст сообщения. Например:
|
|
262
262
|
|
|
263
263
|
```
|
|
264
|
-
|
|
264
|
+
Меня заинтересовала ваша вакансия %(vacancy_name)s. Прошу рассмотреть мою кандидатуру. С уважением, %(first_name)s %(last_name)s.
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
Так же можно делать текст уникальным с помощью `{}`. Внутри них через `|` перечисляются варианты, один из которых будет случайно выбран:
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
hh_applicant_tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
hh_applicant_tool/__main__.py,sha256=cwKJAAML0RRKT9Qbzcwf07HHcuSd8oh7kx4P1apndWQ,84
|
|
3
3
|
hh_applicant_tool/api/__init__.py,sha256=kgFSHibRaAugN2BA3U1djEa20qgKJUUVouwJzjEB0DU,84
|
|
4
|
-
hh_applicant_tool/api/client.py,sha256=
|
|
4
|
+
hh_applicant_tool/api/client.py,sha256=um9NX22hNOtSuPCobCKf1anIFp-jiZlIXm4BuqN-L7k,7997
|
|
5
5
|
hh_applicant_tool/api/errors.py,sha256=0SoWKnsSUA0K2YgQA8GwGhe-pRMwtfK94MR6_MgbORQ,1722
|
|
6
6
|
hh_applicant_tool/color_log.py,sha256=gN6j1Ayy1G7qOMI_e3WvfYw_ublzeQbKgsVLhqGg_3s,823
|
|
7
7
|
hh_applicant_tool/constants.py,sha256=lpgKkP2chWgTnBXvzxbSPWpKcfzp8VxMTlkssFcQhH4,469
|
|
8
|
-
hh_applicant_tool/main.py,sha256=
|
|
8
|
+
hh_applicant_tool/main.py,sha256=B_kI9MlaT_064r5CL7Pjlzu76QPB-hXCaMpFtB-BOfg,4596
|
|
9
9
|
hh_applicant_tool/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
hh_applicant_tool/operations/apply_similar.py,sha256=
|
|
10
|
+
hh_applicant_tool/operations/apply_similar.py,sha256=8L0Im0bPRxn-tsteI9X4D5gPpr6PemuzK0x-IszrOis,17021
|
|
11
11
|
hh_applicant_tool/operations/authorize.py,sha256=TyUTCSOGwSYVJMEd5vSI981LRRI-RZf8hnlVYhtRVwA,3184
|
|
12
12
|
hh_applicant_tool/operations/call_api.py,sha256=qwPDrWP9tiqHkaYYWYBZtymj9AaxObB86Eny-Bf5q_c,1314
|
|
13
13
|
hh_applicant_tool/operations/clear_negotiations.py,sha256=98Yuw9xP4dN5sUnUKlZxqfhU40TQ-aCjK4vj4LRTeYo,3894
|
|
@@ -15,10 +15,10 @@ hh_applicant_tool/operations/list_resumes.py,sha256=XBrVFTnl45BUtuvjVm70h_CXZrOv
|
|
|
15
15
|
hh_applicant_tool/operations/refresh_token.py,sha256=hYTmzBzJFSsb-LDO2_w0Y30WVWsctIH7vTzirkLwzWo,1267
|
|
16
16
|
hh_applicant_tool/operations/update_resumes.py,sha256=gGxMYMoT9GqJjwn4AgrOAEJCZu4sdhaV0VmPr3jG-q8,1049
|
|
17
17
|
hh_applicant_tool/operations/whoami.py,sha256=sg0r7m6oKkpMEmGt4QdtYdS-1gf-1KKdnk32yblbRJs,714
|
|
18
|
-
hh_applicant_tool/telemetry_client.py,sha256=
|
|
18
|
+
hh_applicant_tool/telemetry_client.py,sha256=nNNr1drXY9Z01u5tJX---BXxBg1y06nJpNbhU45DmE0,2239
|
|
19
19
|
hh_applicant_tool/types.py,sha256=q3yaIcq-UOkPzjxws0OFa4w9fTty-yx79_dic70_dUM,843
|
|
20
|
-
hh_applicant_tool/utils.py,sha256=
|
|
21
|
-
hh_applicant_tool-0.3.
|
|
22
|
-
hh_applicant_tool-0.3.
|
|
23
|
-
hh_applicant_tool-0.3.
|
|
24
|
-
hh_applicant_tool-0.3.
|
|
20
|
+
hh_applicant_tool/utils.py,sha256=lHQh94CEwWp14Ty50ecZPcR3YyqLDVlmgmZlrBiBgHQ,2557
|
|
21
|
+
hh_applicant_tool-0.3.9.dist-info/METADATA,sha256=FbQA5oxUmGEGhuUehYcci7vMrUmiad0a8OUqPOHqsG8,20575
|
|
22
|
+
hh_applicant_tool-0.3.9.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
23
|
+
hh_applicant_tool-0.3.9.dist-info/entry_points.txt,sha256=Vb7M2YaYLMtKYJZh8chIrXZApMzSRFT1-rQw-U9r10g,65
|
|
24
|
+
hh_applicant_tool-0.3.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|