3
0
Selaa lähdekoodia

Merge remote-tracking branch 'origin/2.0' into 2.0

chenjunhao 4 viikkoa sitten
vanhempi
sitoutus
41d4727ac1
4 muutettua tiedostoa jossa 175 lisäystä ja 1453 poistoa
  1. 73 1
      spiders/yaoex/yaoex_crawl.py
  2. 14 1440
      spiders/yaoex/yaoex_snapshot_crawl.py
  3. 44 6
      start_run_yaoex.py
  4. 44 6
      start_run_ybm.py

+ 73 - 1
spiders/yaoex/yaoex_crawl.py

@@ -19,6 +19,11 @@ PLATFORM_ID = 6
 YYC_DEVICE_ID = "18193030281"
 
 HEARTBEAT_INTERVAL_SECONDS = 60
+TASK_API_BASE = "http://192.168.2.246:8080/api/collect_task"
+TASK_API_TOKEN = "zhijiayun_crawler_2026"
+TASK_PULL_URL = TASK_API_BASE + "/pull"
+TASK_HEARTBEAT_URL = TASK_API_BASE + "/heartbeat"
+TASK_REPORT_URL = TASK_API_BASE + "/report"
 
 headers = {
     "Accept": "application/json, text/plain, */*",
@@ -61,6 +66,74 @@ class YaoexCrawler:
         self.is_success = True
         self.is_not_product = 0
 
+    # ---------- API report helpers ----------
+
+    def _send_report(self, params: dict, log_msg: str):
+        try:
+            resp = requests.post(
+                TASK_REPORT_URL, json=params, timeout=10,
+                headers={'X-Crawler-Token': TASK_API_TOKEN},
+            )
+            if resp.status_code == 200:
+                try:
+                    data = resp.json()
+                    if data.get("code") == "success":
+                        logger.info("回告成功:%s", log_msg)
+                        return "success"
+                    else:
+                        msg = data.get("msg", "")
+                        if "已达平台限额" in msg or "限额" in msg:
+                            logger.warning("回告接口返回限额错误:code=%s, msg=%s", data.get('code'), msg)
+                            return "limit_reached"
+                        else:
+                            logger.warning("回告接口返回错误:code=%s, msg=%s", data.get('code'), msg)
+                            return "error"
+                except ValueError:
+                    logger.warning("回告响应非 JSON:%s", resp.text[:200])
+                    return "error"
+            else:
+                logger.warning("回告 HTTP %s", resp.status_code)
+                return "error"
+        except Exception as e:
+            logger.error("回告失败:%s,错误:%s", log_msg, str(e))
+            return "error"
+
+    def _report_start(self):
+        payload = {
+            "task_id": self.task_id,
+            "platform": str(self.platform),
+            "username": YYC_DEVICE_ID,
+            "current_page": 0,
+            "total_pages": 0,
+            "is_finished": 0,
+        }
+        logger.info("上报开始 task_id=%s", self.task_id)
+        return self._send_report(payload, "开始上报(is_finished=0)")
+
+    def _report_progress(self, current_page: int, total_pages: int = 0):
+        payload = {
+            "task_id": self.task_id,
+            "platform": str(self.platform),
+            "username": YYC_DEVICE_ID,
+            "current_page": current_page,
+            "total_pages": total_pages,
+            "is_finished": 0,
+        }
+        return self._send_report(payload, f"进度上报 page={current_page}")
+
+    def _report_end(self, success: bool, real_count: int, page_no: int = 0, total_pages: int = 0):
+        payload = {
+            "task_id": self.task_id,
+            "platform": str(self.platform),
+            "username": YYC_DEVICE_ID,
+            "current_page": page_no,
+            "total_pages": total_pages if total_pages > 0 else page_no,
+            "crawled_count": real_count,
+            "is_finished": 1 if success else 0,
+        }
+        logger.info("上报结束 task_id=%s payload=%s", self.task_id, payload)
+        self._send_report(payload, "结束上报(is_finished=1)")
+
     def _post_with_retry(self, url, payload, retries=REQUEST_RETRY_COUNT, timeout=REQUEST_TIMEOUT_SEC):
         last_err = None
         for attempt in range(1, retries + 1):
@@ -98,7 +171,6 @@ class YaoexCrawler:
         self.collect_region_id = self.task_dict.get("collect_region_id", "")
         self.collect_round = self.task_dict.get("collect_round", 1)
 
-    @staticmethod
     def _timestamp_ms() -> str:
         return str(int(time.time() * 1000))
 

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 14 - 1440
spiders/yaoex/yaoex_snapshot_crawl.py


+ 44 - 6
start_run_yaoex.py

@@ -7,13 +7,17 @@ import re
 import time
 from datetime import datetime
 
+import requests
+
 from commons.Logger import get_spider_logger
-from commons.scheduler import CrawlerScheduler
 from commons.feishu_webhook import send_text, send_error_card
 from spiders.yaoex.yaoex_crawl import (
     YaoexCrawler,
     PLATFORM_ID,
     YYC_DEVICE_ID,
+    TASK_PULL_URL,
+    TASK_HEARTBEAT_URL,
+    TASK_API_TOKEN,
 )
 from spiders.yaoex.yaoex_snapshot_crawl import YaoexSnapshotCrawl
 
@@ -24,6 +28,42 @@ IDLE_SECONDS_MIN = 180
 IDLE_SECONDS_MAX = 300
 
 
+def pull_task():
+    """从内部调度 API 拉取任务"""
+    headers = {'X-Crawler-Token': TASK_API_TOKEN}
+    params = {'platform': PLATFORM_ID, 'username': YYC_DEVICE_ID}
+    try:
+        response = requests.get(TASK_PULL_URL, params=params, headers=headers, timeout=15)
+        result = response.json()
+        logger.info("拉取任务 API 返回: %s", result)
+        if result.get('code') == 'success':
+            task = result.get('data', {}).get('task') or {}
+            if task and task.get("id"):
+                logger.info("拉取任务成功 platform=%s task_id=%s", PLATFORM_ID, task.get("id"))
+                return task
+            else:
+                logger.info("拉取任务成功但无有效任务(task=%s),视为暂无任务", task)
+                return {}
+        else:
+            logger.warning("拉取任务 API 返回非 success: code=%s, msg=%s",
+                           result.get('code'), result.get('msg'))
+            return {}
+    except Exception as e:
+        logger.error("拉取任务 API 请求失败: %s", e)
+        return {}
+
+
+def send_heartbeat():
+    """向调度 API 上报心跳,告知服务器爬虫在线"""
+    headers = {'X-Crawler-Token': TASK_API_TOKEN}
+    payload = {"platform": str(PLATFORM_ID), "username": YYC_DEVICE_ID}
+    try:
+        resp = requests.post(TASK_HEARTBEAT_URL, json=payload, headers=headers, timeout=10)
+        logger.debug("心跳上报: HTTP %s, %s", resp.status_code, resp.text[:200])
+    except Exception as e:
+        logger.warning("心跳上报失败: %s", e)
+
+
 def notify_result(task, crawl_count, success):
     """发送飞书通知"""
     try:
@@ -50,16 +90,14 @@ def notify_result(task, crawl_count, success):
 
 def main_loop():
     """循环拉取任务并执行采集"""
-    scheduler = CrawlerScheduler(YYC_DEVICE_ID, str(PLATFORM_ID))
     idle_seconds = random.randint(IDLE_SECONDS_MIN, IDLE_SECONDS_MAX)
     logger.info("壹药城采集启动,每轮间隔 %s 秒", idle_seconds)
 
     while True:
         try:
-            # 先同步心跳,确保服务器登记后再拉任务
-            scheduler.heartbeat_once()
-            scheduler.start()
-            task = scheduler.get_task() or {}
+            # 先上报心跳,告诉服务器爬虫在线
+            send_heartbeat()
+            task = pull_task()
             if not task:
                 logger.info("%s 暂无任务,等待 %s 秒后重试", PLATFORM_NAME, idle_seconds)
                 time.sleep(idle_seconds)

+ 44 - 6
start_run_ybm.py

@@ -7,13 +7,17 @@ import time
 import re
 from datetime import datetime
 
+import requests
+
 from commons.Logger import get_spider_logger
-from commons.scheduler import CrawlerScheduler
 from commons.feishu_webhook import send_text, send_error_card
 from spiders.ybm.ybm_crawl import (
     YbmCrawler,
     PLATFORM_ID,
     YBM_DEVICE_ID,
+    TASK_PULL_URL,
+    TASK_HEARTBEAT_URL,
+    TASK_API_TOKEN,
     load_city_mapping,
 )
 
@@ -24,6 +28,42 @@ IDLE_SECONDS_MIN = 180
 IDLE_SECONDS_MAX = 300
 
 
+def pull_task():
+    """从内部调度 API 拉取任务"""
+    headers = {'X-Crawler-Token': TASK_API_TOKEN}
+    params = {'platform': PLATFORM_ID, 'username': YBM_DEVICE_ID}
+    try:
+        response = requests.get(TASK_PULL_URL, params=params, headers=headers, timeout=15)
+        result = response.json()
+        logger.info("拉取任务 API 返回: %s", result)
+        if result.get('code') == 'success':
+            task = result.get('data', {}).get('task') or {}
+            if task and task.get("id"):
+                logger.info("拉取任务成功 platform=%s task_id=%s", PLATFORM_ID, task.get("id"))
+                return task
+            else:
+                logger.info("拉取任务成功但无有效任务(task=%s),视为暂无任务", task)
+                return {}
+        else:
+            logger.warning("拉取任务 API 返回非 success: code=%s, msg=%s",
+                           result.get('code'), result.get('msg'))
+            return {}
+    except Exception as e:
+        logger.error("拉取任务 API 请求失败: %s", e)
+        return {}
+
+
+def send_heartbeat():
+    """向调度 API 上报心跳,告知服务器爬虫在线"""
+    headers = {'X-Crawler-Token': TASK_API_TOKEN}
+    payload = {"platform": str(PLATFORM_ID), "username": YBM_DEVICE_ID}
+    try:
+        resp = requests.post(TASK_HEARTBEAT_URL, json=payload, headers=headers, timeout=10)
+        logger.debug("心跳上报: HTTP %s, %s", resp.status_code, resp.text[:200])
+    except Exception as e:
+        logger.warning("心跳上报失败: %s", e)
+
+
 def notify_result(task, crawl_count, success):
     """发送飞书通知"""
     try:
@@ -51,16 +91,14 @@ def notify_result(task, crawl_count, success):
 def main_loop():
     """循环拉取任务并执行采集"""
     load_city_mapping()
-    scheduler = CrawlerScheduler(YBM_DEVICE_ID, str(PLATFORM_ID))
     idle_seconds = random.randint(IDLE_SECONDS_MIN, IDLE_SECONDS_MAX)
     logger.info("药帮忙采集启动,每轮间隔 %s 秒", idle_seconds)
 
     while True:
         try:
-            # 先同步心跳,确保服务器登记后再拉任务
-            scheduler.heartbeat_once()
-            scheduler.start()
-            task = scheduler.get_task() or {}
+            # 先上报心跳,告诉服务器爬虫在线
+            send_heartbeat()
+            task = pull_task()
             if not task:
                 logger.info("%s 暂无任务,等待 %s 秒后重试", PLATFORM_NAME, idle_seconds)
                 time.sleep(idle_seconds)

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä