Многопользовательский режим: авторизация, изоляция данных, лимиты генераций, деплой без VNC

This commit is contained in:
apuc committed 2026-09-16 16:11:06 +03:00
1 parent 0ca55f3818
commit 03555a400f
10 files changed
+1195 -154

No files matched your search

+16 -6
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""Поиск вакансий на hh.ru через парсинг страницы поиска (без API)."""
import json
import os
import re
import time
import urllib.parse
@@ -16,6 +17,15 @@ HEADERS = {
SEARCH_URL = "https://hh.ru/search/vacancy"
def get_proxies():
"""Прокси из .env: PROXY_URL=http://LOGIN:PASS@HOST:PORT.
Возвращает dict для requests или None."""
url = os.environ.get("PROXY_URL", "")
if not url:
return None
return {"http": url, "https": url}
def _clean(text):
"""Убираем HTML-теги и лишние пробелы."""
text = re.sub(r"<[^>]+>", "", text)
@@ -117,7 +127,7 @@ def _is_latin1(s):
return False
def search_vacancies(query, area=None, pages=1, per_page=20, delay=2.0, cookies=None):
def search_vacancies(query, area=None, pages=1, per_page=20, delay=2.0, cookies=None, proxies=None):
"""Ищем вакансии по запросу. Возвращает список словарей."""
all_vacancies = []
seen = set()
@@ -126,7 +136,7 @@ def search_vacancies(query, area=None, pages=1, per_page=20, delay=2.0, cookies=
if area:
params["area"] = area
url = f"{SEARCH_URL}?{urllib.parse.urlencode(params)}"
resp = requests.get(url, headers=HEADERS, timeout=30, cookies=cookies)
resp = requests.get(url, headers=HEADERS, timeout=30, cookies=cookies, proxies=proxies)
if resp.status_code != 200:
print(f" [поиск] HTTP {resp.status_code} для страницы {page_num}")
break
@@ -144,10 +154,10 @@ def search_vacancies(query, area=None, pages=1, per_page=20, delay=2.0, cookies=
return all_vacancies
def fetch_vacancy_details(vacancy_id, cookies=None):
def fetch_vacancy_details(vacancy_id, cookies=None, proxies=None):
"""Получаем описание вакансии со страницы вакансии."""
url = f"https://hh.ru/vacancy/{vacancy_id}"
resp = requests.get(url, headers=HEADERS, timeout=30, cookies=cookies)
resp = requests.get(url, headers=HEADERS, timeout=30, cookies=cookies, proxies=proxies)
if resp.status_code != 200:
return None
html = resp.text
@@ -170,11 +180,11 @@ def fetch_vacancy_details(vacancy_id, cookies=None):
return details
def fetch_my_resumes(cookies=None):
def fetch_my_resumes(cookies=None, proxies=None):
"""Получает список резюме пользователя со страницы hh.ru/applicant/resumes.
Возвращает список {"id": hash, "title": ..., "updated": ...}."""
url = "https://hh.ru/applicant/resumes"
resp = requests.get(url, headers=HEADERS, timeout=30, cookies=cookies)
resp = requests.get(url, headers=HEADERS, timeout=30, cookies=cookies, proxies=proxies)
if resp.status_code != 200:
return None, f"HTTP {resp.status_code} — проверьте ключ сессии"
html = resp.text