python演唱会抢票脚本_基于selenium的⼤麦⽹演唱会抢票程
序
⾃从我在知乎分享了代码后,很多⼈关注了我的代码,⾃⼰也很荣幸,哈哈。但是好多⼈运⾏我的代码却出现了这样那样的问题,我刚开始也很纳闷,明明⾃⼰当初试了好⼏个演唱会都可以,为什么现在有这么多问题,上段时间⾃⼰正好有事⾃⼰也没太关注这个,所以我也只是站在原来研究的基础上进⾏回答,很多回答可能并没有点到关键上。最近正好有⼈QQ我,我好好看了下,发现原来是⼤麦⽹的页⾯源码变了,变了很多很多,所以我原来的代码差不多失效⼤半了。我的⽅法太过于依赖页⾯源码的元素ID、xpath、class_name等等标签,所以应付不了这种变化。em,更新代码这件事,我最近先放放。不过⼤致思路是对的,⼤家在我的代码基础上修改下⼜是可以⽤的啦~
⼤麦⽹上,像林俊杰这类歌星的演唱会的门票,往往时间⼀到就瞬间售完,⽹速慢了或者⼿慢了都只能对着屏幕叹息了。所以有时候你愿意花这钱也不⼀定买得到看的机会。但是其实这个问题并不难解决,⼿速慢?那可以让代码模拟操作。⽹速慢?那可以把程序放到阿⾥服务器上运⾏。⽽这其中的关键就是编写⼀个抢票程序!
要说抢票,⽹上关于12306的抢票程序多如繁星,但是关于⼤麦⽹的还真不多,但是核⼼要义都是⼀样的:模拟。其实这种程序⼀定程度上类似于爬⾍,所以马上可以想到Python的urllib、BeautifulSoup、sele
nium、splinter等模块。最初为了⽅便,偷懒使⽤了splinter,封装得相当简单,但是功能不多,⽂档不全,⽹上资料少,写到后来,感觉主⽤这个模块解决不了⾃动登录问题,所以放弃转成了selenium。接下来,我将从账号登录、选择演唱会、购票、确认订单四个⽅⾯依次讲解思路。
1.账号登录
既然是抢票,我希望给定演唱会信息后⼀运⾏程序就能够马上进⾏,不需要其他的⼈⼯⼲预。这就要求我们的账号能够再抢票前⾃动登录绑定。其实要实现⾃动登录,由两种⽅式:①Cookie ②模拟登录。使⽤Cookie(原理:如果服务器端的$_COOKIE函数中记录了你的Cookie,那就可以直接调⽤登录,如果没有就需要⼈⼯登录了,登录了之后,⼆次访问界⾯就能把⾃⼰的Cookie保存到$_COOKIE函数)这种⽅式其实很⽅便,保存在本地,要⽤了调⽤⼀下,相当于带了⼀块出⼊皇宫的令牌,不⽤每次进⼊都验⾝啥的。但是Cookie涉及过期问题,同时是存在较⼤安全隐患。所以我决定玩玩另⼀个⽅式——模拟登录。
⼤麦⽹的登录界⾯如下图:
我们需要做的就是填充账号密码,填完了之后点击登录,其实⼈⼯登录到这⾥就完成了,但是⽤代码填充完内容后点击登录,惊喜就出现了,⼀个滑块突然出现在按钮上⽅,并红字提⽰需要将滑块滑到最右边才能点击登录。所以接下来我们除了要完成内容填充、按钮点击外,还要完成滑块的滑动。(我试过
模拟⼈⼯填写信息来躲避这个滑块,但是奈何骗不过去,只好直⾯问题了)
说实话,因为经验不⾜,内容填充花了我好⼏个⼩时,原因就是这个登录框其实是⼀个⽹页,封装在iframe标签中,作为外部⽹页的⼦界⾯,不管我⽤哪个⼯具包,⽤id、class、xpath等哪个⽅式,都⽆法定位到账号框和密码框。当我注意到iframe这个坑,才搞明⽩要⽤下⾯这句话来定位到⼦页⾯。
self.driver.switch_to_frame('alibaba-login-box')#⾥⾯这个是iframe的id
接下来就简单了,定位到两个框和⼀个按钮,然后点击⼀下按钮,保证滑块乖乖地出现。
self.driver.find_element_by_id('fm-login-id').send_keys(self.uid)
self.driver.find_element_by_id('fm-login-password').send_keys(self.upw)
selenium获取cookieself.driver.find_element_by_tag_name("button").click()
然后,想想⾃⼰是怎么滑动滑块的,在滑块处按下左键不动,移动⿏标向右,到最右边,然后松⼿。要模拟这个过程就需要⽤到ActionChains了。
ActionChains(self.driver).click_and_hold(self.driver.find_element_by_id('nc_1_n1z')).perform()#按住滑块不动
ActionChains(self.driver).move_by_offset(xoffset=250, yoffset=0).perform()#直接到终点,可能速度太快,会被系统判错误操作(这也是我不⽤drag_and_drop这个函数的原因),快到终点时停下
for i in range(2):
ActionChains(self.driver).move_by_offset(xoffset=10, yoffset=0).perform()#再慢慢滑两步
sleep(0.1)
sleep(0.5)#滑完了之后稍等下,让系统判断完毕
ActionChains(self.driver).release().perform()#松开点击
self.driver.find_element_by_tag_name("button").click()#点击登录
结束了之后,记得加上下⾯这句话,从iframe切换出去。
self.driver.switch_to_default_content()
但是,过了两天,我发现这个代码在我的电脑上失效了(别⼈那⾥好像是可以的)。。。不知道什么原因,selenium打开浏览器之后,⽆论是代码滑动滑块还是我⼿动滑动滑块,都是被判⽆效的,但是我⾃
⼰打开浏览器操作是可以的。我觉得我可能是被针对了(以前也碰到过两次),感觉没有办法解决之后,我开始着⼿⽤其他⽅式解决⾃动登录——Cookie。其实吧,这个是套路,直接贴代码就⾏了,有⼀个地⽅需要注意注意注意,重要的事情说三遍,因为⽹上的教程在这个地⽅很多都是错的,从⽽导致我当时代码调得差点⾃闭了。
def get_cookie(self):
(damai_url)
print("###请点击登录###")
while self.driver.title.find('⼤麦⽹-全球演出赛事官⽅购票平台')!=-1:
sleep(1)
print("###请扫码登录###")
while self.driver.title=='中⽂登录':
sleep(1)
print("###扫码成功###")
pickle.dump(_cookies(), open("cookies.pkl", "wb"))
print("###Cookie保存成功###")
def set_cookie(self):
try:
cookies = pickle.load(open("cookies.pkl", "rb"))#载⼊cookie
for cookie in cookies:
cookie_dict = {
'domain':'.damai',#必须有,不然就是假登录
'name': ('name'),
'value': ('value'),
"expires": "",
'path': '/',
'httpOnly': False,
'HostOnly': False,
'Secure': False}
self.driver.add_cookie(cookie_dict)
print('###载⼊Cookie###')
except Exception as e:
print(e)
之后只要如此调⽤就可以了。
if not ists('cookies.pkl'):#如果不存在cookie.pkl,就获取⼀下
<_cookie()
else:
(damai_url)
self.set_cookie()
2.选择演唱会
接下来就很直接了。
self.driver.find_elements_by_xpath('/html/body/div[1]/div/div[4]/input')[0].send_keys(self.name)#到搜索栏,填⼊演唱会歌星的名字
self.driver.find_elements_by_xpath('/html/body/div[1]/div/div[4]/div[1]')[0].click()#点击旁边的搜索按钮
kinds=self.driver.find_element_by_id('category_filter_id').find_elements_by_tag_name('li')#选择演唱会类别
for k in kinds:
=='演唱会':
k.click()
break
lists=self.driver.find_elements_by_id('content_list')[0].find_elements_by_tag_name('li')#获取所有可能演唱会
titles=[]
links=[]
self.choose_result=0
for li in lists:
word_link=li.find_element_by_tag_name('h3')
titles.append()
temp_s=_attribute('innerHTML').find('href')+6
temp_e=_attribute('innerHTML').find('target')-2
links.append(_attribute('innerHTML')[temp_s:temp_e])
if li.find_element_by_tag_name('h3').text.find(self.place)!=-1:#选择地点正确的演唱会
self.choose_result=len(titles)
break
self.url="https:"+links[self.choose_result-1]
(self.url)#载⼊⾄购买界⾯
3.购票
datelist=self.driver.find_element_by_id("performList").find_elements_by_tag_name('li')#根据优先级选择⼀个可⾏⽇期
for i in self.date:
j=datelist[i-1].get_attribute('class')
if j=='itm':
datelist[i-1].click()
break
elif j=='itm itm-sel':
break
elif j=='itm itm-oos':
continue
sleep(1)
pricelist=self.driver.find_element_by_id("priceList").find_elements_by_tag_name('li')#根据优先级选择⼀个可⾏票价for i in self.price:
j=pricelist[i-1].get_attribute('class')
if j=='itm':
pricelist[i-1].click()
break
elif j=='itm itm-sel':
break
elif j=='itm itm-oos':
continue
sleep(1.5)
cart=self.driver.find_element_by_id('cartList')
try:#各种按钮的点击
try:
cart.find_element_by_class_name('ops').find_element_by_link_text("⽴即预定").click()
self.status=3
except:
cart.find_element_by_class_name('ops').find_element_by_link_text("⽴即购买").click()
self.status=4
except:
cart.find_element_by_class_name('ops').find_element_by_link_text("选座购买").click()
self.status=5
self.num+=1
sleep(0.5)
接下来就是要点击确定了,但是这个确定按钮有三类:⽴即预定、⽴即购买、选座购买,我们需要分别处理。如果出错,就刷新界⾯
cart=self.driver.find_element_by_id('cartList')
try:#各种按钮的点击
try:
cart.find_element_by_class_name('ops').find_element_by_link_text("⽴即预定").click()
self.status=3
except:
cart.find_element_by_class_name('ops').find_element_by_link_text("⽴即购买").click()
self.status=4
except:
cart.find_element_by_class_name('ops').find_element_by_link_text("选座购买").click()
self.status=5
如果没有成功跳转,我没抢票的经验,不知道接下来会出现什么,所以也不知道要怎么具体应对,所以就刷新页⾯,重复上述操作,只能暂时这么粗暴地来了。
4.确认订单
点击选座购买,如果跳转成功,接下来就是选座了,这个有点⼩⿇烦,暂时没写代码应对,开始交给⼈⼯处理。
点击⽴即预定和⽴即购买后如果正常跳转,之后就是确认订单信息与结算了,这时会有好多类型的界⾯,但是其中两类界⾯占了⼤多数,所以我就针对这两类进⾏编程。
因为这个时候的界⾯涉及很多隐私信息,我就不放出来了,虽然可以打码,但是我就是不想放。⼤致的操作其实和前⾯是类似的:到⽬标,点击。
print('###开始确认订单###')
print('###默认购票⼈信息###')
rn_button=self.driver.find_elements_by_xpath('/html/body/div[3]/div[3]/div[2]/div[2]/div/a')
if len(rn_button)==1:#如果要求实名制
print('###选择实名制信息###')
rn_button[0].click()
#选择实名信息
tb=self.driver.find_element_by_xpath('/html/body/div[3]/div[3]/div[12]/div')
lb=tb.find_elements_by_tag_name('label')[al_name]#选择第al_name个实名者
lb.find_elements_by_tag_name('td')[0].click()
tb.find_element_by_class_name('one-btn').click()
print('###默认选择付款⽅式###')
print('###确认商品清单###')
rn_button=self.driver.find_elements_by_xpath('/html/body/div[3]/div[3]/div[3]/div[2]/div[2]/div/div/h2/a[1]')
if len(rn_button)==1:#如果要求实名制
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论