gendesign/tradein-mvp/deploy/cron-scrape.sh
lekss361 02267d0306 feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in)
- FastAPI backend: PostGIS estimator + 3 scrapers (Avito/Cian/Yandex)
- Next.js 15 frontend: tradein.html mockup design, basePath=/trade-in
- WeasyPrint PDF (Брусника-style 4-page report)
- Address autocomplete с typo-tolerance + 6 EKB presets
- Изолированный docker stack gendesign-tradein (отдельная postgres БД)
- Caddy inline routes: gendsgn.ru/trade-in/* и /trade-in/api/v1/*
- Forgejo Actions: .forgejo/workflows/deploy-tradein.yml (shell-based GHCR login)
- Триггер только по paths: tradein-mvp/** (не пересекается с deploy.yml)
- Образы: ghcr.io/lekss361/gendesign-tradein-{backend,frontend}:latest

Первый запуск на сервере (вручную, один раз):
  - создать /opt/gendesign/tradein-mvp/.env.runtime (postgres pwd, contact email)
  - docker network create gendesign_shared (если нет)
  - docker compose -p gendesign-tradein up -d
  - docker compose -p gendesign exec caddy caddy reload
2026-05-21 00:25:39 +03:00

79 lines
2.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Периодический скрейп Yandex+Avito по 5 якорям ЕКБ.
# Запускается из cron. Логи в /var/log/tradein-scrape.log
#
# Usage: ./cron-scrape.sh [yandex|avito|all] [deep|fast]
#
# Примеры в crontab:
# # Yandex deep раз в 3 часа
# 0 */3 * * * /opt/tradein-mvp/deploy/cron-scrape.sh yandex deep
# # Avito быстро каждый час
# 30 * * * * /opt/tradein-mvp/deploy/cron-scrape.sh avito fast
set -euo pipefail
SOURCE="${1:-all}"
MODE="${2:-fast}"
API="${API:-http://127.0.0.1:8091}"
LOG="${LOG:-/var/log/tradein-scrape.log}"
log() {
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] $*" | tee -a "$LOG"
}
# 5 якорей по районам ЕКБ. lat lon name
# Для Yandex DATE_DESC возвращает одинаковую выдачу регардлесс — но Cian/Avito
# реально фильтруют по координатам, так что multi-anchor нужен для них.
ANCHORS=(
"56.8400 60.6050 Центр"
"56.7950 60.5300 ЮЗ"
"56.8970 60.6100 Уралмаш"
"56.7700 60.5500 Академический"
"56.8650 60.6200 Пионерский"
)
build_payload() {
local lat="$1" lon="$2" src="$3" mode="$4"
local sources_json
case "$src" in
yandex) sources_json='["yandex"]' ;;
avito) sources_json='["avito"]' ;;
cian) sources_json='["cian"]' ;;
all) sources_json='["avito","cian","yandex"]' ;;
*) sources_json='["avito","cian","yandex"]' ;;
esac
if [[ "$mode" == "deep" ]]; then
echo "{\"lat\":$lat,\"lon\":$lon,\"radius_m\":1500,\"sources\":$sources_json,\"multi_room_yandex\":true,\"deep_yandex\":true,\"multi_room_cian\":true}"
else
echo "{\"lat\":$lat,\"lon\":$lon,\"radius_m\":1500,\"sources\":$sources_json,\"multi_room_yandex\":true,\"multi_room_cian\":true}"
fi
}
log "=== cron-scrape start: source=$SOURCE mode=$MODE ==="
# Circuit breaker: если Avito IP-rate-limited (3 нуля подряд) — пропускаем оставшиеся.
zero_fetch_streak=0
for anchor in "${ANCHORS[@]}"; do
if [[ "$zero_fetch_streak" -ge 3 ]]; then
log "⚠ circuit-breaker tripped (3× zero-fetch in a row) — skipping remaining anchors"
break
fi
read -r lat lon name <<< "$anchor"
payload=$(build_payload "$lat" "$lon" "$SOURCE" "$MODE")
log "$name ($lat, $lon) payload=$payload"
resp=$(curl -s -X POST "$API/api/v1/admin/scrape" \
-H "Content-Type: application/json" \
-d "$payload" \
-m 300 || echo '{"error":"curl_timeout"}')
log "$name $resp"
# Парсим total_fetched — если 0, инкремент streak; иначе reset
fetched=$(echo "$resp" | grep -oE '"total_fetched":[0-9]+' | grep -oE '[0-9]+' || echo 0)
if [[ "${fetched:-0}" == "0" ]]; then
zero_fetch_streak=$((zero_fetch_streak + 1))
else
zero_fetch_streak=0
fi
sleep 5
done
log "=== cron-scrape done ==="