Skip to content

Commit

Permalink
поправил
Browse files Browse the repository at this point in the history
  • Loading branch information
s3rgeym committed Nov 11, 2024
1 parent cf6724b commit 63978ee
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 116 deletions.
228 changes: 116 additions & 112 deletions hh_applicant_tool/operations/apply_similar.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
from ..api import ApiClient, ApiError, BadRequest
from ..main import BaseOperation
from ..main import Namespace as BaseNamespace
from ..telemetry_client import TelemetryError
from ..telemetry_client import get_client as get_telemetry_client
from ..types import ApiListResponse, VacancyItem
from ..utils import print_err, truncate_string, fix_datetime
from ..telemetry_client import (
get_client as get_telemetry_client,
TelemetryError,
)
from ..utils import fix_datetime, print_err, truncate_string

logger = logging.getLogger(__package__)

Expand Down Expand Up @@ -71,11 +69,32 @@ def run(self, args: Namespace) -> None:
access_token=args.config["token"]["access_token"],
user_agent=args.config["user_agent"],
)
resume_id = self._get_resume_id(args, api)
application_messages = self._get_application_messages(args)

apply_min_interval, apply_max_interval = args.apply_interval
page_min_interval, page_max_interval = args.page_interval

self._apply_similar(
api,
resume_id,
args.force_message,
application_messages,
apply_min_interval,
apply_max_interval,
page_min_interval,
page_max_interval,
)

def _get_resume_id(self, args: Namespace, api: ApiClient) -> str:
if not (
resume_id := args.resume_id or args.config["default_resume_id"]
):
resumes: ApiListResponse = api.get("/resumes/mine")
resume_id = resumes["items"][0]["id"]
return resume_id

def _get_application_messages(self, args: Namespace) -> list[str]:
if args.message_list:
application_messages = list(
filter(None, map(str.strip, args.message_list))
Expand All @@ -88,51 +107,7 @@ def run(self, args: Namespace) -> None:
"Хочу присоединиться к вашей успешной команде лидеров рынка в качестве %(name)s",
"Мое резюме содержит все баззворды, указанные в вашей вакансии %(name)s",
]

apply_min_interval, apply_max_interval = args.apply_interval
page_min_interval, page_max_interval = args.page_interval

self._apply_similar(
api,
resume_id,
args.force_message,
application_messages,
apply_min_interval,
apply_max_interval,
page_min_interval,
page_max_interval,
)

def _get_vacancies(
self,
api: ApiClient,
resume_id: str,
page_min_interval: float,
page_max_interval: float,
) -> list[VacancyItem]:
rv = []
per_page = 100
for page in range(20):
res: ApiListResponse = api.get(
f"/resumes/{resume_id}/similar_vacancies",
page=page,
per_page=per_page,
order_by="relevance",
)
rv.extend(res["items"])

if getenv("TEST_TELEMETRY"):
break

if page >= res["pages"] - 1:
break

# Задержка перед получением следующей страницы
if page > 0:
interval = random.uniform(page_min_interval, page_max_interval)
time.sleep(interval)

return rv
return application_messages

