追踪Costco汽油价格

Hacker News Top 工具

摘要

作者开发了一个仪表板,通过抓取API数据并映射趋势,在全球燃油危机期间追踪和可视化美国各地的Costco汽油价格。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/08/25 19:59

# 全球燃油危机期间追踪Costco汽油价格 来源:https://www.jack.bio/blog/costco-gas-tracking 所有发布的观点和内容均为个人观点,不代表任何现任或前任雇主的立场。本站为个人维护的技术分享平台,技术内容仅供教育交流用途。 Costco实时汽油价格看板 **摘要:** 在霍尔木兹海峡燃料危机期间,我追踪了600个Costco加油站的汽油价格波动,并绘制了价格变化地图。 查看实时看板(https://www.jack.bio/costcogas) 四月时,我恰好住在两个Costco仓库之间。多年来每次需要加油时,我都会在心里进行同样的计算:这两个仓库哪个本周实际更优惠。 遗憾的是,Costco从未集中公布汽油价格。官方网站将价格分散在各个仓库页面中,而我附近两个仓库的标价往往不同。众所周知,Costco的汽油业务属于引流亏本商品,通常比周边加油站便宜15至20美分。这个差价通常足以让绕路加油值得考虑,但不足以让我在两个仓库间做出明确选择。 随着那个春天油价攀升,作为坦帕市的通勤者——这座几乎没有公共交通的扩张型城市——我对加油地点变得愈发敏感。我开始特别好奇Costco的定价策略:他们的油价是否与其他加油站同步上涨?如果油价持续攀升,Costco还能继续将汽油作为引流商品吗? 当时缺乏可靠的历史趋势观察工具。因此,我自然而然地决定构建一个追踪系统。 ## 大规模采集汽油数据 遗憾的是,数据采集可能是整个项目中最简单的环节。虽然我很想分享类似华夫饼屋故事(https://www.jack.bio/blog/wafflehouse)那样的酷炫逆向工程方法,但Costco在数据采集方面几乎没有设置障碍。 初步挖掘Costco网站时,我发现了`AjaxGetGasPricesService`这个端点。它接受以`ID1_ID2_ID3_ID4`格式输入的仓库ID——用下划线作为数组分隔符是个有趣的设计!这个端点很有用,但并非完全符合需求:我还需要每个仓库的位置数据,以便进行地图标注并计算实际驾车距离。 进一步挖掘后,我找到了完全符合需求的接口:`AjaxWarehouseBrowseLookupView`。正如其名,该函数通过输入经纬度参数检索仓库信息。更妙的是,`populateWarehouseDetails`参数能在响应中包含几乎所有Costco相关信息:地址、营业时间、服务项目、美食广场可用性(!),以及最重要的汽油价格。 ``` GET /AjaxWarehouseBrowseLookupView ?latitude=27.95 &longitude=-82.45 &hasGas=true &populateWarehouseDetails=true &countryCode=US ``` `populateWarehouseDetails`唯一的缺点是返回的响应体数据量*极其庞大*。虽然我很想一次性获取全美所有Costco数据,但该API每次请求最多返回50个仓库,且按距离排序。为了实现全国覆盖,我需要对地图进行系统性扫描。 ### 全国价格扫描策略 实施方案相当简单:在全国范围内布置坐标网格,逐点扫描,并对返回的仓库ID进行去重。考虑到约600个Costco网点,每个响应返回50个,使用3度间隔的网格覆盖美国本土,再加上阿拉斯加和夏威夷的几个手动选取点,重叠范围已足够捕获所有仓库。 ```python def grid_points(step: int = 3) -> list[tuple[float, float]]: points = [] for lat in range(25, 50, step): for lng in range(-125, -65, step): points.append((float(lat), float(lng))) points.extend([ (61.2, -149.9), # 安克雷奇 (64.8, -147.7), # 费尔班克斯 (21.3, -157.8), # 檀香山 (20.9, -156.5), # 卡胡鲁伊 ]) return points ``` 我限制了并发请求数量以避免冲击服务器,并为极少数失败请求添加了自动重试机制。 ```python async def fetch_all_costcos() -> list[CostcoStation]: points = grid_points() seen: dict[int, CostcoStation] = {} semaphore = asyncio.Semaphore(CONCURRENCY) async with httpx.AsyncClient(headers=HEADERS, timeout=30) as client: tasks = [fetch_point(client, lat, lng, semaphore, ts) for lat, lng in points] results = await asyncio.gather(*tasks) for result in results: for station in result: seen.setdefault(station.id, station) return list(seen.values()) ``` 整个扫描过程耗时不到60秒,一次性获取了全美所有Costco加油站的当前价格、地址和坐标! ## 数据存储方案 扫描系统运行成功后,需要确定数据存储位置。由于项目核心是追踪价格随时间的变化,这本质上是时间序列问题:相同约600个仓库被持续反复采样,且需保留所有历史记录以便回溯分析每个网点的变化趋势。 幸运的是,TimescaleDB是理想的解决方案。作为PostgreSQL的扩展,它既保留了我熟悉的查询语言和工具链,又叠加了时间序列特性。更重要的是它免费且易于部署(感谢TigerData!),这对个人技术项目而言正是我们需要的基础设施特性。 数据存储解决后,需要构建展示界面。没有采用复杂方案:基于Next.js快速构建应用,使用Tailwind CSS美化界面避免电子表格观感,经历与Cloudflare Workers部署斗争的些许挫败午后,最终形成了可搜索的Costco汽油价格实时数据库。 但独自享用成果毫无趣味。当系统初具雏形时,我为每个追踪的加油站创建独立页面,并允许搜索引擎收录所有页面。这样下次有人站在Costco停车场犹豫该去哪个仓库时,就无需像我当初那样逆向工程API,直接搜索即可获取信息。 ## 最终分析:油价真的在下降吗? 项目启动于霍尔木兹海峡危机引发石油市场动荡不久。这个狭窄的咽喉要道对全球油轮运输至关重要,仅是关闭威胁就足以引发油价飙升。 当然,我需要这些数据满足个人需求,但内心总有个声音驱使我去探寻超越个人钱包的答案。 在持续追踪的155天中(实时数据!),Costco共执行了38,101次独立价格调整,日均246次变动,覆盖约600个仓库。总体来看,降价(Cuts)更胜一筹:20,535次降价对比17,566次涨价,降价比涨价多约2,969次。 **每日价格变动** 涨价次数 vs 降价次数 点击或拖动探索数据 **关键事件标注** 2026年6月17日:美伊协议签署 2026年7月2日:协议破裂 2026年7月23日:油轮再遭袭击 2026年8月13日:胡塞武装袭击油轮 那么,我究竟得出了什么结论?即便是实力雄厚的Costco也无法完全摆脱霍尔木兹海峡局势的影响。这个将汽油业务视为“四舍五入误差”的企业,最终仍需顺应市场波动……只是时间问题而已。 我以理性的方式回应了这个发现——在花费数月完善这套每箱油节省几美分的系统后,我将本田CR-V换成了特斯拉Model Y,现在每月支付的车贷比追逐两个仓库间15美分差价所能节省的总额还要多。当我终于拥有回答“该去哪个Costco”的技术架构时,我却让这个提问对我个人而言永久失去了意义。 如果觉得车牌眼熟(或不熟),建议阅读我的[另一篇文章](https://www.jack.bio/blog/licenseplate),了解如何获得佛罗里达州最优雅的双字母车牌组合。 *特别感谢Kai (https://x.com/mcmgoodall)、Neesh (https://x.com/Neesh774)、Ari (https://x.com/aridutilh)、Landon、Mark和Jaden的校对工作,以及Creamcheese Babgel团队的其他成员。 <3* *——戴着车牌的阿尔宙斯*

相似文章

koala73/worldmonitor

GitHub Trending (daily)

# koala73/worldmonitor 来源: [https://github.com/koala73/worldmonitor](https://github.com/koala73/worldmonitor) # World Monitor **实时全球情报仪表板** — AI驱动的新闻聚合、地缘政治监测和基础设施追踪,统一于一个态势感知界面。 [![GitHub stars](https://img.shields.io/github/stars/koala73/worldmonitor?style=social)](https://github.com/koala73/worldmonitor/stargazers) [![GitHub forks](https://img.shields.io/github/forks/ko