基于selenium实现大麦网自动抢票脚本教程_大麦自动抢票脚本
闲来无事,打开大麦网发现现在大多数演唱票都需要手机端才能抢票,仅有很少一部分支持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 = 1 print(\"###登陆成功###\")
购票具体逻辑地实现:如果我们还停留在我们要买的这张票的页面,门票的信息可能是缺货,这个时候需要我们不断的刷新,因此我们可以写一个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]\').text if 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 = 2 else: self.status = 3 tittle = self.driver.title if 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 webdriverfrom selenium.webdriver.common.by import Byimport timeimport osimport 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 = 1 print(\"###登陆成功###\") # 抢票并下单:首先判断是否能够购买,如果不能就一直刷新网页,知道能够购买为止 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]\').text if 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 = 2 else: self.status = 3 tittle = self.driver.title if 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库,我们可以编写一个简单的大麦网自动抢票脚本。但要注意,自动抢票可能存在违反平台规则以及法律风险等情况,在使用时需要谨慎并确保自己的行为合法合规。同时,也希望票务平台能够不断优化售票机制,让更多真正有需求的用户能够公平的购买到门票。