def _apply_similar(
self,
Expand All @@ -145,42 +120,34 @@ def _apply_similar(
page_min_interval: float,
page_max_interval: float,
) -> None:
item: VacancyItem

# Телеметрия не включает ваши персональные данные, она нужна для сбора информации о работодателях и их вакансиях
telemetry_client = get_telemetry_client()
telemetry_data = defaultdict(dict)

for item in self._get_vacancies(
api, resume_id, page_min_interval, page_max_interval
):
vacancies = self._get_vacancies(
api, resume_id, page_min_interval, page_max_interval, per_page=100
)

self._collect_vacancy_telemetry(telemetry_data, vacancies)

for vacancy in vacancies:
try:
# Информация о вакансии
vacancy_id = item["id"]

telemetry_data["vacancies"][vacancy_id] = {
"name": item.get("name"),
"type": item.get("type", {}).get("id"), # open/closed
"area": item.get("area", {}).get("name"), # город
"salary": item.get("salary"), # from, to, currency, gross
"direct_url": item.get(
"alternate_url"
), # ссылка на вакансию
"created_at": fix_datetime(
item.get("created_at")
), # будем вычислять говно-вакансии, которые по полгода висят
"published_at": fix_datetime(item.get("published_at")),
"contacts": item.get(
"contacts"
), # пиздорванки там телеграм для связи указывают
# Остальное неинтересно
}
if getenv("TEST_TELEMETRY"):
break

if vacancy["has_test"]:
print("🚫 Пропускаем тест", vacancy["alternate_url"])
continue

employer_id = item["employer"][
"id"
] # меня интересуют только название и ссылка на сайт
relations = vacancy.get("relations", [])

if relations:
print(
"🚫 Пропускаем ответ на заявку",
vacancy["alternate_url"],
)
continue

# так еще эмулируем какое-то иное действие нежели набор однотипных
employer_id = vacancy["employer"]["id"]
employer = api.get(f"/employers/{employer_id}")

telemetry_data["employers"][employer_id] = {
Expand All @@ -190,29 +157,6 @@ def _apply_similar(
"site_url": employer.get("site_url"),
"area": employer.get("area", {}).get("name"), # город
}

if getenv("TEST_TELEMETRY"):
break

if item["has_test"]:
print("Пропускаем тест", item["alternate_url"])
continue

relations = item.get("relations", [])

# Там черезжопно нужно хеш отклика получать чтобы его отменить
# if "got_response" in relations:
# # Тупая пизда ее даже не рассматривала
# print(
# "Отменяем заявку чтобы отправить ее снова",
# item["alternate_url"],
# )
# api.delete(f"/negotiations/active/{item['id']}")
# elif relations:
if relations:
print("Пропускаем ответ на заявку", item["alternate_url"])
continue

# Задержка перед отправкой отклика
interval = random.uniform(
apply_min_interval, apply_max_interval
Expand All @@ -221,10 +165,10 @@ def _apply_similar(

params = {
"resume_id": resume_id,
"vacancy_id": item["id"],
"vacancy_id": vacancy["id"],
"message": (
random.choice(application_messages) % item
if force_message or item["response_letter_required"]
random.choice(application_messages) % vacancy
if force_message or vacancy["response_letter_required"]
else ""
),
}
Expand All @@ -233,9 +177,9 @@ def _apply_similar(
assert res == {}
print(
"📨 Отправили отклик",
item["alternate_url"],
vacancy["alternate_url"],
"(",
truncate_string(item["name"]),
truncate_string(vacancy["name"]),
")",
)
except ApiError as ex:
Expand All @@ -245,8 +189,68 @@ def _apply_similar(

print("📝 Отклики на вакансии разосланы!")

# Отправляем telemetry_data
self._send_telemetry(telemetry_client, telemetry_data)

def _get_vacancies(
self,
api: ApiClient,
resume_id: str,
page_min_interval: float,
page_max_interval: float,
per_page: int,
) -> list[VacancyItem]:
rv = []
for page in range(20):
res: ApiListResponse = api.get(
f"/resumes/{resume_id}/similar_vacancies",
page=page,
per_page=per_page,
order_by="relevance",
)
rv.extend(res["items"])

if getenv("TEST_TELEMETRY"):
break

if page >= res["pages"] - 1:
break

# Задержка перед получением следующей страницы
if page > 0:
interval = random.uniform(page_min_interval, page_max_interval)
time.sleep(interval)

return rv

def _collect_vacancy_telemetry(
self, telemetry_data: defaultdict, vacancies: list[VacancyItem]
) -> None:
for vacancy in vacancies:
vacancy_id = vacancy["id"]
telemetry_data["vacancies"][vacancy_id] = {
"name": vacancy.get("name"),
"type": vacancy.get("type", {}).get("id"), # open/closed
"area": vacancy.get("area", {}).get("name"), # город
"salary": vacancy.get("salary"), # from, to, currency, gross
"direct_url": vacancy.get(
"alternate_url"
), # ссылка на вакансию
"created_at": fix_datetime(
vacancy.get("created_at")
), # будем вычислять говно-вакансии, которые по полгода висят
"published_at": fix_datetime(vacancy.get("published_at")),
"contacts": vacancy.get(
"contacts"
), # пиздорванки там телеграм для связи указывают
"employer_id": int(vacancy["employer"]["id"]),
# Остальное неинтересно
}

def _send_telemetry(
self, telemetry_client, telemetry_data: defaultdict
) -> None:
try:
telemetry_client.send_telemetry("/collect", dict(telemetry_data))
except TelemetryError as err:
logger.error("Не могу отправить телеметрию")
res = telemetry_client.send_telemetry("/collect", dict(telemetry_data))
logger.debug(res)
except TelemetryError as ex:
logger.error(ex)
12 changes: 9 additions & 3 deletions hh_applicant_tool/telemetry_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ class TelemetryError(Exception):
class TelemetryClient:
"""Клиент для отправки телеметрии на сервер."""

server_address = base64.b64decode('aHR0cDovLzMxLjEzMS4yNTEuMTA3OjU0MTU2').decode()
server_address = base64.b64decode(
"aHR0cDovLzMxLjEzMS4yNTEuMTA3OjU0MTU2"
).decode()

def __init__(
self,
Expand Down Expand Up @@ -53,8 +55,12 @@ def send_telemetry(

try:
response = self.session.post(url, json=data)
response.raise_for_status()
return response.json()
# response.raise_for_status()
result = response.json()
if "error" in result:
raise TelemetryError(result)
return result

except (
requests.exceptions.RequestException,
json.JSONDecodeError,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "hh-applicant-tool"
version = "0.3.2"
version = "0.3.3"
description = ""
authors = ["Senior YAML Developer <[email protected]>"]
readme = "README.md"
Expand Down

0 comments on commit 63978ee

Please sign in to comment.