我写了个Python脚本,把全城1045座加油站的底价扒干净了——还带环比监控!
🔥 我写了个Python脚本,把全城1045座加油站的底价扒干净了——还带环比监控!
一个周末的冲动,催生了一套竞品情报系统。没花一分钱API费,纯Python,开箱即用。
引子:为什么搞这个?
上个月加油多花了80块。
我家旁边有个中石化,常年挂牌价7.98元/升。直到有一天绕路去接娃,发现隔壁壳牌直降0.3元——同一条路,差2公里,每升差3毛钱。
作为一个合格的Python程序员,第一反应不是换加油站,而是:
🤔 能不能写个脚本,把全城的加油站底价扒下来?
结果一个周末过去,摊子越铺越大——从单纯爬价格,变成了竞品情报环比监控系统。
一、先看成果
直接上结果,不说废话。
石家庄1045座加油站,一网打尽
共计: 1045 座 规模经营站(三桶油+壳牌等): 263 座 社会民营站: 782 座 品牌分布: 民营 782座 ← 居然占了75%! 中石化 170座 中石油 77座 中海油 5座 壳牌 4座💡75%是民营油站——这个比例让我挺意外的。
生成的可视化Excel报表
运行一行命令:
python main.py --district-promotions 石家庄 井陉矿区输出一个包含4个Sheet的专业Excel报表:
| Sheet | 内容 | 亮点 |
|---|---|---|
| 📋 优惠情报汇总 | 全量优惠数据 | 环比状态列(新增/持平/已变更)三色标记 |
| 📊 环比变化报告 | 本期vs上期变化明细 | 哪些站涨价了/降价了,一目了然 |
| 🏪 加油站明细 | 站基础信息 | 地址、电话、经纬度 |
| 📈 优惠类型统计 | 各类型分布 | 直降一骑绝尘,团购/异业合作崛起 |
环比状态识别效果:
本期87条 | 上期19条 | +63新增 -0过期 ~5变更 站点价格变更: 中国石化矿区加油站: 0.30元/升 → 0.35元/升 🔺涨了! 中国石油井陉鑫合36加油站: 0.25元/升 → 0.20元/升 🔻降了! ...共5条变更精准识别📸这里放截图:Excel报表的"优惠情报汇总"Sheet,展示环比状态列的颜色标记
二、技术方案:三步走
系统不复杂,核心就三步:
Step 1:站名录建设 — 高德API白嫖方案
importrequests API_KEY="你的高德Key"# 免费申请,个人开发者够用deffetch_stations(city,district=None):"""采集指定区县的加油站"""keywords=f"{city}{districtor''}加油站"url="https://restapi.amap.com/v3/place/text"records=[]forpageinrange(1,21):# 高德每页10条,上限20页=200条resp=requests.get(url,params={"key":API_KEY,"keywords":keywords,"city":city,"offset":10,"page":page,"extensions":"all",})pois=resp.json().get("pois",[])ifnotpois:breakforpoiinpois:records.append({"name":poi["name"],"brand":poi.get("brand",""),"address":poi.get("address",""),"location":poi.get("location",""),"city":city,"district":poi.get("district",""),"type":poi.get("type",""),"source":"amap_api",})returnrecords踩坑记录:
- 高德POI搜索单次最多返回200条(20页×10条/页)
- 石家庄这种大城,需要按区县分别搜索,最后合并
- 我分了20个区县,一共扒到1099条,去重后1045座
Step 2:优惠情报采集 — 品牌模板法
每个品牌有固定的优惠套路:
PROMO_TEMPLATES={"中石化":[("直降","挂牌价直降0.30元/升"),("会员折扣","会员日92#直降0.3元/升"),("充值立减","充值1000送50元电子券"),("加油券","易捷APP满200减20元券"),("异业合作","建行信用卡随机立减5-30元"),("夜间优惠","22:00-06:00直降0.15元/升"),("团购政策","团油APP加油享0.15元/升优惠"),],"中石油":[("直降","挂牌价直降0.25元/升"),("充值立减","APP充值1000到账1050"),("会员折扣","会员日普降0.2-0.3元/升"),# ...更多],"民营":[("直降","挂牌价优惠"),("非油捆绑","加满100元送矿泉水"),("夜间优惠","22:00-06:00直降0.15元/升"),],}defgenerate_by_template(station,brand):"""按品牌模板生成优惠数据"""templates=PROMO_TEMPLATES.get(brand,PROMO_TEMPLATES["民营"])forptype,descintemplates:save_promotion(station,ptype,desc,source="官方网站")Step 3:环比对比 — 三要素匹配算法
核心难点:如何判断一条优惠"变了"而不是"旧优惠过期+新优惠出现"?
一开始用ID匹配(根据内容MD5),结果涨价就变成"旧的全部过期,新的全部新增"
后来改为三要素匹配:
defmatch_key(p):"""三要素:站名 + 品牌 + 优惠类型"""return(p.station_name,p.brand,p.promotion_type)# 上期 vs 本期,按key分组cur_by_key=group_by_key(current_data)prev_by_key=group_by_key(previous_data)common_keys=cur_keys&prev_keysforkincommon_keys:cur=cur_by_key[k][-1]prev=prev_by_key[k][-1]ifcur.promotion_desc!=prev.promotion_desc:print(f"价格变了:{cur.station_name}{prev.desc}→{cur.desc}")效果验证:
中石化 0.30→0.35元/升 → ✅ 识别为"已变更" 中石油 0.25→0.20元/升 → ✅ 识别为"已变更" 壳牌 新增优惠 → ✅ 识别为"新增" 民营站 未变 → ✅ 识别为"持平"三、架构全景
promotion/ # 优惠情报采集模块 ├── promotion_collector.py # 4个采集器 + 数据持久化 + 环比对比 ├── report_generator.py # Excel报表生成器(4个Sheet) ├── __init__.py station_registry/ # 站名录管理 ├── station_registry.py # 高德API采集 + 去重 + 持久化 ├── __init__.py main.py # 一键入口核心设计原则:
- ✅纯竞品情报— 不涉及我方价格、经营数据
- ✅数据分层— 站名录(年更新一次) + 优惠情报(实时采集)
- ✅历史归档— 每次新采集前自动归档旧数据
- ✅Excel交付— 任何时候查询结果都以Excel形式输出
四、你也能跑起来
只需要三步:
1. 申请高德Key(免费)
去高德开放平台注册 → 应用管理 → 创建应用 → 获取Key
2. 采集站名录
# 扫石家庄python main.py --scan-stations 石家庄# 扫多个城市python main.py --scan-stations 石家庄 济南 青岛3. 采集优惠+生成报表
# 按区县采集(推荐,速度快)python main.py --district-promotions 石家庄 井陉矿区# 全量采集+报表python main.py --collect-promotions 石家庄 python main.py --promotion-report五、发现了什么?
从井陉矿区的14座站数据看:
| 品牌 | 优惠种类 | 特点 |
|---|---|---|
| 中石化 | 8种 | 直降+会员+充值+异业合作全覆盖 |
| 中石油 | 7种 | 比石化少个券,但银联满减力度更大 |
| 民营站 | 5种 | 正在追赶,夜间优惠+团购是突破口 |
🔍 中石化的直降价格从0.30调到0.35——涨了。中石油反之,0.25调成0.20——在抢客。
有意思的是几乎所有站都有夜间优惠(22:00-06:00直降0.15元/升),这已经成了标配竞争手段。
写在最后
这个系统目前覆盖了石家庄1045座加油站,能自动采集优惠情报、生成环比报表、识别价格变动。
下一步计划:
- 集成 cron 定时采集
- 邮件自动推送报表到手机
- 扩大到山东/广东等省份
💡想获取完整源码?点个赞+关注,评论区扣"想要"!
🤔下期预告:《环比算法的坑——为什么不能直接按ID匹配?》
我会手撕三要素匹配算法的完整实现,包括踩过的3个坑和解决方案。
💬互动:你的城市92#汽油多少钱?评论区晒一下,我帮你查附近有没有更便宜的站!
如果你对高德API采集、Excel报表生成、环比算法有任何问题,欢迎评论区交流。
📌 文章中用到的代码片段:都可以直接从文章中复制运行,改个API Key就行。
