前言
全民抢购茅台,导致中证白酒指数一路飙升… 跟着大牛喝汤的同时,我也参与了抢购,抢到就是赚到,年关将至,就算自己不喝送礼也是非常 nice 的。
各大平台基本都有抢购茅台的活动,作为互联网从业人员,大家都知道通过前端手动抢购太慢了,避开前端直接通过接口对服务器发起请求会大大增加抢购的效率。GitHub 上就有大佬开源的抢购项目,本着学习的态度,对代码仔细阅读和研究。学习过程中也发现了一些问题,并尝试进行完善。下文分享学习过程中遇到的问题,以及解决办法。
原理
首先来看下,实际用户抢购的步骤(某东为例):
登录某东商城客户端
进入商品详情页
预约商品
在指定时间进行抢购
程序的实现逻辑也是如此,通过代码的方式一步一步去实现它。
运行环境 Python 3.7.3
1. 登录某东商城客户端
访问 WEB 登录页面,爬取登录二维码保存
将图片弹出,用户手动扫码后去循环刷新登录状态,获取用户身份标识 token/cookies/ticket
2. 进入商品详情页
根据商品 ID,获取商品详情页面链接,预约链接
3. 预约商品
用户身份标识 + 预约链接,完成预约
4. 在指定时间进行抢购
通过电脑时间跟某东服务器时间进行比对,在开放抢购前 500 毫秒发起请求
为快速进行请求,同时开启 5 个线程去访问
为保证程序稳定,循环开启线程时设置时间间隔
准备
1. 程序运行依赖一些第三方库,需要提前安装(用的清华源,速度会快一点);
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/
2. 获取用户标识(必填参数);
进入某东商城 WEB 页面,选择一个可下单的商品
进入开发者模式
console
栏,输入_JdTdudfp
,然后在页面上点击下单将获取到的
eid
和fp
写入配置文件内
使用
直接运行 main.py
,根据提示选择就行,程序入口代码如下,非常简单。
jd_seckill = JdSeckill()
choice_function = input('请选择:')
if choice_function == '1': # 预约
jd_seckill.reserve()
elif choice_function == '2': # 抢购
jd_seckill.seckill_by_proc_pool()
else:
print('没有此功能')
sys.exit(1)
需要整个项目原代码后台回复「抢购」
改动
我在原项目的基础上又做了一些改动,其中部分问题已经有人提 issues
了,但是作者还没来得及改,有些是我根据自己的喜好修改的。
问题 1:
拿到代码后直接从根目录执行 main.py 文件时,报异常:FileNotFoundException
原因:读取配置文件时,没有使用绝对路径,使用 abspath 替换并拼接后,解决该问题
问题 2:
预约和抢购需要执行两次 main.py 文件,分别输入 1、2 完成对应操作
原因:这个其实作者设计如此,但是我的预期是执行文件后,直接帮我预约,预约完成后进行抢购,所以我把运行入口代码修改了,执行一次即可
问题 3:
预约逻辑问题,某东预约是每天 10 点 30 分以后即可预约,但是程序设计为必须到达抢购时间才可预约,也就是抢购前 500 毫秒
修改:当前时间大于 10 点 30,即可进行预约
问题 4:
抢购时间需要每次在配置文件内手动修改为当天,如果不修改会判断当前时间永远大于抢购时间,出现只要运行程序就发起抢购的问题
修改:增加当天时间自动获取,如果在 10 点前运行程序,则等待到达抢购时间;如果在 10 点 30 分后手动运行程序,则直接提示抢购时间已过,不再发起请求;针对两种情况区分了提示信息
问题 5:
原程序是没有自动终止的,比如抢购 2 分钟后,结果已经就如此了,往后再抢购意义不大,需要手动去终止程序
解决:增加了一个杀死进程的方法,需要配合定时任务使用
问题 6:
抢购过程中,多进程处理时,都增加了商品名称和用户名获取的逻辑
优化:取消掉该逻辑,因为抢购的商品就一个,所以程序运行前去获取一次就可以了
问题 7:
抢购过程中出现了一次「当前地区无货」的情况,无法从日志看出问题
解决:增加了这种情况下的逻辑判断和日志打印
问题 8:
日志格式过长,打开日志文件,当前屏看到的都是格式,需要左滑才能看到真正的日志
解决:修改日志 formatter 格式,精简信息
问题 9:
日志文件根据存储大小来进行判断是否备份,每天的抢购信息不好区分
优化:根据日期,每天一个日志文件,最多做 5 天备份,超出则删除最早一天的日志文件
问题 10:
作者使用了 serverChan 进行推送抢购结果到微信,该方法在多线程内,每抢购一次就发送一次消息,调用次数过于频繁,导致有时被服务拉黑(server酱对发送消息有限制,每人每天上限 500 条,相同内容 5 分钟内不能重复发送,不同内容 10 分钟内不能连续发送,每天调用接口超过1000次的用户将被系统自动拉黑)所以其实发送这么频繁,真正收不到几条消息
解决:修改发送消息逻辑,改为定时任务,获取到最终结果后,再发送消息,预约一条,抢购结果一条。由于微信上推送的内容是仅展示标题,作者是把标题写死了,所以需要点击「查看详情」才能查看结果,为了少点那一下,我就把结果直接改为标题,真的要查看详细信息了再去点击。
定时任务
该脚本配合定时任务,不再需要每天掐着点去抢购啦
# [Python] jd seckill maotai
55 09 * * * /usr/bin/python3 workspace/jd_seckill/main.py
# [Python] Stop Python Process
02 10 * * * /usr/bin/python3 workspace/jd_seckill/seckill_stop.py
# [Python] Send wechat message by serverChan
03 10 * * * /usr/bin/python3 workspace/jd_seckill/util.py
如果需要我修改后的代码,后台回复「加油」
其实脚本抢购是次要的,因为在某东各种风控的限制下,抢购速度并不是第一位的,重在参与,结果倒是无所谓了... 如果能从开源脚本中学到一点东西,那么才是真的赚呢。
感谢阅读。
end