|
|
vor 1 Woche | |
|---|---|---|
| .. | ||
| README.md | vor 1 Woche | |
| YamlLoader.py | vor 1 Woche | |
| application.yml | vor 1 Woche | |
| mysql_pool.py | vor 1 Woche | |
| requirements.txt | vor 1 Woche | |
| scp_core.py | vor 1 Woche | |
| scp_history.py | vor 1 Woche | |
| scp_spider.py | vor 1 Woche | |
抓取 SCP Auctions(catalogs.scpauctions.com)历史拍卖会的已售/流拍拍品数据,含拍卖会信息、拍品列表与拍品详情。提供 历史全量 与 每周新增 两个任务。
curl_cffi(浏览器指纹)+ parsel| 层级 | 来源页 | 抓取字段 |
|---|---|---|
| 拍卖会 | /auctions/past |
标题、类型、状态、开始/结束时间、主页链接、图录链接、封面图、event_id(去重) |
| 拍品列表 | 图录页 catalog |
Lot 号、标题、详情链接、缩略图、出价数、成交状态、成交价、item_id(去重) |
| 拍品详情 | /online-auctions/... |
标题、成交价、成交状态、出价数、Collection、Sport、Type、Athlete、Team、多图 |
用户要求「优先从接口抓取」。经浏览器抓包确认:本站为 Bidsquare 纯 SSR 页面,数据全部内嵌在 HTML 中,无独立数据 API(XHR 仅为 GA/埋点)。因此采用
curl_cffi直接 GET 页面 +parsel解析,无 Cloudflare 挑战,响应 200 纯 HTML。
event_id(拍卖会卡片 data-event_id,如 21706,也出现在 URL 尾部)item_id(lot 卡片 data-item_id,如 9317607)/auctions/past?page=N,每页 24 场,翻到空页为止{catalog_url}?page=N&limit=120,limit 上限 120,翻到空页为止.item-attributes li(<label>键</label><span>值</span>)可能是 2~5 个,Athlete/Team 常缺失 → 先建 label→value 字典,再按需取值,缺失置 None。s1.img.bidsquare.com/item/s/... 与大图 /item/l/... 并存,统一替换成 /item/l/(large)后去重,逗号拼接入库。9 BidsSold for$90,000 / 24 BidsUnsold;详情页 .bidding-price 有金额为 sold,为空为 unsold。2026-07-15(scp_spider)/
├── application.yml # MySQL 配置(mysql_pool 从运行目录读取)
├── create_table.sql # 建表:scp_auction(场次)+ scp_lot(拍品)
├── scp_core.py # 公用模块:HTTP/代理、列表解析、分页抓取、详情解析、入库
├── scp_history.py # 任务一:历史全量(一次性)
├── scp_spider.py # 任务二:每周新增(周调度常驻)
└── logs/ # 运行日志(loguru 按天切分,保留 7 天)
scp_auction:一条 = 一场拍卖会,event_id 唯一索引。scp_lot:一条 = 一个拍品,item_id 唯一索引;字段分两阶段写入。两阶段设计:
scp_lot.state=0(含成交价/状态/出价,列表页即有)。state != 1 的 lot,逐条进详情页补 Collection/Sport/Type/Athlete/Team/多图,成功置 state=1,失败置 2。curl_cffi、parsel、loguru、tenacity、schedule,以及全局公共库 charley-utils(提供 mysql_pool)。create_table.sql(DDL 写操作,需人工确认执行)。application.yml 中的 MySQL 连接。# 任务一:历史全量(初始化数据库时跑一次)
python scp_history.py
# 任务二:每周新增(常驻,先立即跑一次,之后每周一 05:00)
python scp_spider.py
/auctions/past 首页 → 与库中 event_id 求差集 → 仅新增拍卖会才入库查询;随后补跑阶段二,兜底上一轮失败/中断的详情。代理集中在 scp_core.py 的 get_proxys()(带重试)。默认使用住宅代理(北美出口,与 SCP 面向的美区一致):
http_proxy = "http://账号:密码@proxy.123proxy.cn:36927"
# 若改用本地 VPN 客户端 HTTP 端口(如 Clash),改成:
# http_proxy = https_proxy = "http://127.0.0.1:7890"
切换本地 VPN 端口时,把 get_proxys() 内两行替换为对应地址即可,其余代码无需改动。
curl_cffi 随机浏览器指纹(impersonate)+ 通用请求头即可,未写死 UA(避免与 TLS 指纹矛盾)。tenacity 包裹重试;周调度主函数失败按小时重试。insert_many(ignore=True) 依赖唯一索引去重,重复跑不会产生脏数据。time.sleep。label 建字典按需取,避免按固定顺序取值错位。EDT/EST):解析时剥离时区名,保留东部墙钟时间入 datetime 字段,原文另存 *_raw 字段。utf8mb4 库无碍。state=2,而补抓查询 where state != 1 会把 state=2 每轮重新选中 → 该 404 永久循环、阻塞其他待抓 lot。修复:新增 LotNotFound 异常,_get_selector 遇 404/410/软404 直接抛出且 retry_if_not_exception_type 不重试;置终态 state=3;补抓查询改为 where state in (0, 2),跳过已成功(1)与永久不存在(3)。event_id/item_id 去重 + 首页差集增量,是 Bidsquare 系托管拍卖站的通用范式,换其他 Bidsquare 站点只需调整域名与少量选择器。