前言
全民搶購茅台,導致中證白酒指數一路飆升… 跟着大牛喝湯的同時,我也參與了搶購,搶到就是賺到,年關將至,就算自己不喝送禮也是非常 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