从零开始学写脚本(大麦网抢票 上)第二天

Posted 程序工厂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始学写脚本(大麦网抢票 上)第二天相关的知识,希望对你有一定的参考价值。

接着我们上期的教程,今天带大家一起来学习下怎么去大麦网抢票

 

我们先看看代码运行的视频效果

 

https://vkceyugu.cdn.bspapp.com/VKCEYUGU-4a31945b-22cb-4446-83cb-b078e22c7b51/e67d6cf0-4569-48c4-ab8d-15bca1cf020b.mp4

 

由于今天写的时候频繁下单又取消,导致不能下单

控制台输出

 

E:\\python3.9.5\\damai\\venv\\Scripts\\python.exe E:/python3.9.5/damai/main.py###打开浏览器,进入大麦网######请点击登录######请扫码登录######Cookie保存成功######成功获取Cookie,重启浏览器######开始登录######载入Cookie######登录成功######进入抢票界面######等待--确认订单--页面出现,可自行刷新,若长期不跳转可选择-- CRTL+C --重新抢票######开始确认订单######选择购票人信息,可手动帮助点击###本次抢票时间: 1.37282133102417###等待跳转到--付款界面--,可自行刷新,若长期不跳转可选择-- CRTL+C --重新抢票###

 

 

创建配置参数文件

 

创建一个动态参数目录,把我们经常修改的参数写在里面

 

创建 config.json 文件

 

 

写入参数

 

{    "sess": [1],    "price": [2, 3, 1],    "real_name": [1, 2],    "nick_name": "程序工厂",    "ticket_num": 1,    "driver_path": "D:/python3.9.5/chromedriver.exe",    "damai_url": "https://www.damai.cn/",    "target_url": "https://detail.damai.cn/item.htm?spm=a2oeg.home.card_0.ditem_1.591b23e12Cgyqo&id=645040954905"}

 

nick_name  你在大麦网账户的昵称

driver_path 浏览器驱动的地址

target_url 所抢票的购买地址

 

抢票代码

 

