from __future__ import annotations import os import threading import time import schedule from app.config import load_config, setup_logging from app.crawlers.barrons import BarronsCrawler from app.crawlers.openinsider import OpenInsiderCrawler from app.api.server import create_app def start(): # Load configuration and setup logging config = load_config() logger = setup_logging(config.log_level, config.log_dir) # Select crawler via env var crawler_type = (os.getenv('CRAWLER_TYPE') or 'barrons').lower() crawlers = [] if crawler_type in ('openinsider', 'open_insider'): symbols_raw = os.getenv('SYMBOLS') or os.getenv('SYMBOL', 'PLTR') symbols = [s.strip().upper() for s in symbols_raw.split(',') if s.strip()] logger.info(f"使用 OpenInsider 內部人交易爬蟲,symbols={symbols}") for sym in symbols: crawlers.append(OpenInsiderCrawler(config, logger, symbol=sym)) else: logger.info("使用 Barron's 股票推薦爬蟲") crawlers.append(BarronsCrawler(config, logger)) # Create and start API in background app = create_app(crawlers if len(crawlers) > 1 else crawlers[0]) def run_api(): app.run(host='0.0.0.0', port=8080, debug=False) flask_thread = threading.Thread(target=run_api, daemon=True) flask_thread.start() # Schedule checks for each crawler and run loop (blocking) if getattr(config, 'run_daily_at', None): for c in crawlers: schedule.every().day.at(config.run_daily_at).do(c.run_check) logger.info(f"🚀 多爬蟲已啟動,每天 {config.run_daily_at} 檢查一次:{[getattr(c, 'symbol', c.name) for c in crawlers]}") else: for c in crawlers: schedule.every(config.check_interval).seconds.do(c.run_check) logger.info(f"🚀 多爬蟲已啟動,每 {config.check_interval} 秒檢查一次:{[getattr(c, 'symbol', c.name) for c in crawlers]}") # Initial run for each for c in crawlers: c.run_check() # Mark first check done to respect ALWAYS_NOTIFY_ON_STARTUP logic afterwards try: c._first_check_done = True except Exception: pass # Main loop try: while True: schedule.run_pending() time.sleep(1) except KeyboardInterrupt: logger.info("收到停止信號,正在關閉…")