Merge branch 'master' into dev

dev
wenxianping 2018-01-24 22:50:22 +08:00
commit b056211587
16 changed files with 452 additions and 145 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
*.html
*.pyc
*.yaml
*.log
idea/

View File

@ -13,7 +13,10 @@
- 配置yaml文件的时候需注意空格和遵循yaml语法格式项目的yaml配置ex
- ticket_config.yaml 配置说明
```
#station_date:出发日期格式ex2018-01-06
#station_date:出发日期改为多日期查询格式ex
- "2018-02-03"
- "2018-02-04"
- "2018-02-05"
#station_trains:过滤车次格式ex
# - "G1353"
# - "G1329"
@ -170,4 +173,21 @@
- 更新请求第三方库
- 优化若干代码,小伙伴尽情的放肆起来
- 2018.1.21跟新
- 修复若干bug
- 合并dev
- 恢复之前因为12306改版引起的订票功能
- 增加派对失败自动取消订单功能
- 优化接口请求规范
- 增加多日期查询请严格按照yaml格式添加 即可
- 注意:如果多日期查询的话,可能查询时间会比较长
- 增加如果排队时间超过一分钟,自动取消订单
- 2018.1.23更新
- 增加若快平台打码yaml新增字段aotu_code_type1=打码兔2=若快 若快注册地址http://www.ruokuai.com/client/index?6726
- 修改is_aotu_code字段为全部是否自动打码字段也就是说字段为rue则全部自动打码为False全部手动打码包括提交订单注意centOs不可设置手动打码
- 修复bug
- 优化抢票功能

82
config/configCommon.py Normal file
View File

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
import os
import time
saleMinDelayDay = 0
saleMaxDelayDay = 59
saleStartTime = "06:00:00"
saleStopTime = "23:00:00"
rushRefreshMinTimeIntval = 2000
rushRefreshMaxTimeIntval = 3600000
rushRefreshTimeIntval = 100
RS_SUC = 0
RS_TIMEOUT = 1
RS_JSON_ERROR = 2
RS_OTHER_ERROR = 3
def getNowTimestamp():
return time.time()
def getMinimumDate():
return time.localtime(getNowTimestamp() + saleMinDelayDay * 24 * 3600)[:3]
def getMaximumDate():
return time.localtime(getNowTimestamp() + saleMaxDelayDay * 24 * 3600)[:3]
def getMinimumTime():
return [int(x) for x in saleStartTime.split(":")]
def getMaximumTime():
return [int(x) for x in saleStopTime.split(":")]
def decMakeDir(func):
def handleFunc(*args, **kwargs):
dirname = func(*args, **kwargs)
if not os.path.exists(dirname):
os.makedirs(dirname)
elif not os.path.isdir(dirname):
pass
return dirname
return func
def getWorkDir():
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@decMakeDir
def getTmpDir():
return os.path.join(getWorkDir(), "tmp")
@decMakeDir
def getLogDir():
return os.path.join(getTmpDir(), "log")
@decMakeDir
def getCacheDir():
return os.path.join(getTmpDir(), "cache")
@decMakeDir
def getVCodeDir():
return os.path.join(getTmpDir(), "vcode")
def getVCodeImageFile(imageName):
return os.path.join(getVCodeDir(), imageName + ".jpg")
def getCacheFile(cacheType):
return os.path.join(getCacheDir(), cacheType + ".cache")

View File

@ -23,7 +23,7 @@ def sendEmail(msg):
host = email_conf["email_conf"]["host"]
s = "{0}".format(msg)
msg = MIMEText(s, 'text', 'utf-8') # 中文需参数utf-8单字节字符不需要
msg = MIMEText(s, 'plain', 'utf-8') # 中文需参数utf-8单字节字符不需要
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = sender
msg['To'] = receiver

61
config/logger.py Normal file
View File

@ -0,0 +1,61 @@
#coding: utf-8
import os
import time
import logging
from config import configCommon
logger = None
loggerHandler = None
dateStr = '' #默认拥有日期后缀
suffix = '' #除了日期外的后缀
def setSuffix(s):
global suffix
suffix = s
def getTodayDateStr():
return time.strftime("%Y-%m-%d", time.localtime(configCommon.getNowTimestamp()))
def setDateStr(s):
global dateStr
dateStr = s
def isAnotherDay(s):
global dateStr
return dateStr != s
def getLogFile():
global dateStr, suffix
rtn = os.path.join(configCommon.getLogDir(), dateStr)
if suffix:
rtn += "_" + suffix
return rtn + ".log"
def log(msg, func = "info"):
global logger
if not logger:
logger = logging.getLogger()
logger.setLevel(logging.INFO)
todayStr = getTodayDateStr()
if isAnotherDay(todayStr):
setDateStr(todayStr)
logger.removeHandler(loggerHandler)
fh = logging.FileHandler(getLogFile())
fm = logging.Formatter(u'[%(asctime)s][%(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)')
fh.setFormatter(fm)
logger.addHandler(fh)
levels = {
"debug": logger.debug,
"info": logger.info,
"warning": logger.warning,
"error": logger.error,
"critical": logger.critical
}
levels[func](msg)

View File

@ -1,6 +1,5 @@
# -*- coding: utf8 -*-
__author__ = 'MR.wen'
import os
import yaml
import PyQt5

View File

@ -22,6 +22,7 @@
#ticke_peoples: 乘客
#damatu打码兔账号用于自动登录
#is_aotu_code是否自动打码如果选择Ture,则调用打码兔打码,默认不使用打码兔
#aotu_code_type 1为打码兔2为若快
#is_email: 是否需要邮件通知 ex: True or False 切记邮箱加完一定到config目录下测试emailConf功能是否正常
#邮箱配置 列举163
@ -39,9 +40,22 @@
set:
station_date: "2018-02-12"
station_dates:
# - "2018-01-27"
# - "2018-01-28"
- "2018-02-09"
- "2018-02-10"
# - "2018-02-09"
station_trains:
- "G4741"
- "G2365"
- "G1371"
- "G1337"
- "G1377"
- "G1329"
# - "G1302"
# - "G1372"
# - "G1326"
# - "K4300"
# - "K5226"
# - "K7772"
@ -51,35 +65,36 @@ set:
# - "G1373"
# - "G1363"
# - "G4933"
from_station: "昆山"
to_station: "长沙"
from_station: "上海"
to_station: "邵阳"
set_type:
- "二等座"
is_more_ticket: True
ticke_peoples:
- "宋倩倩"
- "文贤平"
# - "彭淑杰"
12306count:
# - uesr: ""
# - pwd: "apple1995"
- uesr: ""
- pwd: "songyu1995"
- uesr: "931128603@qq.com"
- pwd: "QWERTY"
select_refresh_interval: 0.1
expect_refresh_interval: 0.3
select_refresh_interval: 0.5
expect_refresh_interval: 0.1
ticket_black_list_time: 3
is_aotu_code: False
is_aotu_code: True
aotu_code_type: 2
#enable_proxy: False
damatu:
uesr: ""
pwd: "wen1995"
uesr: "931128603"
pwd: "qazWSX1995"
email_conf:
is_email: False
email: "@qq.com "
notice_email_list: "@qq.com"
username: ""
is_email: True
email: "931128603@qq.com "
notice_email_list: "61995120@qq.com"
username: "931128603"
password: "xwopwxbkupbqbfgb"
host: "smtp.qq.com"

View File

@ -84,6 +84,11 @@ urls = {
"initNoCompleteUrl": {
"req_url": "https://kyfw.12306.cn/otn/queryOrder/initNoComplete",
"req_type": "post"
},
"cancelNoCompleteMyOrder": {
"req_url": "https://kyfw.12306.cn/otn/queryOrder/cancelNoCompleteMyOrder",
"req_type": "post"
}
}

View File

@ -22,7 +22,7 @@ class DamatuApi():
KEY = 'ca9507e17e8d5ddf7c57cd18d8d33010'
HOST = 'http://api.dama2.com:7766/app/'
def __init__(self, username, password, file_path):
def __init__(self, username, password, file_path=None):
self.username = username
self.password = password
self.file_path = file_path
@ -108,13 +108,10 @@ class DamatuApi():
return jres['ret']
def main(self):
balance = self.getBalance()
if int(balance) > 40:
result = self.decode(287)
img_code = result.replace('|', ',') if not isinstance(result, int) else ""
return img_code
else:
raise balanceException('余额不足,当前余额为: {}'.format(balance))
result = self.decode(287)
img_code = result.replace('|', ',') if not isinstance(result, int) else ""
print("验证码识别坐标为{0}".format(img_code))
return img_code
# # 调用类型实例:
# # 1.实例化类型 参数是打码兔用户账号和密码

55
damatuCode/ruokuai.py Normal file
View File

@ -0,0 +1,55 @@
# coding:utf-8
import requests
from hashlib import md5
class RClient(object):
def __init__(self, username, password):
self.username = username
self.password = md5(password).hexdigest()
self.soft_id = '96061'
self.soft_key = '6facb9da7bb645ad9c4a229464b2cf89'
self.base_params = {
'username': self.username,
'password': self.password,
'softid': self.soft_id,
'softkey': self.soft_key,
}
self.headers = {
'Connection': 'Keep-Alive',
'Expect': '100-continue',
'User-Agent': 'ben',
}
def rk_create(self, im, im_type, timeout=60):
"""
im: 图片字节
im_type: 题目类型
"""
params = {
'typeid': im_type,
'timeout': timeout,
}
params.update(self.base_params)
files = {'image': ('a.jpg', im)}
r = requests.post('http://api.ruokuai.com/create.json', data=params, files=files, headers=self.headers)
return r.json()
def rk_report_error(self, im_id):
"""
im_id:报错题目的ID
"""
params = {
'id': im_id,
}
params.update(self.base_params)
r = requests.post('http://api.ruokuai.com/reporterror.json', data=params, headers=self.headers)
return r.json()
if __name__ == '__main__':
rc = RClient('931128603', 'qazWSX1995',)
im = open('tkcode', 'rb').read()
print rc.rk_create(im, 6113)

View File

@ -9,15 +9,19 @@ from time import sleep
from config.ticketConf import _get_yaml
from PIL import Image
from damatuCode.damatuWeb import DamatuApi
from damatuCode.ruokuai import RClient
from myException.UserPasswordException import UserPasswordException
from myException.balanceException import balanceException
from myUrllib import myurllib2
class GoLogin:
def __init__(self, httpClint, urlConf):
def __init__(self, httpClint, urlConf, is_aotu_code, aotu_code_type):
self.httpClint = httpClint
self.randCode = ""
self.urlConf = urlConf
self.is_aotu_code = is_aotu_code
self.aotu_code_type = aotu_code_type
def cookietp(self):
print("正在获取cookie")
@ -28,7 +32,7 @@ class GoLogin:
# for index, c in enumerate(myurllib2.cookiejar):
# stoidinput(c)
def readImg(self):
def readImg(self, code_url):
"""
增加手动打码只是登录接口完全不用担心提交订单效率
思路
@ -38,28 +42,39 @@ class GoLogin:
:return:
"""
print ("下载验证码...")
codeimgUrl = self.urlConf["getCodeImg"]["req_url"]
codeimgUrl = code_url
img_path = './tkcode'
result = self.httpClint.send(codeimgUrl)
result = self.httpClint.send(codeimgUrl, is_logger=False)
try:
open(img_path, 'wb').write(result)
if _get_yaml()["is_aotu_code"]:
self.randCode = DamatuApi(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"], img_path).main()
if self.is_aotu_code:
if self.aotu_code_type == 1:
return DamatuApi(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"], img_path).main()
elif self.aotu_code_type == 2:
rc = RClient(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"])
im = open('./tkcode', 'rb').read()
Result = rc.rk_create(im, 6113)
if "Result" in Result:
return self.codexy(Ofset=",".join(list(Result["Result"])), is_raw_input=False)
else:
if "Error" in Result and Result["Error"]:
print Result["Error"]
return ""
else:
img = Image.open('./tkcode')
img.show()
self.codexy()
return self.codexy()
except OSError as e:
print (e)
pass
return ""
def codexy(self):
def codexy(self, Ofset=None, is_raw_input=True):
"""
获取验证码
:return: str
"""
Ofset = raw_input("请输入验证码: ")
if is_raw_input:
Ofset = raw_input("请输入验证码: ")
select = Ofset.split(',')
post = []
offsetsX = 0 # 选择的答案的left值,通过浏览器点击8个小图的中点得到的,这样基本没问题
@ -93,7 +108,9 @@ class GoLogin:
pass
post.append(offsetsX)
post.append(offsetsY)
self.randCode = str(post).replace(']', '').replace('[', '').replace("'", '').replace(' ', '')
randCode = str(post).replace(']', '').replace('[', '').replace("'", '').replace(' ', '')
print("验证码识别坐标为{0}".format(randCode))
return randCode
def auth(self):
"""认证"""
@ -149,7 +166,7 @@ class GoLogin:
if messages.find("密码输入错误") is not -1:
raise UserPasswordException("{0}".format(messages))
else:
print ("登录失败: {0}".format("".join(tresult)))
print ("登录失败: {0}".format(messages))
print ("尝试重新登陆")
return False
else:
@ -166,11 +183,16 @@ class GoLogin:
uamauthclientUrl = self.urlConf["uamauthclient"]["req_url"]
data = {"tk": uamtk}
uamauthclientResult = self.httpClint.send(uamauthclientUrl, data)
if "result_code" in uamauthclientResult and uamauthclientResult["result_code"] == 0:
print("欢迎 {} 登录".format(uamauthclientResult["username"]))
return True
if uamauthclientResult:
if "result_code" in uamauthclientResult and uamauthclientResult["result_code"] == 0:
print("欢迎 {} 登录".format(uamauthclientResult["username"]))
return True
else:
return False
else:
return False
self.httpClint.send(uamauthclientUrl, data)
url = self.urlConf["getUserInfo"]["req_url"]
self.httpClint.send(url)
def go_login(self):
"""
@ -179,19 +201,25 @@ class GoLogin:
:param passwd: 密码
:return:
"""
if self.is_aotu_code and self.aotu_code_type == 1:
balance = DamatuApi(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"]).getBalance()
if int(balance) < 40:
raise balanceException('余额不足,当前余额为: {}'.format(balance))
user, passwd = _get_yaml()["set"]["12306count"][0]["uesr"], _get_yaml()["set"]["12306count"][1]["pwd"]
if not user or not passwd:
raise UserPasswordException("温馨提示: 用户名或者密码为空,请仔细检查")
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.readImg()
self.randCode = self.readImg(self.urlConf["getCodeImg"]["req_url"])
login_num += 1
self.auth()
if self.codeCheck():
uamtk = self.baseLogin(user, passwd)
if uamtk:
if self.getUserName(uamtk):
break
self.getUserName(uamtk)
break
def logout(self):
url = 'https://kyfw.12306.cn/otn/login/loginOut'

View File

@ -1,17 +1,14 @@
# -*- coding=utf-8 -*-
import json
import datetime
import random
import re
import socket
import urllib
import sys
import time
from collections import OrderedDict
from config import urlConf
from init import login
from config.emailConf import sendEmail
from config.ticketConf import _get_yaml
from damatuCode.damatuWeb import DamatuApi
@ -29,7 +26,9 @@ sys.setdefaultencoding('utf-8')
class select:
def __init__(self):
self.from_station, self.to_station, self.station_date, self._station_seat, self.is_more_ticket, self.ticke_peoples, self.select_refresh_interval, self.station_trains, self.expect_refresh_interval, self.ticket_black_list_time = self.get_ticket_info()
self.from_station, self.to_station, self.station_dates, self._station_seat, self.is_more_ticket, self.ticke_peoples, self.select_refresh_interval, self.station_trains, self.expect_refresh_interval, self.ticket_black_list_time = self.get_ticket_info()
self.is_aotu_code = _get_yaml()["is_aotu_code"]
self.aotu_code_type = _get_yaml()["aotu_code_type"]
self.order_request_params = {} # 订单提交时的参数
self.ticketInfoForPassengerForm = {} # 初始化当前页面参数
self.current_seats = {} # 席别信息
@ -41,6 +40,7 @@ class select:
self.is_check_user = dict()
self.httpClint = HTTPClient()
self.confUrl = urlConf.urls
self.login = GoLogin(self.httpClint, self.confUrl, self.is_aotu_code, self.aotu_code_type)
def get_ticket_info(self):
"""
@ -50,7 +50,7 @@ class select:
ticket_info_config = _get_yaml()
from_station = ticket_info_config["set"]["from_station"].encode("utf8")
to_station = ticket_info_config["set"]["to_station"].encode("utf8")
station_date = ticket_info_config["set"]["station_date"].encode("utf8")
station_dates = ticket_info_config["set"]["station_dates"]
set_type = ticket_info_config["set"]["set_type"]
is_more_ticket = ticket_info_config["set"]["is_more_ticket"]
ticke_peoples = ticket_info_config["set"]["ticke_peoples"]
@ -63,7 +63,7 @@ class select:
(
from_station,
to_station,
station_date,
station_dates,
",".join(set_type),
is_more_ticket,
",".join(ticke_peoples),
@ -73,7 +73,7 @@ class select:
ticket_black_list_time,
)
print "*"*20
return from_station, to_station, station_date, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, expect_refresh_interval, ticket_black_list_time
return from_station, to_station, station_dates, set_type, is_more_ticket, ticke_peoples, select_refresh_interval, station_trains, expect_refresh_interval, ticket_black_list_time
def get_order_request_params(self):
return self.order_request_params
@ -141,7 +141,7 @@ class select:
获取提交车票请求token
:return: token
"""
initdc_url = self.confUrl["initdc_url"]["req+url"]
initdc_url = self.confUrl["initdc_url"]["req_url"]
initdc_result = self.httpClint.send(initdc_url)
token_name = re.compile(r"var globalRepeatSubmitToken = '(\S+)'")
ticketInfoForPassengerForm_name = re.compile(r'var ticketInfoForPassengerForm=(\{.+\})?')
@ -173,7 +173,7 @@ class select:
'normal_passengers']:
normal_passengers = jsonData['data']['normal_passengers']
_normal_passenger = [normal_passengers[i] for i in range(len(normal_passengers))if normal_passengers[i]["passenger_name"] in self.ticke_peoples]
return _normal_passenger if _normal_passenger else normal_passengers[0] # 如果配置乘车人没有在账号,则默认返回第一个用户
return _normal_passenger if _normal_passenger else [normal_passengers[0]] # 如果配置乘车人没有在账号,则默认返回第一个用户
else:
if 'data' in jsonData and 'exMsg' in jsonData['data'] and jsonData['data']['exMsg']:
print(jsonData['data']['exMsg'])
@ -185,9 +185,9 @@ class select:
def submitOrderRequestFunc(self, from_station, to_station, station_date=None):
select_url = self.confUrl["select_url"]["req_url"].format(
self.station_date if station_date is None else station_date, from_station, to_station)
station_ticket = self.httpClint.send(select_url)
return station_ticket
station_date, from_station, to_station)
station_ticket = self.httpClint.send(select_url, is_logger=False)
return json.loads(station_ticket)
def submitOrderRequestImplement(self, from_station, to_station,):
"""
@ -204,44 +204,45 @@ class select:
} 参照station_seat()方法
:return:
"""
station_ticket = self.submitOrderRequestFunc(from_station, to_station)
value = station_ticket['data']
if not value:
print ('{0}-{1} 车次坐席查询为空...'.format(self.from_station, self.to_station))
else:
if value['result']:
for i in value['result']:
ticket_info = i.split('|')
if ticket_info[11] == "Y" and ticket_info[1].encode("utf8") == "预订": # 筛选未在开始时间内的车次
for j in range(len(self._station_seat)):
is_ticket_pass = ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))]
# print self._station_seat[j]
if is_ticket_pass != '' and is_ticket_pass != '' and ticket_info[3] in self.station_trains and is_ticket_pass != '*': # 过滤有效目标车次
# tiket_values = [k for k in value['map'].values()]
self.secretStr = ticket_info[0]
train_no = ticket_info[3]
print ('车次: ' + train_no + ' 始发车站: ' + self.from_station + ' 终点站: ' +
self.to_station + ' ' + self._station_seat[j].encode("utf8") + ':' + ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))])
if self.ticket_black_list.has_key(train_no) and (datetime.datetime.now() - self.ticket_black_list[train_no]).seconds/60 < int(self.ticket_black_list_time):
print("该车次{} 正在被关小黑屋,跳过此车次".format(train_no))
break
else:
print ('正在尝试提交订票...')
# 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()
if self.checkOrderInfo(train_no, self._station_seat[j].encode("utf8")):
break
else:
pass
else:
pass
time.sleep(self.expect_refresh_interval)
station_tickets = [self.submitOrderRequestFunc(from_station, to_station, station_date) for station_date in self.station_dates]
for station_ticket in station_tickets:
value = station_ticket['data']
if not value:
print ('{0}-{1} 车次坐席查询为空...'.format(self.from_station, self.to_station))
else:
print "车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket)
if value['result']:
for i in value['result']:
ticket_info = i.split('|')
if ticket_info[11] == "Y" and ticket_info[1].encode("utf8") == "预订": # 筛选未在开始时间内的车次
for j in range(len(self._station_seat)):
is_ticket_pass = ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))]
# print self._station_seat[j]
if is_ticket_pass != '' and is_ticket_pass != '' and ticket_info[3] in self.station_trains and is_ticket_pass != '*': # 过滤有效目标车次
# tiket_values = [k for k in value['map'].values()]
self.secretStr = ticket_info[0]
train_no = ticket_info[3]
print ('车次: ' + train_no + ' 始发车站: ' + self.from_station + ' 终点站: ' +
self.to_station + ' ' + self._station_seat[j].encode("utf8") + ':' + ticket_info[self.station_seat(self._station_seat[j].encode("utf8"))])
if self.ticket_black_list.has_key(train_no) and (datetime.datetime.now() - self.ticket_black_list[train_no]).seconds/60 < int(self.ticket_black_list_time):
print("该车次{} 正在被关小黑屋,跳过此车次".format(train_no))
break
else:
print ('正在尝试提交订票...')
# 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()
if self.checkOrderInfo(train_no, self._station_seat[j].encode("utf8")):
break
else:
pass
else:
pass
time.sleep(self.expect_refresh_interval)
else:
print "车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket)
def check_user(self):
"""
@ -249,11 +250,11 @@ class select:
:return:
"""
check_user_url = self.confUrl["check_user_url"]["req_url"]
data = dict(_json_att=None)
data = {"_json_att": ""}
check_user = self.httpClint.send(check_user_url, data)
check_user_flag = check_user['data']['flag']
if check_user_flag is True:
return True
self.is_check_user["user_time"] = datetime.datetime.now()
else:
if check_user['messages']:
print ('用户检查失败:%s可能未登录可能session已经失效' % check_user['messages'][0])
@ -464,11 +465,7 @@ class select:
print("正在使用自动识别验证码功能")
checkRandCodeAnsyn = self.confUrl["checkRandCodeAnsyn"]["req_url"]
codeImgByOrder = self.confUrl["codeImgByOrder"]["req_url"]
result = self.httpClint.send(codeImgByOrder)
img_path = './tkcode'
open(img_path, 'wb').write(result)
randCode = DamatuApi(_get_yaml()["damatu"]["uesr"], _get_yaml()["damatu"]["pwd"],
img_path).main()
randCode = self.login.readImg(codeImgByOrder)
randData = {
"randCode": randCode,
"rand": "randp",
@ -516,6 +513,9 @@ class select:
num += 1
if num > 30:
print("超出排队时间,自动放弃,正在重新刷票")
order_id = self.queryMyOrderNoComplete() # 排队失败,自动取消排队订单
if order_id:
self.cancelNoCompleteMyOrder(order_id)
break
try:
data = {"random": _random, "tourFlag": "dc"}
@ -526,8 +526,8 @@ class select:
if queryOrderWaitTimeResult:
if "status" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["status"]:
if "orderId" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["orderId"] is not None:
sendEmail("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306访问未完成订单在30分钟内完成支付".format(queryOrderWaitTimeResult["data"]["orderId"]))
raise ticketIsExitsException("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306访问未完成订单在30分钟内完成支付".format(queryOrderWaitTimeResult["data"]["orderId"]))
sendEmail("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306访问未完成订单在30分钟内完成支付".format(queryOrderWaitTimeResult["data"]["orderId"]))
raise ticketIsExitsException("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306访问未完成订单在30分钟内完成支付".format(queryOrderWaitTimeResult["data"]["orderId"]))
elif "msg" in queryOrderWaitTimeResult["data"] and queryOrderWaitTimeResult["data"]["msg"]:
print queryOrderWaitTimeResult["data"]["msg"]
break
@ -538,14 +538,10 @@ class select:
elif "messages" in queryOrderWaitTimeResult and queryOrderWaitTimeResult["messages"]:
print("排队等待失败: " + queryOrderWaitTimeResult["messages"])
else:
print("{}次排队中,请耐心等待".format(num))
print("{}次排队中,请耐心等待".format(num+1))
else:
print("排队中")
time.sleep(1)
order_id = self.queryMyOrderNoComplete() # 尝试查看订单列表,如果有订单,则判断成功,不过一般可能性不大
if order_id:
sendEmail("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306访问未完成订单在30分钟内完成支付".format(order_id))
raise ticketIsExitsException("恭喜您订票成功,订单号为:{0}, 请立即打开浏览器登录12306访问未完成订单在30分钟内完成支付".format(order_id))
time.sleep(2)
else:
print(ticketNumOutException("订单提交失败!,正在重新刷票"))
@ -557,7 +553,7 @@ class select:
"""
self.initNoComplete()
queryMyOrderNoCompleteUrl = self.confUrl["queryMyOrderNoCompleteUrl"]["req_url"]
data = {"_json_att": None}
data = {"_json_att": ""}
try:
queryMyOrderNoCompleteResult = self.httpClint.send(queryMyOrderNoCompleteUrl, data)
except ValueError:
@ -584,10 +580,31 @@ class select:
获取订单前需要进入订单列表页获取订单列表页session
:return:
"""
self.httpClint.set_cookies(acw_tc="AQAAAEnFJnekLwwAtGHjZZCr79B6dpXk", current_captcha_type="Z")
initNoCompleteUrl = self.confUrl["initNoCompleteUrl"]["req_url"]
data = {"_json_att": None}
data = {"_json_att": ""}
self.httpClint.send(initNoCompleteUrl, data)
def cancelNoCompleteMyOrder(self, sequence_no):
"""
取消订单
:param sequence_no: 订单编号
:return:
"""
cancelNoCompleteMyOrderUrl = self.confUrl["cancelNoCompleteMyOrder"]["req_url"]
cancelNoCompleteMyOrderData = {
"sequence_no": sequence_no,
"cancel_flag": "cancel_order",
"_json_att": ""
}
cancelNoCompleteMyOrderResult = self.httpClint.send(cancelNoCompleteMyOrderUrl, cancelNoCompleteMyOrderData)
if "data" in cancelNoCompleteMyOrderResult and "existError" in cancelNoCompleteMyOrderResult["data"] and cancelNoCompleteMyOrderResult["data"]["existError"] == "N":
print("排队超时,已为您自动取消订单,订单编号: {0}".format(sequence_no))
time.sleep(2)
return True
else:
print("排队超时,取消订单失败, 订单号{0}".format(sequence_no))
# def call_submit_ticket(self, function_name=None):
# """
# 订票失败回调方法默认执行submitOrderRequest()
@ -600,21 +617,27 @@ class select:
# else:
# self.submitOrderRequest()
def call_login(self):
"""登录回调方法"""
login = GoLogin(self.httpClint, self.confUrl)
login.go_login()
def call_login(self, auth=False):
"""
登录回调方法
:return:
"""
if auth:
return self.login.auth()
else:
self.login.go_login()
def main(self):
self.call_login()
from_station, to_station = self.station_table(self.from_station, self.to_station)
# if self.leftTicketLog(from_station, to_station):
self.check_user()
time.sleep(0.1)
num = 1
while 1:
try:
num += 1
if "user_time" in self.is_check_user and (datetime.datetime.now() - self.is_check_user["user_time"]).seconds/60 > 10:
# 十分钟调用一次检查用户是否登录
if "user_time" in self.is_check_user and (datetime.datetime.now() - self.is_check_user["user_time"]).seconds/60 > 5:
# 5分钟检查一次用户是否登录
self.check_user()
time.sleep(self.select_refresh_interval)
if time.strftime('%H:%M:%S', time.localtime(time.time())) > "23:00:00":
@ -623,7 +646,7 @@ class select:
self.call_login()
start_time = datetime.datetime.now()
self.submitOrderRequestImplement(from_station, to_station)
print "正在第{0}次查询 乘车日期: {1} 车次{2} 查询无票 代理设置 无 总耗时{3}ms".format(num, self.station_date, ",".join(self.station_trains), (datetime.datetime.now()-start_time).microseconds/1000)
print "正在第{0}次查询 乘车日期: {1} 车次{2} 查询无票 代理设置 无 总耗时{3}ms".format(num, ",".join(self.station_dates), ",".join(self.station_trains), (datetime.datetime.now()-start_time).microseconds/1000)
except PassengerUserException as e:
print e.message
break
@ -647,13 +670,11 @@ class select:
except KeyError as e:
print(e.message)
except TypeError as e:
print(e.message)
print("12306接口无响应正在重试 {0}".format(e.message))
except socket.error as e:
print(e.message)
if __name__ == '__main__':
login()
# a = select('上海', '北京')

View File

@ -2,9 +2,12 @@
import datetime
import json
import socket
from time import sleep
import requests
import sys
from config import logger
class HTTPClient(object):
@ -57,6 +60,10 @@ class HTTPClient(object):
self._s.headers.update(headers)
return self
def resetHeaders(self):
self._s.headers.clear()
self._s.headers.update(self._set_header())
def getHeadersHost(self):
return self._s.headers["Host"]
@ -71,26 +78,41 @@ class HTTPClient(object):
self._s.headers.update({"Referer": referer})
return self
def send(self, url, data=None, **kwargs):
def send(self, url, data=None, is_logger=True, **kwargs):
"""send request to url.If response 200,return response, else return None."""
method = "post"if data else "get"
response = self._s.request(method=method,
url=url,
data=data,
**kwargs)
try:
if response.content:
return json.loads(response.content) if method == "post" else response.content
else:
return ""
except ValueError as e:
if e.message == "No JSON object could be decoded":
print("12306接口无响应正在重试")
else:
print(e.message)
except KeyError as e:
print(e.message)
except TypeError as e:
print(e.message)
except socket.error as e:
print(e.message)
allow_redirects = False
error_data = {"code": 99999, "message": "重试次数达到上限"}
if data:
method = "post"
self.setHeaders({"Content-Length": "{0}".format(len(data))})
else:
method = "get"
self.resetHeaders()
if is_logger:
logger.log(
u"url: {0}\n入参: {1}\n请求方式: {2}\n".format(url,data,method,))
for i in range(10):
try:
response = self._s.request(method=method,
timeout=10,
url=url,
data=data,
allow_redirects=allow_redirects,
**kwargs)
if response.status_code == 200:
if response.content:
if is_logger:
logger.log(
u"出参:{0}".format(response.content))
return json.loads(response.content) if method == "post" else response.content
else:
logger.log(
u"url: {} 返回参数为空".format(url))
return error_data
else:
sleep(0.1)
except (requests.exceptions.Timeout, requests.exceptions.ReadTimeout, requests.exceptions.ConnectionError):
pass
except socket.error:
pass
return error_data

BIN
tkcode

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
tmp/__init__.py Normal file
View File

0
tmp/log/__init__.py Normal file
View File