# coding: utf-8from json import loadsfrom time import sleep, timefrom pickle import dump, loadfrom os.path import existsfrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.desired_capabilities import DesiredCapabilitiesclass Concert(object):    def __init__(self, session, price, real_name, nick_name, ticket_num, damai_url, target_url,driver_path):        self.session = session  # 场次序号优先级        self.price = price  # 票价序号优先级        self.real_name = real_name  # 实名者序号        self.status = 0  # 状态标记        self.time_start = 0  # 开始时间        self.time_end = 0  # 结束时间        self.num = 0  # 尝试次数        self.ticket_num = ticket_num  # 购买票数        self.nick_name = nick_name  # 用户昵称        self.damai_url = damai_url  # 大麦网官网网址        self.target_url = target_url  # 目标购票网址        self.driver_path = driver_path  # 浏览器驱动地址        self.driver = None    def isClassPresent(self, item, name, ret=False):        try:            result = item.find_element_by_class_name(name)            if ret:                return result            else:                return True        except:            return False    def get_cookie(self):        self.driver.get(self.damai_url)        print(u"###请点击登录###")        self.driver.find_element_by_class_name('login-user').click()        while self.driver.title.find('大麦网-全球演出赛事官方购票平台') != -1:  # 等待网页加载完成            sleep(1)        print(u"###请扫码登录###")        while self.driver.title == '大麦登录':  # 等待扫码完成            sleep(1)        dump(self.driver.get_cookies(), open("cookies.pkl", "wb"))        print(u"###Cookie保存成功###")    def set_cookie(self):        try:            cookies = load(open("cookies.pkl", "rb"))  # 载入cookie            for cookie in cookies:                cookie_dict = {                    'domain':'.damai.cn',  # 必须有,不然就是假登录                    'name': cookie.get('name'),                    'value': cookie.get('value'),                    "expires": "",                    'path': '/',                    'httpOnly': False,                    'HostOnly': False,                    'Secure': False}                self.driver.add_cookie(cookie_dict)            print(u'###载入Cookie###')        except Exception as e:            print(e)    def login(self):        print(u'###开始登录###')        self.driver.get(self.target_url)        WebDriverWait(self.driver, 10, 0.1).until(EC.title_contains('大麦网'))        self.set_cookie()    def enter_concert(self):        print(u'###打开浏览器,进入大麦网###')        if not exists('cookies.pkl'):   # 如果不存在cookie.pkl,就获取一下            self.driver = webdriver.Chrome(executable_path=self.driver_path)            self.get_cookie()            print(u'###成功获取Cookie,重启浏览器###')            self.driver.quit()        options = webdriver.ChromeOptions()        # 禁止图片、js、css加载        prefs = {"profile.managed_default_content_settings.images": 2,                 "profile.managed_default_content_settings.javascript": 1,                 'permissions.default.stylesheet': 2}        options.add_experimental_option("prefs", prefs)        # 更换等待策略为不等待浏览器加载完全就进行下一步操作        capa = DesiredCapabilities.CHROME        capa["pageLoadStrategy"] = "none"        self.driver = webdriver.Chrome(executable_path=self.driver_path, options=options, desired_capabilities=capa)        self.login()        self.driver.refresh()        try:            locator = (By.XPATH, "/html/body/div[1]/div/div[3]/div[1]/a[2]/div")            WebDriverWait(self.driver, 5, 0.3).until(EC.text_to_be_present_in_element(locator, self.nick_name))            self.status = 1            print(u"###登录成功###")            self.time_start = time()        except:            self.status = 0            self.driver.quit()            raise Exception(u"***错误:登录失败,请删除cookie后重试***")    def choose_ticket(self):        print(u"###进入抢票界面###")        while self.driver.title.find('确认订单') == -1:  # 如果跳转到了确认界面就算这步成功了,否则继续执行此步            self.num += 1            if con.driver.current_url.find("buy.damai.cn") != -1:                break            # 确认页面刷新成功            try:                #box = self.driver.find_element_by_class_name('perform__order__box')                box = WebDriverWait(self.driver, 1, 0.1).until(EC.presence_of_element_located((By.CLASS_NAME, 'perform__order__box')))            except:                raise Exception(u"***Error: 页面刷新出错***")            try:                buybutton = box.find_element_by_class_name('buybtn')                buybutton_text = buybutton.text            except:                raise Exception(u"***Error: buybutton 位置找不到***")            if buybutton_text == "即将开抢" or buybutton_text == "即将开售":                self.status = 2                raise Exception(u"---尚未开售,刷新等待---")            try:                selects = box.find_elements_by_class_name('perform__order__select')                for item in selects:                    if item.find_element_by_class_name('select_left').text == '场次':                        session = item                        # print('\\t场次定位成功')                    elif item.find_element_by_class_name('select_left').text == '票档':                        price = item                        # print('\\t票档定位成功')                session_list = session.find_elements_by_class_name('select_right_list_item')                # print('可选场次数量为:{}'.format(len(session_list)))                for i in self.session:  # 根据优先级选择一个可行场次                    j = session_list[i-1]                    k = self.isClassPresent(j, 'presell', True)                    if k: # 如果找到了带presell的类                        if k.text == '无票':                            continue                        elif k.text == '预售':                            j.click()                            break                    else:                        j.click()                        break                price_list = price.find_elements_by_class_name('select_right_list_item')                # print('可选票档数量为:{}'.format(len(price_list)))                for i in self.price:                    j = price_list[i-1]                    k = self.isClassPresent(j, 'notticket')                    if k:  # 存在notticket代表存在缺货登记,跳过                        continue                    else:                        j.click()                        break            except:                raise Exception(u"***Error: 选择场次or票档不成功***")            try:                ticket_num_up = box.find_element_by_class_name('cafe-c-input-number-handler-up')            except:                if buybutton_text == "选座购买":  # 选座购买没有增减票数键                    buybutton.click()                    self.status = 5                    print(u"###请自行选择位置和票价###")                    break                elif buybutton_text == "提交缺货登记":                    raise Exception(u'###票已被抢完,持续捡漏中...或请关闭程序并手动提交缺货登记###')                else:                    raise Exception(u"***Error: ticket_num_up 位置找不到***")            if buybutton_text == "立即预订":                for i in range(self.ticket_num-1):  # 设置增加票数                    ticket_num_up.click()                buybutton.click()                self.status = 3            elif buybutton_text == "立即购买":                for i in range(self.ticket_num-1):  # 设置增加票数                    ticket_num_up.click()                buybutton.click()                self.status = 4    def check_order(self):        if self.status in [3, 4, 5]:            if self.real_name is not None:                print(u"###等待--确认订单--页面出现,可自行刷新,若长期不跳转可选择-- CRTL+C --重新抢票###")                try:                    tb = WebDriverWait(self.driver, 1, 0.1).until(EC.presence_of_element_located((By.XPATH, '/html/body/div[3]/div[2]/div')))                except:                    raise Exception(u"***Error:实名信息选择框没有显示***")                print(u'###开始确认订单###')                print(u'###选择购票人信息,可手动帮助点击###')                init_sleeptime = 0.0                Labels = tb.find_elements_by_tag_name('label')                # 防止点击过快导致没有选择多个人                while True:                    init_sleeptime += 0.1                    true_num = 0                    for num_people in self.real_name:                        tag_input = Labels[num_people-1].find_element_by_tag_name('input')                        if tag_input.get_attribute('aria-checked') == 'false':                            sleep(init_sleeptime)                            tag_input.click()                        else:                            true_num += 1                    if true_num == len(self.real_name):                        break                print("本次抢票时间:", time()-self.time_start)                self.driver.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[9]/button').click() # 同意以上协议并提交订单            else:                self.driver.find_element_by_xpath('/html/body/div[2]/div[2]/div/div[8]/button').click()            # 判断title是不是支付宝            print(u"###等待跳转到--付款界面--,可自行刷新,若长期不跳转可选择-- CRTL+C --重新抢票###")            try:                WebDriverWait(self.driver, 3600, 0.1).until(EC.title_contains('支付宝'))            except:                raise Exception(u'***Error: 长期跳转不到付款界面***')            self.status = 6            print(u'###成功提交订单,请手动支付###')            self.time_end = time()if __name__ == '__main__':    try:        with open('./config.json', 'r', encoding='utf-8') as f:            config = loads(f.read())            # params: 场次优先级,票价优先级,实名者序号, 用户昵称, 购买票数, 官网网址, 目标网址, 浏览器驱动地址        con = Concert(config['sess'], config['price'], config['real_name'], config['nick_name'], config['ticket_num'], config['damai_url'], config['target_url'], config['driver_path'])        con.enter_concert()    except Exception as e:        print(e)        exit(1)    while True:        try:            con.choose_ticket()            con.check_order()        except Exception as e:            con.driver.get(con.target_url)            print(e)            continue        if con.status == 6:            print(u"###经过%d轮奋斗,共耗时%.1f秒,抢票成功!请确认订单信息###" % (con.num, round(con.time_end-con.time_start, 3)))            break

 

我们下来看看运行开始逻辑

 

if __name__ == '__main__':    try:        with open('./config.json', 'r', encoding='utf-8') as f:            config = loads(f.read())            # params: 场次优先级,票价优先级,实名者序号, 用户昵称, 购买票数, 官网网址, 目标网址, 浏览器驱动地址        con = Concert(config['sess'], config['price'], config['real_name'], config['nick_name'], config['ticket_num'], config['damai_url'], config['target_url'], config['driver_path'])        con.enter_concert()    except Exception as e:        print(e)        exit(1)    

 

try:

except Exception as e:

 

是 异常(运行报错)捕获,如果在 try 和 except Exception as e:  之间的代码,如果出现异常了,就会进入 except Exception as e:  下面的方法 

print(e)

exit(1)

 

print是打印的意思,e是具体的异常错误,print(e),意思是把运行具体的报错信息打印出来,方便我们写代码的人看到具体是什么错误,exit(1) 退出程序

 

 

读取指定地址的文件

 

with open('./config.json', 'r', encoding='utf-8') as f:

 

以utf-8的格式,打开我们前面创建的配置参数文件,f 作为他的标志

 

 

读取文件内容

 config = loads(f.read())

 

read 为读取的意思,loads是加载信息,f是前面打开的文件, 那么 loads(f.read()),就是读取config.json文件的内容,然后把读到的内容给config,后面就可以直接用 config 取到config.json的内容


 

把读取到的文件赋值给指定参数

