pull/41/head
wenxianping 2018-02-28 18:40:03 +08:00
parent d7b381e7a6
commit 520c8a528d
6 changed files with 146 additions and 34 deletions

View File

@ -3,7 +3,7 @@
- python版本支持
- 2.7
- 依赖库
- 依赖打码兔 需要去打码兔注册用户账号打码兔账号地址http://www.dama2.com一般充值1元就够用了充值打码兔之后首次运行是需要到官网黑白名单授权
- 依赖打码兔 需要去打码兔注册用户账号打码兔账号地址http://www.dama2.com 一般充值1元就够用了充值打码兔之后首次运行是需要到官网黑白名单授权
- 依赖若快 若快注册地址http://www.ruokuai.com/client/index?6726 推荐用若快打码兔在12306验证码更新之后识别率不是很高
- 项目依赖包 requirements.txt
- 安装方法 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
@ -204,4 +204,8 @@
- 修改已知bug
- 最后感谢群里提供测试和代码的小伙伴,能为你们买到一张回家的票真的感到灰常开心
- 2018.2.28更新收12306风控影响代码可能有时候会进入慢排队请自行调整刷新参数
- 修改已知bug
- 优化接口提交参数规范

View File

@ -10,6 +10,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -20,6 +21,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
@ -31,6 +33,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": False,
},
@ -41,6 +44,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -51,6 +55,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": False,
},
@ -61,6 +66,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": False,
},
@ -71,6 +77,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -81,6 +88,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -91,6 +99,29 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": False,
},
"GetJS": {
"req_url": "/otn/HttpZF/GetJS",
"req_type": "get",
"Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc",
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": False,
},
"odxmfwg": {
"req_url": "/otn/dynamicJs/odxmfwg",
"req_type": "get",
"Referer": "https://kyfw.12306.cn/otn/confirmPassenger/initDc",
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": False,
},
@ -101,6 +132,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -111,6 +143,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": True,
},
@ -121,6 +154,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.3,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -131,6 +165,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -141,6 +176,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -151,6 +187,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -161,6 +198,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -171,6 +209,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -181,6 +220,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": False,
"is_json": False,
},
@ -191,6 +231,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -201,6 +242,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -211,6 +253,7 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
@ -221,6 +264,40 @@ urls = {
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
"autoSubmitOrderRequest": {
"req_url": "/otn/confirmPassenger/autoSubmitOrderRequest",
"req_type": "post",
"Referer": "https://kyfw.12306.cn/otn/queryOrder/initNoComplete",
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
"getQueueCountAsync": {
"req_url": "/otn/confirmPassenger/getQueueCountAsync",
"req_type": "post",
"Referer": "https://kyfw.12306.cn/otn/queryOrder/initNoComplete",
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},
"confirmSingleForQueueAsys": {
"req_url": "/otn/confirmPassenger/confirmSingleForQueueAsys",
"req_type": "post",
"Referer": "https://kyfw.12306.cn/otn/queryOrder/initNoComplete",
"Host": "kyfw.12306.cn",
"re_try": 10,
"re_time": 0.1,
"s_time": 0.01,
"is_logger": True,
"is_json": True,
},

View File

@ -220,7 +220,10 @@ class GoLogin:
login_num = 0
while True:
self.cookietp()
self.httpClint.set_cookies(_jc_save_wfdc_flag="dc", _jc_save_fromStation="%u4E0A%u6D77%u8679%u6865%2CAOH", _jc_save_toStation="%u5170%u5DDE%u897F%2CLAJ", _jc_save_fromDate="2018-02-14", _jc_save_toDate="2018-01-16", RAIL_DEVICEID="EN_3_EGSe2GWGHXJeCkFQ52kHvNCrNlkz9n1GOqqQ1wR0i98WsD8Gj-a3YHZ-XYKeESWgCiJyyucgSwkFOzVHhHqfpidLPcm2vK9n83uzOPuShO3Pl4lCydAtQu4BdFqz-RVmiduNFixrcrN_Ny43135JiEtqLaI")
self.httpClint.set_cookies(_jc_save_showIns="true",
_jc_save_wfdc_flag="dc",
_jc_save_fromDate=_get_yaml()["set"]["station_dates"][0],
_jc_save_toDate=_get_yaml()["set"]["station_dates"][0])
self.urlConf["getCodeImg"]["req_url"] = self.urlConf["getCodeImg"]["req_url"].format(random.random())
self.readImg(self.urlConf["getCodeImg"])
self.randCode = self.getRandCode()

View File

@ -10,6 +10,8 @@ import time
import urllib
from collections import OrderedDict
import collections
from agency.cdn_utils import CDNProxy
from config import urlConf
from config.emailConf import sendEmail
@ -48,6 +50,7 @@ class select:
self.is_download_img = False
self.randCode = ""
self.cdn_list = []
self.buy_ticket_time = ""
def get_ticket_info(self):
"""
@ -64,7 +67,8 @@ class select:
select_refresh_interval = ticket_info_config["select_refresh_interval"]
station_trains = ticket_info_config["set"]["station_trains"]
ticket_black_list_time = ticket_info_config["ticket_black_list_time"]
print "*"*20
print u"*"*20
print u"12306刷票小助手最后更新于2018.2.28请勿作为商业用途交流群号286271084\n"
print u"当前配置:出发站:{0}\n到达站:{1}\n乘车日期:{2}\n坐席:{3}\n是否有票自动提交:{4}\n乘车人:{5}\n刷新间隔:{6}\n候选购买车次:{7}\n僵尸票关小黑屋时长:{8}\n".format\
(
from_station,
@ -77,7 +81,7 @@ class select:
",".join(station_trains),
ticket_black_list_time,
)
print "*"*20
print u"*"*20
return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, ticket_black_list_time
def get_order_request_params(self):
@ -138,8 +142,8 @@ class select:
:return:
"""
today = datetime.date.today()
tomorrow = today+datetime.timedelta(1)
return tomorrow.strftime('%Y-%m-%d')
# tomorrow = today+datetime.timedelta(1)
return today.strftime('%Y-%m-%d')
def callReadImg(self, code_url):
"""
@ -147,7 +151,6 @@ class select:
:param code_url: 验证码url
:return:
"""
print(code_url)
self.login.readImg(code_url=code_url)
self.is_aotu_code = True
@ -183,6 +186,12 @@ class select:
else:
pass
def GetJS(self):
getJSUrl = self.confUrl["GetJS"]
self.httpClint.send(getJSUrl)
odxmfwgUrl = self.confUrl["odxmfwg"]
self.httpClint.send(odxmfwgUrl)
def getPassengerDTOs(self):
"""
获取乘客信息
@ -253,15 +262,17 @@ class select:
break
else:
print (u'正在尝试提交订票...')
self.buy_ticket_time = datetime.datetime.now()
# self.submitOrderRequestFunc(from_station, to_station, self.time())
self.submit_station()
self.getPassengerTicketStr(self._station_seat[j].encode("utf8"))
self.getRepeatSubmitToken()
if not self.user_info: # 修改每次都调用用户接口导致用户接口不能用
self.user_info = self.getPassengerDTOs()
codeImgByOrder = self.confUrl["codeImgByOrder"]
self.login.readImg(codeImgByOrder)
if self.checkOrderInfo(train_no, self._station_seat[j].encode("utf8")):
break
break
else:
pass
else:
@ -305,7 +316,7 @@ class select:
"""
submit_station_url = self.confUrl["submit_station_url"]
data = [('secretStr', urllib.unquote(self.secretStr)), # 字符串加密
('train_date', self.time()), # 出发时间
('train_date', self.station_dates[0]), # 出发时间
('back_train_date', self.time()), # 返程时间
('tour_flag', 'dc'), # 旅途类型
('purpose_codes', 'ADULT'), # 成人票还是学生票
@ -384,7 +395,7 @@ class select:
"""
passengerTicketStrList, oldPassengerStr = self.getPassengerTicketStrListAndOldPassengerStr()
checkOrderInfoUrl = self.confUrl["checkOrderInfoUrl"]
data = OrderedDict()
data = collections.OrderedDict()
data['cancel_flag'] = 2
data['bed_level_order_num'] = "000000000000000000000000000000"
data['passengerTicketStr'] = self.set_type + "," + ",".join(passengerTicketStrList).rstrip("_{0}".format(self.set_type))
@ -422,18 +433,17 @@ class select:
l_time = time.localtime(time.time())
new_train_date = time.strftime("%a %b %d %Y", l_time)
getQueueCountUrl = self.confUrl["getQueueCountUrl"]
data = {
'train_date': str(new_train_date) + " 00:00:00 GMT+0800 (中国标准时间)",
'train_no': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['train_no'],
'stationTrainCode': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['station_train_code'],
'seatType': self.set_type,
'fromStationTelecode': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['from_station'],
'toStationTelecode': self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['to_station'],
'leftTicket': self.get_ticketInfoForPassengerForm()['leftTicketStr'],
'purpose_codes': self.get_ticketInfoForPassengerForm()['purpose_codes'],
'train_location': self.get_ticketInfoForPassengerForm()['train_location'],
'REPEAT_SUBMIT_TOKEN': self.get_token(),
}
data = collections.OrderedDict()
data['train_date'] = str(new_train_date) + " 00:00:00 GMT+0800 (中国标准时间)",
data['train_no'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['train_no'],
data['stationTrainCode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['station_train_code'],
data['seatType'] = self.set_type,
data['fromStationTelecode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['from_station'],
data['toStationTelecode'] = self.get_ticketInfoForPassengerForm()['queryLeftTicketRequestDTO']['to_station'],
data['leftTicket'] = self.get_ticketInfoForPassengerForm()['leftTicketStr'],
data['purpose_codes'] = self.get_ticketInfoForPassengerForm()['purpose_codes'],
data['train_location'] = self.get_ticketInfoForPassengerForm()['train_location'],
data['REPEAT_SUBMIT_TOKEN'] = self.get_token(),
getQueueCountResult = self.httpClint.send(getQueueCountUrl, data)
if "status" in getQueueCountResult and getQueueCountResult["status"] is True:
if "countT" in getQueueCountResult["data"]:
@ -497,15 +507,14 @@ class select:
"dwAll": "N",
"whatsSelect": 1,
"_json_at": "",
"randCode": "",
"choose_seats": "",
"REPEAT_SUBMIT_TOKEN": self.get_token(),
}
try:
if is_node_code:
print(u"正在使用自动识别验证码功能")
for i in range(3):
codeImgByOrder = self.confUrl["codeImgByOrder"]
self.login.readImg(codeImgByOrder)
randCode = self.login.getRandCode()
checkcode = self.checkRandCodeAnsyn(randCode)
if checkcode == 'TRUE':
@ -517,7 +526,9 @@ class select:
print(u"验证码超过限定次数3次放弃此次订票机会!")
else:
print(u"不需要验证码")
time.sleep(0.5)
buy_end_time = (datetime.datetime.now() - self.buy_ticket_time).seconds
print("总共花费时长{0}S".format(buy_end_time))
time.sleep(8-buy_end_time if buy_end_time<8 else 0)
checkQueueOrderResult = self.httpClint.send(checkQueueOrderUrl, data)
if "status" in checkQueueOrderResult and checkQueueOrderResult["status"]:
c_data = checkQueueOrderResult["data"] if "data" in checkQueueOrderResult else {}
@ -670,7 +681,7 @@ class select:
start_time = datetime.datetime.now()
http.cdn = cdn[i].replace("\n", "")
rep = http.send(urls)
if rep and "message" not in rep and (datetime.datetime.now() - start_time).microseconds / 1000 < 300:
if rep and "message" not in rep and (datetime.datetime.now() - start_time).microseconds / 1000 < 200:
self.cdn_list.append(cdn[i].replace("\n", ""))
print(u"所有cdn解析完成...")
@ -707,10 +718,14 @@ class select:
# 5分钟检查一次用户是否登录
self.check_user()
time.sleep(self.select_refresh_interval)
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00":
print u"12306休息时间本程序自动停止,明天早上6点将自动运行"
time.sleep(60 * 60 * 7)
self.call_login()
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00" or time.strftime('%H:%M:%S', time.localtime(time.time())) < "06:00:00":
print(u"12306休息时间本程序自动停止,明天早上6点将自动运行")
while 1:
time.sleep(1)
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "06:00:00":
print(u"休息时间已过,重新开启检票功能")
self.call_login()
break
start_time = datetime.datetime.now()
self.submitOrderRequestImplement(from_station, to_station)
print u"正在第{0}次查询 乘车日期: {1} 车次{2} 查询无票 cdn轮询IP {4} 当前cdn总数{5} 总耗时{3}ms".format(num,

View File

@ -50,10 +50,14 @@ class HTTPClient(object):
"""设置header"""
return {
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
"X-Requested-With": "xmlHttpRequest",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"X-Requested-With": "application/json, text/javascript, */*; q=0.01",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5",
"Referer": "https://kyfw.12306.cn/otn/login/init",
"Accept": "*/*",
"Accept-Encoding": "br, gzip, deflate",
"Origin": "https://kyfw.12306.cn",
"Accept-Language": "zh-cn",
"Connection": "keep-alive",
}
def setHeaders(self, headers):
@ -86,6 +90,14 @@ class HTTPClient(object):
def cdn(self, cdn):
self._cdn = cdn
# def send_socket(self, urls, data=None, **kwargs):
# data = """
# POST {0} HTTP/1.1
# {0}
# """.format(urls["req_url"], self._set_header())
# fack = socket.create_connection(urls["Host"], 443)
# fack.send()
def send(self, urls, data=None, **kwargs):
"""send request to url.If response 200,return response, else return None."""
allow_redirects = False
@ -108,6 +120,7 @@ class HTTPClient(object):
url_host = urls["Host"]
for i in range(urls["re_try"]):
try:
sleep(urls["s_time"]) if "s_time" in urls else sleep(0.001)
requests.packages.urllib3.disable_warnings()
response = self._s.request(method=method,
timeout=2,

BIN
tkcode

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB