start_run_yaojiujiu.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. """药九九统一入口 — 根据任务 snapshot_collect_status 字段自动切换普通/快照模式。
  2. 对接 CrawlerScheduler API(拉取任务/心跳/进度上报),
  3. snapshot_collect_status=0 → 快照模式(Playwright截图),非0 → 普通API模式。
  4. """
  5. import random
  6. import time
  7. import json
  8. from spiders.yaojiujiu.yyjzt_crawl import YyjztSpider
  9. from spiders.yaojiujiu.yyjzt_snapshot import YyjztSnapshotSpider
  10. from commons.scheduler import CrawlerScheduler
  11. from commons.conn_mysql import MySQLPoolOn2
  12. from commons.Logger import logger
  13. PLATFORM_NAME = "药九九"
  14. PLATFORM_ID = 7
  15. def get_device_config():
  16. """从 accounts_platform 获取药九九账号(platform=7, status=1)。"""
  17. db = MySQLPoolOn2()
  18. sql = """SELECT `name`, `phone`, `password` FROM `accounts_platform`
  19. WHERE `platform`=7 AND `status`=1
  20. ORDER BY `cookie_timestamp` ASC LIMIT 1"""
  21. rows = db.select_data(sql)
  22. if not rows:
  23. logger.error("无可用药九九账号(platform=7, status=1)")
  24. return None
  25. account = rows[0]
  26. logger.info("获取到药九九账号: name=%s, phone=%s", account["name"], account["phone"])
  27. return account["phone"], account["password"], account["name"]
  28. def _build_task_dict(api_task, device_id, account_password, account_name, scheduler):
  29. """组装 spider 需要的 task_dict。"""
  30. current_page = api_task.get("current_page", 0)
  31. task_dict = {
  32. "id": api_task.get("id"),
  33. "company_id": api_task.get("company_id"),
  34. "product_name": api_task.get("product_name", ""),
  35. "product_specs": api_task.get("product_specs", ""),
  36. "product_brand": api_task.get("product_brand", ""),
  37. "product_keyword": api_task.get("product_keyword", ""),
  38. "current_page": current_page,
  39. "start_page": current_page if current_page > 0 else 1,
  40. "end_page": 0,
  41. "scheduler": scheduler,
  42. "_device_id": device_id,
  43. "_platform": str(PLATFORM_ID),
  44. "collect_task_id": str(api_task.get("id", "")),
  45. "snapshot_collect_status": api_task.get("snapshot_collect_status"),
  46. "sampling_cycle": "",
  47. "sampling_start_time": "",
  48. "sampling_end_time": "",
  49. "collect_equipment_account_id": "",
  50. "collect_region_id": "",
  51. "collect_equipment_id": "",
  52. "collect_round": 1,
  53. # 登录账号信息(spider 内检查登录状态用)
  54. "account_phone": device_id,
  55. "account_password": account_password,
  56. "account_name": account_name,
  57. }
  58. return task_dict
  59. def _report_progress(scheduler, task_id, is_finished, crawled_count=0,
  60. current_page=0, total_pages=0,
  61. exception_type=None, remark=None):
  62. data = {
  63. "task_id": task_id,
  64. "platform": str(PLATFORM_ID),
  65. "username": scheduler.username,
  66. "current_page": current_page,
  67. "is_finished": is_finished,
  68. "total_pages": total_pages,
  69. }
  70. data["crawled_count"] = crawled_count
  71. if exception_type is not None:
  72. data["exception_type"] = exception_type
  73. if remark:
  74. data["remark"] = remark
  75. try:
  76. scheduler.post_report(data)
  77. logger.info("任务上报成功: is_finished=%s, crawled_count=%s", is_finished, crawled_count)
  78. except Exception as e:
  79. logger.warning("任务上报失败: %s", e)
  80. def run_one_task(scheduler, device_id, account_password, account_name):
  81. """拉取一个任务,根据 snapshot_collect_status 选 spider 执行并上报。"""
  82. api_task = scheduler.get_task()
  83. if not api_task:
  84. logger.info("%s 暂无任务", PLATFORM_NAME)
  85. return
  86. task_id = api_task.get("id", "")
  87. task_dict = _build_task_dict(api_task, device_id, account_password,
  88. account_name, scheduler)
  89. log_dict = {k: v for k, v in task_dict.items() if k != "scheduler"}
  90. logger.info("拉取到任务: %s", json.dumps(log_dict, ensure_ascii=False))
  91. # 根据 snapshot_collect_status 决定走普通爬虫还是快照爬虫
  92. snapshot_status = task_dict.get("snapshot_collect_status", 0)
  93. if not snapshot_status:
  94. spider_cls = YyjztSnapshotSpider
  95. logger.info("任务 %s 启用快照模式", task_id)
  96. else:
  97. spider_cls = YyjztSpider
  98. logger.info("任务 %s 使用普通模式", task_id)
  99. try:
  100. result = spider_cls(task_dict).run()
  101. except Exception as e:
  102. logger.exception("任务 %s 执行异常: %s", task_id, e)
  103. _report_progress(scheduler, task_id, is_finished=0,
  104. crawled_count=0,
  105. exception_type=5, remark=str(e)[:200])
  106. return
  107. if len(result) == 3:
  108. crawl_count, is_success, total_pages = result
  109. else:
  110. crawl_count, is_success = result
  111. total_pages = 0
  112. if is_success:
  113. _report_progress(scheduler, task_id, is_finished=1,
  114. crawled_count=crawl_count,
  115. current_page=total_pages, total_pages=total_pages)
  116. else:
  117. _report_progress(scheduler, task_id, is_finished=0,
  118. crawled_count=crawl_count,
  119. current_page=total_pages, total_pages=total_pages)
  120. if __name__ == "__main__":
  121. # 1. 获取账号
  122. result = get_device_config()
  123. if result:
  124. device_id, account_password, account_name = result
  125. else:
  126. device_id, account_password, account_name = "YYJZT", None, None
  127. # 2. 启动调度器
  128. scheduler = CrawlerScheduler(DEVICE_ID=device_id, platform=str(PLATFORM_ID))
  129. scheduler.start()
  130. time.sleep(2)
  131. logger.info("药九九调度器已启动, device_id=%s", device_id)
  132. # 3. 循环执行
  133. idle_seconds = random.randint(180, 300)
  134. logger.info("药九九循环任务已启动, 间隔 %s 秒", idle_seconds)
  135. while True:
  136. try:
  137. logger.info("开始执行药九九爬虫")
  138. run_one_task(scheduler, device_id, account_password, account_name)
  139. logger.info("药九九爬虫执行完成")
  140. except Exception as e:
  141. logger.error("药九九爬虫执行失败: %s", e, exc_info=True)
  142. time.sleep(idle_seconds)