scp_history.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. # -*- coding: utf-8 -*-
  2. # Author : Charley
  3. # Python : 3.12.10
  4. # Date : 2026/07/15
  5. """
  6. SCP Auctions (catalogs.scpauctions.com) 全量历史爬虫(一次性脚本)
  7. 逻辑(两阶段):
  8. 阶段一 列表:GET /auctions/past 翻页解析「全部」历史拍卖会 → 逐场入库 scp_auction,
  9. 再逐场翻页抓 lot 列表入库 scp_lot(state 默认 0)
  10. 阶段二 详情:扫库 scp_lot 中 state != 1 的记录 → 逐条进详情页抓
  11. 「标题 + 成交价 + 属性(Collection/Sport/Type/Athlete/Team) + 多图」写回
  12. 适用场景:初始化数据库时跑一次。后续每周增量由 scp_spider.py 负责。
  13. """
  14. import sys
  15. import random
  16. from curl_cffi import requests
  17. from loguru import logger
  18. from mysql_pool import MySQLConnectionPool
  19. from scp_core import (
  20. client_identifier_list,
  21. crawl_one_auction,
  22. get_auction_list,
  23. save_auction,
  24. update_details_for_pending,
  25. )
  26. logger.remove()
  27. logger.add("./logs/his_{time:YYYYMMDD}.log", encoding="utf-8", rotation="00:00",
  28. format="[{time:YYYY-MM-DD HH:mm:ss.SSS}] {level} {message}",
  29. level="DEBUG", retention="7 day")
  30. # —— 调试开关 ——
  31. # 只抓前 N 个拍卖会,None 表示全抓(生产);测试时设小一点,比如 1
  32. DEBUG_AUCTION_LIMIT = None
  33. def run_history(log, sql_pool):
  34. """全量抓取所有历史拍卖会及其 lot 列表(阶段一)。
  35. Args:
  36. log: logger 对象。
  37. sql_pool: MySQL 连接池;传 None 时不入库,仅翻页抓取并 print 样本。
  38. Returns:
  39. None: 结果直接入库,无返回值。
  40. """
  41. impersonate = random.choice(client_identifier_list)
  42. with requests.Session() as session:
  43. try:
  44. auctions = get_auction_list(log, session, impersonate, only_first_page=False)
  45. except Exception as e:
  46. log.error(f"获取拍卖会列表失败: {e}")
  47. return
  48. if DEBUG_AUCTION_LIMIT is not None:
  49. auctions = auctions[:DEBUG_AUCTION_LIMIT]
  50. log.warning(f"[DEBUG] 调试模式,仅抓前 {len(auctions)} 场拍卖会")
  51. for idx, auc in enumerate(auctions, 1):
  52. log.info(f"========== [{idx}/{len(auctions)}] 拍卖会 {auc['event_id']} ({auc['auction_name']}) ==========")
  53. try:
  54. save_auction(log, sql_pool, auc) # 先入库拍卖会本身
  55. lots = crawl_one_auction(log, sql_pool, session, impersonate, auc)
  56. if sql_pool is None:
  57. for row in lots[:2]:
  58. print(row)
  59. except Exception as e:
  60. log.error(f"拍卖会 {auc['event_id']} 抓取异常: {e}")
  61. continue
  62. def scp_history_main(log):
  63. """全量历史抓取入口。
  64. Args:
  65. log: logger 对象。
  66. Returns:
  67. None: 无返回值。
  68. """
  69. log.info(f"开始运行 {sys._getframe().f_code.co_name} 全量爬虫任务 ...")
  70. sql_pool = MySQLConnectionPool(log=log)
  71. if not sql_pool:
  72. log.error("MySQL数据库连接失败")
  73. raise Exception("MySQL数据库连接失败")
  74. try:
  75. # 阶段一:抓拍卖会 + lot 列表入库
  76. run_history(log, sql_pool)
  77. # 阶段二:扫库 state != 1 的 lot 补抓详情
  78. update_details_for_pending(log, sql_pool)
  79. except Exception as e:
  80. log.error(f"{sys._getframe().f_code.co_name} error: {e}")
  81. finally:
  82. log.info(f"爬虫程序 {sys._getframe().f_code.co_name} 运行结束")
  83. if __name__ == "__main__":
  84. scp_history_main(log=logger)