Инструмент для мониторинга вакансий с произвольных сайтов и трекинга откликов.
- Скрейпинг любых сайтов — без привязки к структуре URL или API
- Поддержка SPA-сайтов (React/Vue) через headless Chromium, остальные — через HTTP
- Per-URL выбор скрейпера через
browser_urlsв конфиге - Фильтрация по ключевым словам с учётом границ слов (
Goне зацепитMongoDB) - Автоматическое определение компании по домену вакансии
- Дедупликация по URL — повторные уведомления не приходят
- Трекер откликов с дедлайнами и статусами
Config.toml
└── urls + keywords + browser_urls + companies
│
├── browser_urls → BrowserScraper (headless Chromium)
└── остальные → UniversalScraper (HTTP)
│
▼
extract_jobs_from_html / JS
— ищет элементы с ключевыми словами
— находит ближайшую ссылку (без URL-паттернов)
— определяет компанию по домену
│
▼
SQLite seen_jobs (id, title, company, url)
│
▼
ConsoleNotifier + ApplicationTracker
Для SPA-сайтов нужен Chromium:
sudo pacman -S chromium # Arch Linux
sudo apt install chromium # Debian/UbuntuConfig.toml:
[scraping]
# список сайтов с вакансиями
urls = [
"https://careers.kaspersky.ru/stack/GO",
"https://career.avito.com/vacancies/?q=&action=filter",
]
# интервал автоматического скрейпинга
interval_minutes = 1440
# Время ежедневного запуска планировщика в формате HH:MM (по умолчанию 11:00)
schedule_time = "11:00"
timeout_secs = 10
# ключевые слова выборки
keywords = ["Go", "Golang"]
user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
# SPA-сайты — скрейпятся через headless Chromium
# Остальные URL из списка urls идут через обычный HTTP
browser_urls = [
"https://careers.kaspersky.ru/",
"https://internship.vk.company/",
]
# chrome_path = "/usr/bin/chromium" # если не находит автоматически
browser_wait_ms = 5000 # время ожидания JS-рендеринга (мс)
# Маппинг домен → название компании
[companies]
"careers.kaspersky.ru" = "Kaspersky"
"career.avito.com" = "Avito"
"internship.vk.company" = "VK"keywords — обязательное поле. Без него скрейпер не вернёт ни одной вакансии.
Если домен не указан в [companies] — название берётся автоматически из второго уровня домена (например Kaspersky из careers.kaspersky.ru).
cargo testtouch job_notifier.db # создать файл БД перед первым запуском
# Docker
docker compose up -d --build # сборка контейнераcargo build --release
cargo run -- run --run-once
# Docker:
docker compose exec job-notifier ./JobNotifier run --run-oncecargo run -- run
# Docker: планировщик запускается автоматически при docker compose up
docker compose up -d --buildcargo run -- run --stats # общая статистика
cargo run -- run --recent 20 # последние 20 найденных вакансий
# Docker:
docker compose exec job-notifier ./JobNotifier run --stats
docker compose exec job-notifier ./JobNotifier run --recent 20# Добавить отклик
cargo run -- add-application \
--company "Kaspersky" \
--position "Developer Go (Sandbox)" \
--job-url "https://careers.kaspersky.ru/vacancy/24936" \
--reply-days 14
# Docker:
docker compose exec job-notifier ./JobNotifier add-application \
--company "Kaspersky" \
--position "Developer Go (Sandbox)" \
--job-url "https://careers.kaspersky.ru/vacancy/24936" \
--reply-days 14
# Список откликов
cargo run -- list-applications
# Docker:
docker compose exec job-notifier ./JobNotifier list-applications
# Обновить статус
cargo run -- update-status --id <UUID> --status in-review
# Docker:
docker compose exec job-notifier ./JobNotifier update-status --id <UUID> --status in-review
# Удалить
cargo run -- delete-application --id <UUID>
# Docker:
docker compose exec job-notifier ./JobNotifier delete-application --id <UUID>Статусы: submitted, in-review, rejected, offer-received, withdrawn.
При запуске выводятся напоминания о заявках с дедлайном сегодня:
=== Deadline reminders ===
[!] Kaspersky — Developer Go (Sandbox) (deadline: 2026-04-02)
Вакансии хранятся в SQLite (job_notifier.db). Просмотр:
sqlite3 job_notifier.db "SELECT title, company, url FROM seen_jobs ORDER BY id DESC LIMIT 50;"
# Docker:
docker compose exec job-notifier sqlite3 job_notifier.db "SELECT title, company, url FROM seen_jobs ORDER BY id DESC LIMIT 50;"Очистить:
sqlite3 job_notifier.db "DELETE FROM seen_jobs;"
# Docker:
docker compose exec job-notifier sqlite3 job_notifier.db "DELETE FROM seen_jobs;"# Логи (Ctrl+C отсоединяет от вывода, контейнер продолжает работать)
docker compose logs -f
# Остановить
docker compose downConfig.toml монтируется из корня репозитория как read-only — отредактируй его перед запуском:
urls/browser_urls— список сайтовinterval_minutes— интервал прогонаkeywords— ключевые слова фильтрации
Chromium уже включён в образ, chrome_path в конфиге указывать не нужно.
Альтернатива Docker — запуск как пользовательский systemd-сервис (без root). Сервис стартует при входе пользователя и перезапускается при падении.
cargo build --releaseСкопируй бинарник в удобное место. Вариант — рядом с проектом:
# Либо оставь в target/release и укажи полный путь в service-файле
# Либо скопируй в ~/.local/bin (должен быть в PATH)
cp target/release/JobNotifier ~/.local/bin/JobNotifierОткрой job-notifier.service и укажи путь к директории проекта в WorkingDirectory — там должны лежать Config.toml и job_notifier.db:
mkdir -p ~/.config/systemd/user
cp job-notifier.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now job-notifiersystemctl --user status job-notifier # статус
systemctl --user stop job-notifier # остановить
systemctl --user restart job-notifier # перезапустить
systemctl --user disable job-notifier # убрать из автозапускаjournalctl --user -u job-notifier -f # следить в реальном времени
journalctl --user -u job-notifier -n 100 # последние 100 строк
journalctl --user -u job-notifier --since "1 hour ago"По умолчанию пользовательские сервисы останавливаются при выходе из системы. Чтобы сервис работал в фоне постоянно:
loginctl enable-linger $USER