ticket-py/yes24/tuiPiaodev.py
2024-04-30 17:47:01 +08:00

405 lines
18 KiB
Python

# -*- coding:utf-8 -*-
import threading
from requestUtil import myRequests
import weChatUtil
from bs4 import BeautifulSoup
import re
import json
import time
import datetime
import chaojiying
import randomStr
import log
class tuiPiao(threading.Thread):
def __init__(self, setting):
threading.Thread.__init__(self)
self.setting=setting
self.userName = setting.get("userName")
self.userPwd = setting.get("userPwd")
self.idCustomer = setting.get("idCustomer")
self.goodsid = setting.get("goodsid")
self.blocks = setting.get("blocks")
self.block = None
self.playDay = setting.get("playDay")
self.ticketTotal = int(setting.get("ticketTotal"))
self.Delivery = str(setting.get("Delivery"))
self.sleepTime = int(setting.get("sleepTime"))/1000
self.idTime = setting.get("idTime")
self.idHall = setting.get("idHall")
self.startTime = setting.get("startTime")
self.etcFee = {"EtcFees": "69#1000^", "EtcFeeAmount": 1000}
self.captchaInfo={
"key": '',
"result": ''
}
self.req = myRequests()
def __login(self):
time.sleep(self.sleepTime)
Referer = "https://www.yes24.com/Templates/FTLogin.aspx"
log.debug("{}开始执行登陆".format(self.userName))
loginData = {
"SMemberID": self.userName,
"SMemberPassword": self.userPwd,
"LoginType": "",
"AutoLogin": 1,
"FBLoginSub$ReturnParams": "",
"FBLoginSub$ReturnURL": "",
"RefererUrl": "http://ticket.yes24.com/",
"LoginIDSave": "N",
"FBLoginSub$NaverCode": "",
"FBLoginSub$NaverState": "",
"FBLoginSub$Facebook": ""
}
r=self.req.post("https://www.yes24.com/Templates/FTLogin.aspx", postData=loginData,postReferer=Referer)
if r[0:20].find('<script')<0:
raise Exception("登陆失败")
def __logout(self):
time.sleep(self.sleepTime)
self.req.get("https://www.yes24.com/Templates/FTLogout.aspx?ReturnURL=http://ticket.yes24.com")
log.info("{}退出{}日抢票".format(self.userName, self.playDay))
def __getServerTime(self):
time.sleep(self.sleepTime)
return self.req.getServerTime("http://ticket.yes24.com")
def __waiteToStart(self):
if not self.startTime:
return
servertime = self.__getServerTime()
servertime = datetime.datetime.strptime(
servertime, '%a, %d %b %Y %H:%M:%S GMT')+datetime.timedelta(hours=9) # 韩国在东9区
starttime = datetime.datetime.strptime(
"{} GMT".format(self.startTime), "%Y%m%d %H:%M:%S GMT") # 韩国的售票时间
offset = time.mktime(starttime.timetuple()) - \
time.mktime(servertime.timetuple())
if offset > 0:
log.info("{}时间未到。睡眠{}".format(self.userName, offset))
time.sleep(offset-0.3) # 考虑网络延迟 少睡0.3秒
def __waiteToLogin(self):
servertime = self.__getServerTime()
servertime = datetime.datetime.strptime(
servertime, '%a, %d %b %Y %H:%M:%S GMT')+datetime.timedelta(hours=9) # 韩国在东9区
starttime = datetime.datetime.strptime(
"{} GMT".format(self.startTime), "%Y%m%d %H:%M:%S GMT") # 韩国的售票时间
offset = time.mktime(starttime.timetuple()) - \
time.mktime(servertime.timetuple())
offset=offset-1800
if offset > 0:
log.info("{}时间未到。睡眠{}分钟后登陆".format(self.userName, offset//60))
time.sleep(offset)
def __initDeliveryInfo(self):
time.sleep(self.sleepTime)
log.info("{}开始获取delivery信息".format(self.userName))
r = self.req.post("http://ticket.yes24.com/Pages/Perf/Sale/Ajax/Perf/DeliveryUserInfo.aspx",
postReferer="http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleProcess.aspx?IdPerf={}&IdTime=".format(self.goodsid))
soup = BeautifulSoup(r, 'lxml')
deliveryList = soup.select('input')
deliveryInfo={}
for i in deliveryList:
deliveryInfo[i.get("id")]=i.get("value")
self.deliveryInfo=deliveryInfo
def __initIdCustomer(self):
time.sleep(self.sleepTime)
Referer = "http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleProcess.aspx?IdPerf={}&IdTime={}".format(self.goodsid,self.idTime)
d = {
"idTime": self.idTime,
"idHall": self.idHall,
"block": self.blocks[0],#退票比较特殊 获取ID时还没有具体的block
"stMax": 10,
"pHCardAppOpt": 0
}
r = self.req.get(
"http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleHtmlSeat.aspx", getData=d, getReferer=Referer)
begin = r.find("var IdCustomer")
end = begin+28
targetStr = r[begin:end]
idCustomer = re.sub(r"\D", "", targetStr)
log.warning("***注意***{}的idCustomer为{} 请保存".format(self.userName, self.idCustomer))
self.idCustomer= idCustomer
def __getServerTime(self):
time.sleep(self.sleepTime)
return self.req.getServerTime("http://ticket.yes24.com")
def __doLock(self,seatValue):
time.sleep(self.sleepTime)
lockData = {
"name": self.idCustomer,
"idTime": self.idTime,
"token": seatValue,
"Block": self.block
}
log.debug("{}开始对{}进行锁票".format(self.userName, seatValue))
Referer = "http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleHtmlSeat.aspx?idTime={}&idHall={}".format(self.idTime,self.idHall)
lockDataRes = self.req.post("http://ticket.yes24.com/OSIF/Book.asmx/Lock", postData=lockData, postReferer=Referer)
if lockDataRes.find('<int xmlns="http://tempuri.org/">0</int>') > -1:
log.debug("{}锁票成功".format(seatValue))
return True
else:
log.debug("{}锁票失败".format(seatValue))
return False
#应该可以省略
def __computeSelectedSeatTotalPrice(self,seatGrade):
time.sleep(self.sleepTime)
d = {
"pIdTime": self.idTime,
"PCntClass": seatGrade
}
Referer = "http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleProcess.aspx?IdPerf={}&IdTime={}".format(self.goodsid,self.idTime)
r = self.req.post(
"http://ticket.yes24.com/Pages/Perf/Sale/Ajax/Perf/TimeSeatFlashEnd.aspx", postData=d, postReferer=Referer)
#<li class='grade'><div classbyte='T192$252$188$174'><strong class='c_name'>전석</strong> <span class='c_price'>99,000원</span><select id='selSeatClass' price='99000'><option selected value='1'>1매</option></select></div></li>
soup = BeautifulSoup(r, 'lxml')
self.classByte = soup.select('div')[0].get('classbyte')
selSeatClass = soup.select('#selSeatClass')[0]
price = int(selSeatClass.get('price'))
seatCount = int(selSeatClass.select(
'option')[0].get('value'))
TotalPrice= price*seatCount
if self.Delivery == "2" :
TotalPrice += 2800
TotalPrice += self.etcFee['EtcFeeAmount']
self.TotalPrice=TotalPrice
def __isNeedCaptcha(self):
time.sleep(self.sleepTime)
d = {
"IdPerf": self.goodsid,
"IdTime": self.idTime
}
r = self.req.get(
"http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleProcess.aspx", getData=d)
if r.find("reCAPTCHAUse = 'Y';") > -1:
return True
else:
return False
def __computeCaptchaKeyAndResult(self):
time.sleep(self.sleepTime)
Referer = "http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleProcess.aspx?IdPerf={}".format(self.goodsid)
captchaKeyDataRes = self.req.postJson(
"http://ticket.yes24.com/Pages/Perf/Sale/Captcha/CaptchaImage.aspx/GetKeyCaptcha", postReferer=Referer)
captchaKey = json.loads(captchaKeyDataRes)
captchaKey = captchaKey['d']['Result']
time.sleep(self.sleepTime)
imgDataRes = self.req.getImage(
"http://ticket.yes24.com/Pages/Perf/Sale/Captcha/CaptchaImage.aspx?key="+captchaKey, getReferer=Referer)
captchaFileName = "captchas/cap_"+randomStr.getRandomStr()+".jpeg"
with open(captchaFileName, 'wb') as f:
f.write(imgDataRes)
f.close()
keyData = {
"key": captchaKey,
"result": ''
}
captchaCount=0
while True:
if captchaCount==3:
raise Exception("验证码连续三次识别失败")
cap=chaojiying.getCaptcha(captchaFileName)
if cap=='error':
captchaCount+=1
continue
else:
keyData['result']=cap
break
self.captchaInfo=keyData
def __InicisPayInfo(self):
time.sleep(self.sleepTime)
d = {
"pIdPerf": self.goodsid,
"pPrice": self.TotalPrice,
"pIdTime":self.idTime,
"pHCardAppOpt": 0,
"pIsMPoint": 0
}
Referer = "http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleProcess.aspx?IdPerf={}".format(self.goodsid)
r = self.req.post(
"http://ticket.yes24.com/Pages/Perf/Sale/Ajax/Perf/InicisPayInfo.aspx", postData=d, postReferer=Referer)
soup = BeautifulSoup(r, 'lxml')
inputList = soup.select("input")
INicisPay = {}
for _input in inputList:
INicisPay[_input.get("id")]=_input.get("value")
self.INicisPay=INicisPay
def __GetBookWhole(self):
time.sleep(self.sleepTime)
d = {
"idHall": self.idHall,
"idTime": self.idTime,
"block": self.block,
"channel": 1,
"idCustomer": self.idCustomer,
"idOrg": 1
}
Referer = "http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleHtmlSeat.aspx?idTime={}&idHall={}".format(self.idTime,self.idHall)
r = self.req.post("http://ticket.yes24.com/OSIF/Book.asmx/GetBookWhole", postData=d, postReferer=Referer)
soup = BeautifulSoup(r, 'xml')
if soup.BlockSeat is None:
raise Exception("扫描座位信息异常")
return soup.BlockSeat.string
def __doBuy(self,seatValue,seatGrade,blockSeat):
time.sleep(self.sleepTime)
merchantData=[]
merchantData.append("ksPayMethod=001000000000")
merchantData.append("ksPrice={}".format(self.TotalPrice))
merchantData.append("ksMid={}".format(self.INicisPay["hidMid"]))
merchantData.append("ksIdPerf={}".format(self.goodsid))
merchantData.append("ksIdTime={}".format(self.idTime))
merchantData.append("ksTimeOption=2")
merchantData.append("ksIdSeat={}".format(seatValue))
merchantData.append("ksIdNonSeat={}-{}".format(self.classByte,seatGrade))
merchantData.append("ksSeatCnt=1")
merchantData.append("ksUserMail={}".format(self.INicisPay['hidBuyeremail']))
merchantData.append("ksUserName={}".format(self.INicisPay['hidBuyername']))
merchantData.append("ksUserTel={}".format(self.INicisPay['hidBuyertel']))
merchantData.append("ksUserMobile={}".format(self.INicisPay['hidBuyermobile']))
merchantData.append("ksGoodsName=공연티켓상품")
merchantData.append("recaptcha_challenge_field=")
merchantData.append("recaptcha_response_field=")
merchantData.append("ksEmergencyName={}".format(self.INicisPay['hidBuyername']))
merchantData.append("ksEmergencyTel={}".format(self.INicisPay['hidBuyertel']))
merchantData.append("ksEmergencyMail={}".format(self.INicisPay['hidBuyeremail']))
merchantData.append("ksEtcFee={}".format(self.etcFee['EtcFees']))
merchantData.append("ksEtcValidTicketCnt=1")
merchantData.append("ksPayBank=50")
merchantData.append("ksIsYesPointYN=N")
merchantData.append("captchaText={}".format(self.captchaInfo['result']))
merchantData.append("captchaKey={}".format(self.captchaInfo['key']))
if self.Delivery == "2" :
merchantData.append("ksDelivery=8%232800")
merchantData.append("ksReceiver={}".format(self.INicisPay['hidBuyername']))
merchantData.append("ksTel={}".format(self.INicisPay['hidBuyertel']))
merchantData.append("ksZipCode={}".format(self.deliveryInfo['LUAddr_ZipCode1']))
merchantData.append("ksAddress={} {}".format(self.deliveryInfo['LUAddr_Address1'],self.deliveryInfo['LUAddr_Address2']))
d = {
"merchantData": "&".join(merchantData),
"version": "1.0",
"currency": "WON",
"goodsname": "공연티켓상품",
"mid": self.INicisPay['hidMid'],
"oid": self.INicisPay['hidOId'],
"price": self.TotalPrice,
"buyername": self.INicisPay['hidBuyername'],
"buyertel": self.INicisPay['hidBuyertel'],
"buyeremail": self.INicisPay['hidBuyeremail'],
"timestamp": self.INicisPay['hidTimestamp'],
"signature": self.INicisPay['hidSignature'],
"returnUrl": "http://ticket.yes24.com/Pages/InicisNewPG/INIStdPayResponse.aspx",
"closeUrl": "http://ticket.yes24.com/Pages/InicisNewPG/INIStdPayClose.aspx?t=pay",
"mKey": self.INicisPay['hidMKey'],
"gopaymethod": "Card",
"payViewType": "overlay",
"quotabase": "2:3:4:5:6:7:8:9:10:11:12",
"acceptmethod": "HPP(1):no_receipt:va_receipt:vbanknoreg(0):below1000:popreturn:usespcp:cardpoint"
}
Referer = "http://ticket.yes24.com/Pages/Perf/Sale/PerfSaleProcess.aspx?IdPerf={}&IdTime={}".format(self.goodsid,self.idTime)
r = self.req.post("http://ticket.yes24.com/Pages/InicisNewPG/INIStdPayResponse.aspx", postData=d, postReferer=Referer)
if r.find("parent.fts_ProcessSaleFail('');") > 0:
sBegin = r.find("fts_ProcessSaleSuccess('")
order_id = r[sBegin:(sBegin+41)]
order_id = re.sub(r"\D", "", order_id.split("'")[1])
BankAccountInfoData = {
"pIdOrder": order_id
}
time.sleep(self.sleepTime)
self.req.post("http://ticket.yes24.com/Pages/Perf/Sale/Ajax/Perf/BankAccountInfo.aspx",
postData=BankAccountInfoData, postReferer=Referer)
log.info("{}购票成功商品id{}座位:{}".format(
self.userName, self.goodsid, blockSeat))
weChatUtil.sendTicketSuccess('yes24',self.goodsid,self.playDay,blockSeat,self.userName)
return True
else:
log.debug("{}购票失败,详见日志".format(self.userName))
return False
def __do_ticket(self):
# self.__waiteToLogin()
self.__login()
self.__waiteToStart()
if self.idCustomer is None or self.idCustomer == '':
self.__initIdCustomer()
while self.ticketTotal>0:
for self.block in self.blocks:
if self.ticketTotal<=0:
break
blockSeatStr=self.__GetBookWhole()
if blockSeatStr is None or blockSeatStr=="":
log.info("区域{}无座位".format(self.block))
time.sleep(self.sleepTime)
continue
blockSeatList = blockSeatStr.split("^")
for blockSeat in blockSeatList:
if self.ticketTotal<=0:
break
if blockSeat is None or blockSeat == "":
continue
_temp = blockSeat.split('@')
seatValue = _temp[0]
seatGrade = _temp[-1]
if self.__doLock(seatValue) is False:
continue
self.__computeSelectedSeatTotalPrice(seatGrade)
if self.__isNeedCaptcha() is True:
tryCount=0
while True:
if tryCount==3:
raise Exception("连续三次尝试购票失败")
self.__computeCaptchaKeyAndResult()
if tryCount==0:
self.__initDeliveryInfo()
self.__InicisPayInfo()#获取一次即可
ok=self.__doBuy(seatValue,seatGrade,blockSeat)
if ok is False:
tryCount+=1
continue
else:
self.ticketTotal-=1
break
else:
self.__initDeliveryInfo()
self.__InicisPayInfo()
ok=self.__doBuy(seatValue,seatGrade,blockSeat)
if ok is True:
self.ticketTotal-=1#无验证码的 不重试
self.__logout()
def run(self):
log.debug("开始用账号{}进行抢票.账号配置详情===>{}".format(self.userName,self.setting))
try:
self.__do_ticket()
except Exception as err:
log.error("账号{}抢票出现异常情况====> {}".format(self.userName ,err))
log.info("账号{}结束抢票".format(self.userName))