con = Concert(config['sess'], config['price'], config['real_name'], config['nick_name'], config['ticket_num'], config['damai_url'], config['target_url'], config['driver_path'])

 

 config['sess'] 就是读取 config.json 文件里 sess 的参数,后面几个也一样

 

 

Concert 是前面写的一个方法

 

 class Concert(object):    def __init__(self, session, price, real_name, nick_name, ticket_num, damai_url, target_url,driver_path):        self.session = session  # 场次序号优先级        self.price = price  # 票价序号优先级        self.real_name = real_name  # 实名者序号        self.status = 0  # 状态标记        self.time_start = 0  # 开始时间        self.time_end = 0  # 结束时间        self.num = 0  # 尝试次数        self.ticket_num = ticket_num  # 购买票数        self.nick_name = nick_name  # 用户昵称        self.damai_url = damai_url  # 大麦网官网网址        self.target_url = target_url  # 目标购票网址        self.driver_path = driver_path  # 浏览器驱动地址        self.driver = None

 

连起来就是,把文件里读取过来的信息,赋值按照每个参数的单独读取,然后穿给我们定义的变量里,在这个程序里,哪里要用到的话就可以直接以 self.session 方式调用

 

 

接着看后面一行代码

con.enter_concert()

 

con.enter_concert() 是我们前面写的一个登录方法

 

    def enter_concert(self):        print(u'###打开浏览器,进入大麦网###')        if not exists('cookies.pkl'):   # 如果不存在cookie.pkl,就获取一下            self.driver = webdriver.Chrome(executable_path=self.driver_path)            self.get_cookie()            print(u'###成功获取Cookie,重启浏览器###')            self.driver.quit()        options = webdriver.ChromeOptions()        # 禁止图片、js、css加载        prefs = {"profile.managed_default_content_settings.images": 2,                 "profile.managed_default_content_settings.javascript": 1,                 'permissions.default.stylesheet': 2}        options.add_experimental_option("prefs", prefs)        # 更换等待策略为不等待浏览器加载完全就进行下一步操作        capa = DesiredCapabilities.CHROME        capa["pageLoadStrategy"] = "none"        self.driver = webdriver.Chrome(executable_path=self.driver_path, options=options, desired_capabilities=capa)        self.login()        self.driver.refresh()        try:            locator = (By.XPATH, "/html/body/div[1]/div/div[3]/div[1]/a[2]/div")            WebDriverWait(self.driver, 5, 0.3).until(EC.text_to_be_present_in_element(locator, self.nick_name))            self.status = 1            print(u"###登录成功###")            self.time_start = time()        except:            self.status = 0            self.driver.quit()            raise Exception(u"***错误:登录失败,请删除cookie后重试***")

 

其中

 

if not exists('cookies.pkl'):

 

这行代码的意思是,if not exists (如果不存在 ) cookies.pkl 文件,执行代码

 

self.driver = webdriver.Chrome(executable_path=self.driver_path)self.get_cookie()print(u'###成功获取Cookie,重启浏览器###')self.driver.quit()

 

self.driver = webdriver.Chrome(executable_path=self.driver_path)

 

这行代码在我们上一课讲过,打开浏览器

 

self.get_cookie()  是我们代码中的一个方法

    def get_cookie(self):        self.driver.get(self.damai_url)        print(u"###请点击登录###")        self.driver.find_element_by_class_name('login-user').click()        while self.driver.title.find('大麦网-全球演出赛事官方购票平台') != -1:  # 等待网页加载完成            sleep(1)        print(u"###请扫码登录###")        while self.driver.title == '大麦登录':  # 等待扫码完成            sleep(1)        dump(self.driver.get_cookies(), open("cookies.pkl", "wb"))        print(u"###Cookie保存成功###")

 

打开浏览器,访问 self.damai_url (配置参数文件里 damai_url  填写的地址)地址,点击 login-user 按钮,页面就自动跳转到大麦网的登录页面了,这时候因为登录页面有多种登录方式,我们也不确定使用者具体使用那种登录方式,这是比较好的一个解决办法就是让用户自己手动登录账户,然后我们把他的登录信息存成 cookies.pkl 文件,下次进入方法如果有这个文件就不用重复登录系统了

 

