閑來無事,打開大麥網發現現在大多數演唱票都需要手機端才能搶票,僅有很少一部分支持pc端用網頁去搶票,但正所謂:道高一尺,魔高一丈,解決這個反爬問題,我們可以采用Airtest連接仿真機來模擬手機端操作,這次教程我們就先著手去解決利用selenium解決少部分可以用pc端搶票的問題。如果針對手機端搶票的呼聲較高,后面我會出一篇關于Airtest搶票的blog。
前提聲明:
1、本教程僅用于學習和研究使用,不得用于商業行為。
2、請確保在合法合規的前提前下使用本代碼
3、本教程所涉及的操作均為正常模擬用戶操作,不涉及任何數據入侵或數據竊取。
一、引言?
在熱門演出和賽事門票一票難求的今天,利用自動化工具來提高搶票成功率成為很多人的需求,本文將詳細介紹如何使用chromedriver及selenium利用python來編寫一個簡單的大麥網自動搶票腳本。
二、準備工作
在開始之前,確保開發環境中安裝了我們所需要的庫:
chromedriver版本:?131.0.6778.87
chrome版本:131.0.6778.140
selenium:4.27.1(用于網頁自動化操作)
如果這些并未安裝,可以看我之前寫的blog,也可以在B站等平臺搜索資源進行學習。這里我們就不詳細說了。
三、代碼分析
1、所需頁面URL
首先我們需要定義大麥網首頁、登陸頁面以及我們想要搶的那張票的頁面URL。
damai_url = "https://www.damai.cn/“
login_url = ”https://passport.damai.cn/login?ru=https%3A%2F%2Fwww.damai.cn%2F“
target_url ="https://detail.damai.cn/item.htm?spm=a2oeg.home.card_0.ditem_3.591b23e11Li5yj&id=862317821501“
?我們主要采取面向對象的思想來編寫代碼,我們首先定義一個類對象,然后進行初始化加載。
class Concert:def __init__(self):self.status = 0 # 狀態,表示當前操作執行到哪一步self.login_method = 1 # 0:模擬登錄 1:使用cookie登錄self.driver = webdriver.Chrome()
然后執行登陸操作,我們需要判斷是否需要進行模擬登陸操作,如果需要模擬登錄就先打開登陸頁面:
"""登錄"""def login(self):# 如果為0,模擬登錄if self.login_method == 0:self.driver.get(login_url)elif self.login_method == 1:# 如果當前目錄下沒有這個cookie.pkl文件if not os.path.exists('cookie.pkl'):# 登陸一下記錄登錄信息self.set_cookies()else:self.driver.get(target_url)# 登陸一下 通過selenium傳入一些信息self.get_cookie()
我們來看定義的兩個函數:set_cookies()和get_cookie():
"""cookies:登陸網站的時候出現的,記錄用戶信息"""def set_cookies(self):self.driver.get(login_url)print("###請掃碼登陸###")time.sleep(10)print("###登陸成功###")pickle.dump(self.driver.get_cookies(), open('cookie.pkl','wb')) #獲取登陸的信息,并保存下來print("###cookie保存成功###")# 登陸成功后就跳轉到搶票頁面self.driver.get(target_url)# time.sleep(2)# 如果文件中已經有了cookie.pkl文件def get_cookie(self):cookies = pickle.load(open('cookie.pkl','rb'))for cookie in cookies:cookie_dict = {"domain":".damai.cn","name":cookie.get("name"),"value":cookie.get("value"),}self.driver.add_cookie(cookie_dict)print("###載入cookie成功###")
?打開瀏覽器,狀態此時改為1
def enter_concert(self):print("###打開瀏覽器,進入大麥網###")# 調用登錄self.login()self.driver.refresh()self.status = 1print("###登陸成功###")
購票具體邏輯地實現:如果我們還停留在我們要買的這張票的頁面,門票的信息可能是缺貨,這個時候需要我們不斷的刷新,因此我們可以寫一個while循環來實現它,直到點擊進入頁面:訂單確認頁為止。給不同的情況,賦予不同的狀態,并采用不同的邏輯去判斷,比如需要我們手動選座購買的邏輯代碼等等。然后就是進入訂單確認頁的具體邏輯執行,我們可以采取xpath的方式去定位元素。把具體的代碼封裝到方法中。
# 搶票并下單:首先判斷是否能夠購買,如果不能就一直刷新網頁,知道能夠購買為止def choose_ticket(self):if self.status == 1:print("="*30)print("###請選擇日期以及票價###")while self.driver.title.find("訂單確認頁") == -1: # driver.title.find尋找索引頁,如果找不到返回-1,找到返回索引頁# 下單按鈕button = self.driver.find_element(By.XPATH,'/html/body/div[2]/div/div[1]/div[1]/div/div[2]/div[3]/div[9]/div/div[3]/div[3]').textif button == "提交缺貨登記": # 這里也就是說不一定會是"不,立即購票"這幾個字,也有可能會是提交缺貨登記等self.driver.refresh()elif button == "不,立即購票":self.driver.find_element(By.XPATH,'/html/body/div[2]/div/div[1]/div[1]/div/div[2]/div[3]/div[9]/div/div[3]/div[3]').click()time.sleep(10)elif button == "不,選座購票":self.driver.find_element(By.XPATH,'/html/body/div[2]/div/div[1]/div[1]/div/div[2]/div[3]/div[9]/div/div[3]/div[3]').click()self.status = 2else:self.status = 3tittle = self.driver.titleif tittle == "選擇座位":print("###請選擇座位###")time.sleep(10)self.driver.find_element('//*[@id="root"]/div/div[4]/div[2]/button').click()elif tittle == "訂單確認頁":while True:print("###正在加載中###")self.order_check()break
其實這里如果不是企業級的項目,而是自用的話,可以直接通過selenium語句去寫觀影人等信息。
# self.driver.find_element(By.XPATH,'//*[@id="dmViewerBlock_DmViewerBlock"]/div/div/div[3]').click()# name = self.driver.find_element(By.XPATH,'//*[@id="addholder-model"]/div/div[1]/div/div[1]/input').clear().send_keys("your_name")# testify = self.driver.find_element(By.XPATH,'//*[@id="addholder-model"]/div/div[1]/div/div[5]/input').clear().send_keys("your_password")
# self.driver.find_element(By.XPATH,'//*[@id="addholder-model"]/div/div[1]/div/div[8]/div').click()
# time.sleep(2)
# self.driver.find_element(By.XPATH,'//*[@id="dmViewerBlock_DmViewerBlock"]/div[2]/div/div/div[2]/i').click()
我們來看order_check()這個方法的具體實現,其實就是勾選觀影人(通過selenium去定位接口)然后提交訂單即可。
def order_check(self):print("###開始確認訂單###")try:self.driver.find_element(By.XPATH, '//*[@id="dmViewerBlock_DmViewerBlock"]/div[2]/div/div/div[2]/i').click()except Exception as e:print("###購票人信息選擇失敗,請重新選擇元素###")print(e)time.sleep(0.5)shoujihao = self.driver.find_element(By.XPATH,'//*[@id="dmContactBlock_DmContactBlock"]/div[2]/div/div[2]/input').clear()time.sleep(2)self.driver.find_element(By.XPATH,'//*[@id="dmContactBlock_DmContactBlock"]/div[2]/div/div[2]/input').send_keys("your_iphone_number")time.sleep(2)self.driver.find_element(By.XPATH, '//*[@id="dmOrderSubmitBlock_DmOrderSubmitBlock"]/div[2]/div/div[2]/div[2]/div[2]').click()time.sleep(10)
以上就是實現大麥網自動搶票的全部代碼實現,其實邏輯來講并不復雜,主要就是selenium的一些應用,最重要的是我們需要學習當中的面向對象的思想以及邏輯的復現,這是我們需要我們掌握并且要攻克的難點。
四、代碼優化與注意事項
1、元素定位:要準確的使用xpath或者其他定位方式(如CSS選擇器)來定位頁面元素,因為大麥網也買你可能會更新,元素的xpath語法可能會改變,所以需要定期檢查和調整代碼。
2、等待時間:合理設置等待的時間,避免因為也頁面加載緩慢導致操作失敗,但也不能設置過長的時間影響搶票效率。可以使用selenium中的顯示等待和隱式等待來優化。
3、多線程:可以考慮使用多線程技術,同時監控多個場次或者多個門票的搶購情況,提高搶票成功的概率,但要注意大麥網的相關規則,避免被判定為異常操作。
五、全部代碼
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
import os
import pickle
# 自動登錄
# 大麥網首頁
damai_url = "https://www.damai.cn/"
# 登錄頁面網址
login_url = "https://passport.damai.cn/login?ru=https%3A%2F%2Fwww.damai.cn%2F"
# 要搶票的網址
target_url = "https://detail.damai.cn/item.htm?spm=a2oeg.home.card_0.ditem_3.591b23e11Li5yj&id=862317821501"class Concert:def __init__(self):self.status = 0 # 狀態,表示當前操作執行到哪一步self.login_method = 1 # 0:模擬登錄 1:使用cookie登錄self.driver = webdriver.Chrome()"""cookies:登陸網站的時候出現的,記錄用戶信息"""def set_cookies(self):self.driver.get(login_url)print("###請掃碼登陸###")time.sleep(10)print("###登陸成功###")pickle.dump(self.driver.get_cookies(), open('cookie.pkl','wb')) #獲取登陸的信息,并保存下來print("###cookie保存成功###")# 登陸成功后就跳轉到搶票頁面self.driver.get(target_url)# self.zhanghao = self.driver.find_element(By.XPATH, '//*[@id="fm-login-id"]').send_keys("17719114890")# self.mima = self.driver.find_element(By.XPATH, '//*[@id="fm-login-password"]').send_keys("dwq0219423")# self.button = self.driver.find_element(By.XPATH, '//*[@id="fm-login-submit"]').click()# time.sleep(2)# 如果文件中已經有了cookie.pkl文件def get_cookie(self):cookies = pickle.load(open('cookie.pkl','rb'))for cookie in cookies:cookie_dict = {"domain":".damai.cn","name":cookie.get("name"),"value":cookie.get("value"),}self.driver.add_cookie(cookie_dict)time.sleep(10) # 在這里記得手動刷新一下,用戶信息才會顯示出來print("###載入cookie成功###")"""登錄"""def login(self):# 如果為0,模擬登錄if self.login_method == 0:self.driver.get(login_url)elif self.login_method == 1:# 如果當前目錄下沒有這個cookie.pkl文件if not os.path.exists('cookie.pkl'):# 登陸一下記錄登錄信息self.set_cookies()else:self.driver.get(target_url)# 登陸一下 通過selenium傳入一些信息self.get_cookie()"""打開瀏覽器"""def enter_concert(self):print("###打開瀏覽器,進入大麥網###")# 調用登錄self.login()self.driver.refresh()self.status = 1print("###登陸成功###")# 搶票并下單:首先判斷是否能夠購買,如果不能就一直刷新網頁,知道能夠購買為止def choose_ticket(self):if self.status == 1:print("="*30)print("###請選擇日期以及票價###")while self.driver.title.find("訂單確認頁") == -1: # driver.title.find尋找索引頁,如果找不到返回-1,找到返回索引頁# 下單按鈕button = self.driver.find_element(By.XPATH,'/html/body/div[2]/div/div[1]/div[1]/div/div[2]/div[3]/div[9]/div/div[3]/div[3]').textif button == "提交缺貨登記": # 這里也就是說不一定會是"不,立即購票"這幾個字,也有可能會是提交缺貨登記等self.driver.refresh()elif button == "不,立即購票":self.driver.find_element(By.XPATH,'/html/body/div[2]/div/div[1]/div[1]/div/div[2]/div[3]/div[9]/div/div[3]/div[3]').click()time.sleep(10)elif button == "不,選座購票":self.driver.find_element(By.XPATH,'/html/body/div[2]/div/div[1]/div[1]/div/div[2]/div[3]/div[9]/div/div[3]/div[3]').click()self.status = 2else:self.status = 3tittle = self.driver.titleif tittle == "選擇座位":print("###請選擇座位###")time.sleep(10)self.driver.find_element('//*[@id="root"]/div/div[4]/div[2]/button').click()elif tittle == "訂單確認頁":while True:print("###正在加載中###")self.order_check()break# 實現下單的邏輯# self.driver.find_element(By.XPATH,'//*[@id="dmViewerBlock_DmViewerBlock"]/div/div/div[3]').click()# name = self.driver.find_element(By.XPATH,'//*[@id="addholder-model"]/div/div[1]/div/div[1]/input').clear().send_keys("your_name")# testify = self.driver.find_element(By.XPATH,'//*[@id="addholder-model"]/div/div[1]/div/div[5]/input').clear().send_keys("your_password")# self.driver.find_element(By.XPATH,'//*[@id="addholder-model"]/div/div[1]/div/div[8]/div').click()# time.sleep(2)# self.driver.find_element(By.XPATH,'//*[@id="dmViewerBlock_DmViewerBlock"]/div[2]/div/div/div[2]/i').click()def order_check(self):print("###開始確認訂單###")try:self.driver.find_element(By.XPATH, '//*[@id="dmViewerBlock_DmViewerBlock"]/div[2]/div/div/div[2]/i').click()except Exception as e:print("###購票人信息選擇失敗,請重新選擇元素###")print(e)time.sleep(0.5)shoujihao = self.driver.find_element(By.XPATH,'//*[@id="dmContactBlock_DmContactBlock"]/div[2]/div/div[2]/input').clear()time.sleep(2)self.driver.find_element(By.XPATH,'//*[@id="dmContactBlock_DmContactBlock"]/div[2]/div/div[2]/input').send_keys("your_iphone_number")time.sleep(2)self.driver.find_element(By.XPATH, '//*[@id="dmOrderSubmitBlock_DmOrderSubmitBlock"]/div[2]/div/div[2]/div[2]/div[2]').click()time.sleep(10)if __name__ == '__main__':concert = Concert()concert.enter_concert()concert.choose_ticket()
六、總結
通過使用chromedriver和selenium庫,我們可以編寫一個簡單的大麥網自動搶票腳本。但要注意,自動搶票可能存在違反平臺規則以及法律風險等情況,在使用時需要謹慎并確保自己的行為合法合規。同時,也希望票務平臺能夠不斷優化售票機制,讓更多真正有需求的用戶能夠公平的購買到門票。
?