接着运行到了下面代码

 

    while True:        try:            con.choose_ticket()            con.check_order()        except Exception as e:            con.driver.get(con.target_url)            print(e)            continue        if con.status == 6:            print(u"###经过%d轮奋斗,共耗时%.1f秒,抢票成功!请确认订单信息###" % (con.num, round(con.time_end-con.time_start, 3)))            break

 

 

con.choose_ticket() 是我们前面写的一个方法

 

    def choose_ticket(self):        print(u"###进入抢票界面###")        while self.driver.title.find('确认订单') == -1:  # 如果跳转到了确认界面就算这步成功了,否则继续执行此步            self.num += 1            if con.driver.current_url.find("buy.damai.cn") != -1:                break            # 确认页面刷新成功            try:                #box = self.driver.find_element_by_class_name('perform__order__box')                box = WebDriverWait(self.driver, 1, 0.1).until(EC.presence_of_element_located((By.CLASS_NAME, 'perform__order__box')))            except:                raise Exception(u"***Error: 页面刷新出错***")            try:                buybutton = box.find_element_by_class_name('buybtn')                buybutton_text = buybutton.text            except:                raise Exception(u"***Error: buybutton 位置找不到***")            if buybutton_text == "即将开抢" or buybutton_text == "即将开售":                self.status = 2                raise Exception(u"---尚未开售,刷新等待---")            try:                selects = box.find_elements_by_class_name('perform__order__select')                for item in selects:                    if item.find_element_by_class_name('select_left').text == '场次':                        session = item                        # print('\\t场次定位成功')                    elif item.find_element_by_class_name('select_left').text == '票档':                        price = item                        # print('\\t票档定位成功')                session_list = session.find_elements_by_class_name('select_right_list_item')                # print('可选场次数量为:{}'.format(len(session_list)))                for i in self.session:  # 根据优先级选择一个可行场次                    j = session_list[i-1]                    k = self.isClassPresent(j, 'presell', True)                    if k: # 如果找到了带presell的类                        if k.text == '无票':                            continue                        elif k.text == '预售':                            j.click()                            break                    else:                        j.click()                        break                price_list = price.find_elements_by_class_name('select_right_list_item')                # print('可选票档数量为:{}'.format(len(price_list)))                for i in self.price:                    j = price_list[i-1]                    k = self.isClassPresent(j, 'notticket')                    if k:  # 存在notticket代表存在缺货登记,跳过                        continue                    else:                        j.click()                        break            except:                raise Exception(u"***Error: 选择场次or票档不成功***")            try:                ticket_num_up = box.find_element_by_class_name('cafe-c-input-number-handler-up')            except:                if buybutton_text == "选座购买":  # 选座购买没有增减票数键                    buybutton.click()                    self.status = 5                    print(u"###请自行选择位置和票价###")                    break                elif buybutton_text == "提交缺货登记":                    raise Exception(u'###票已被抢完,持续捡漏中...或请关闭程序并手动提交缺货登记###')                else:                    raise Exception(u"***Error: ticket_num_up 位置找不到***")            if buybutton_text == "立即预订":                for i in range(self.ticket_num-1):  # 设置增加票数                    ticket_num_up.click()                buybutton.click()                self.status = 3            elif buybutton_text == "立即购买":                for i in range(self.ticket_num-1):  # 设置增加票数                    ticket_num_up.click()                buybutton.click()                self.status = 4

 

今天先到这里,我们抢票的逻辑我们下期继续讲解

需要源码的关注下方微信公众号回复:大麦网源码 获取本期源码

     

关注微信公众号:程序工厂

私信我加入交流群

 

移动联通电信话费91折充值

 

本期代码主要参考自GitHub上代码

github地址: https://github.com/BBDrive/damai_ticket

代码是二年前写的,下载下来还不能运行,稍微修改了些代码,作为本期课程素材

以上是关于从零开始学写脚本(大麦网抢票 上)第二天的主要内容,如果未能解决你的问题,请参考以下文章

大麦网抢票工具系列

从零开始学写脚本第一天

从零开始学写脚本第一天

PHP从零开始,第二天

从零开始学习C语言(第二天)

想去看演唱却总是抢不到票?教你用Python制作一个自动抢票脚本