fix login

pull/569/head
文贤平 2019-09-03 14:54:01 +08:00
parent 8a68530f38
commit 499f0fbda7
7 changed files with 181 additions and 117 deletions

View File

@ -19,14 +19,15 @@ STATION_DATES = [
# 填入需要购买的车次(list)"G1353"
STATION_TRAINS = [
"",
"G6142",
"G6174",
]
# 出发城市,比如深圳北,就填深圳就搜得到
FROM_STATION = ""
FROM_STATION = "深圳北"
# 到达城市 比如深圳北,就填深圳就搜得到
TO_STATION = ""
TO_STATION = "隆回"
# 座位(list) 多个座位ex:
# "商务座",
@ -39,23 +40,24 @@ TO_STATION = ""
# "无座",
# "动卧",
SET_TYPE = [
"",
"二等座",
]
# 当余票小于乘车人,如果选择优先提交,则删减联系人和余票数一致在提交
# bool
IS_MORE_TICKET = False
IS_MORE_TICKET = True
# 乘车人(list) 多个乘车人ex:
# - "张三"
# - "李四"
TICKET_PEOPLES = [
"",
"文贤平",
"李梦云",
]
# 12306登录账号
USER = ""
PWD = ""
USER = "931128603@qq.com"
PWD = "QWERTY"
# 加入小黑屋时间默认为5分钟此功能为了防止僵尸票导致一直下单不成功错过正常的票
TICKET_BLACK_LIST_TIME = 5
@ -77,12 +79,12 @@ IS_AUTO_CODE = True
# password: "授权码"
# host: "smtp.qq.com"
EMAIL_CONF = {
"IS_MAIL": False,
"email": "",
"notice_email_list": "",
"username": "",
"password": "",
"host": "",
"IS_MAIL": True,
"email": "931128603@qq.com",
"notice_email_list": "931128603@qq.com",
"username": "931128603@qq.com",
"password": "lwvgfrcydzyvbfjf",
"host": "smtp.qq.com",
}
# 是否开启 pushbear 微信提醒, 使用前需要前往 http://pushbear.ftqq.com 扫码绑定获取 send_key 并关注获得抢票结果通知的公众号

View File

@ -139,7 +139,7 @@ urls = {
"is_json": False,
},
"getDevicesId": { # 获取用户信息
"req_url": "/otn/HttpZF/logdevice?algID=YD9Iw7QM4u&hashCode=d7vhohETY2f2TpCef2MPZFvngSXyZU71bSRYvkHTkbc&FMQw=0&q4f3=zh-CN&VySQ=FGFC5l5w_W3LWESYu2oI4qV2jIzzka61&VPIf=1&custID=133&VEek=unknown&dzuS=0&yD16=0&EOQP=c227b88b01f5c513710d4b9f16a5ce52&lEnu=3232235624&jp76=52d67b2a5aa5e031084733d5006cc664&hAqN=MacIntel&platform=WEB&ks0Q=d22ca0b81584fbea62237b14bd04c866&TeRS=831x1440&tOHY=24xx900x1440&Fvje=i1l1o1s1&q5aJ=-8&wNLf=99115dfb07133750ba677d055874de87&0aew=Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_13_4)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/76.0.3809.132%20Safari/537.36&E3gR=ab86d46d16b9293beca4799ff15c5db1&timestamp={0}",
"req_url": "/otn/HttpZF/logdevice",
"req_type": "get",
"Referer": "https://kyfw.12306.cn/otn/passport?redirect=/otn/",
"Host": "kyfw.12306.cn",

View File

@ -1,9 +1,13 @@
# -*- coding=utf-8 -*-
import copy
import json
import random
import re
import time
from collections import OrderedDict
from time import sleep
import TickerConfig
from config.urlConf import urls
from inter.GetPassCodeNewOrderAndLogin import getPassCodeNewOrderAndLogin1
from inter.GetRandCode import getRandCode
from inter.LoginAysnSuggest import loginAysnSuggest
@ -119,6 +123,7 @@ class GoLogin:
:return:
"""
user, passwd = TickerConfig.USER, TickerConfig.PWD
self.request_device_id()
if not user or not passwd:
raise UserPasswordException(u"温馨提示: 用户名或者密码为空,请仔细检查")
login_num = 0
@ -142,3 +147,137 @@ class GoLogin:
loginAysnSuggest(self.session, username=user, password=passwd)
login_num += 1
break
def request_device_id(self):
"""
获取加密后的浏览器特征 ID
:return:
"""
params = {"algID": self.request_alg_id(), "timestamp": int(time.time() * 1000)}
params = dict(params, **self._get_hash_code_params())
response = self.session.httpClint.send(urls.get("getDevicesId"), params=params)
if response.find('callbackFunction') >= 0:
result = response[18:-2]
try:
result = json.loads(result)
self.session.httpClint.set_cookies({
'RAIL_EXPIRATION': result.get('exp'),
'RAIL_DEVICEID': result.get('dfp'),
})
except:
return False
def request_alg_id(self):
response = self.session.httpClint.send(urls.get("GetJS"))
result = re.search(r'algID\\x3d(.*?)\\x26', response)
try:
return result.group(1)
except (IndexError, AttributeError) as e:
pass
return ""
def _get_hash_code_params(self):
from collections import OrderedDict
data = {
'adblock': '0',
'browserLanguage': 'en-US',
'cookieEnabled': '1',
'custID': '133',
'doNotTrack': 'unknown',
'flashVersion': '0',
'javaEnabled': '0',
'jsFonts': 'c227b88b01f5c513710d4b9f16a5ce52',
'localCode': '3232236206',
'mimeTypes': '52d67b2a5aa5e031084733d5006cc664',
'os': 'MacIntel',
'platform': 'WEB',
'plugins': 'd22ca0b81584fbea62237b14bd04c866',
'scrAvailSize': str(random.randint(500, 1000)) + 'x1920',
'srcScreenSize': '24xx1080x1920',
'storeDb': 'i1l1o1s1',
'timeZone': '-8',
'touchSupport': '99115dfb07133750ba677d055874de87',
'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.' + str(
random.randint(
5000, 7000)) + '.0 Safari/537.36',
'webSmartID': 'f4e3b7b14cc647e30a6267028ad54c56',
}
data_trans = {
'browserVersion': 'd435',
'touchSupport': 'wNLf',
'systemLanguage': 'e6OK',
'scrWidth': 'ssI5',
'openDatabase': 'V8vl',
'scrAvailSize': 'TeRS',
'hasLiedResolution': '3neK',
'hasLiedOs': 'ci5c',
'timeZone': 'q5aJ',
'userAgent': '0aew',
'userLanguage': 'hLzX',
'jsFonts': 'EOQP',
'scrAvailHeight': '88tV',
'browserName': '-UVA',
'cookieCode': 'VySQ',
'online': '9vyE',
'scrAvailWidth': 'E-lJ',
'flashVersion': 'dzuS',
'scrDeviceXDPI': '3jCe',
'srcScreenSize': 'tOHY',
'storeDb': 'Fvje',
'doNotTrack': 'VEek',
'mimeTypes': 'jp76',
'sessionStorage': 'HVia',
'cookieEnabled': 'VPIf',
'os': 'hAqN',
'hasLiedLanguages': 'j5po',
'hasLiedBrowser': '2xC5',
'webSmartID': 'E3gR',
'appcodeName': 'qT7b',
'javaEnabled': 'yD16',
'plugins': 'ks0Q',
'appMinorVersion': 'qBVW',
'cpuClass': 'Md7A',
'indexedDb': '3sw-',
'adblock': 'FMQw',
'localCode': 'lEnu',
'browserLanguage': 'q4f3',
'scrHeight': '5Jwy',
'localStorage': 'XM7l',
'historyList': 'kU5z',
'scrColorDepth': "qmyu"
}
data = OrderedDict(data)
d = ''
params = {}
for key, item in data.items():
d += key + item
key = data_trans[key] if key in data_trans else key
params[key] = item
d_len = len(d)
d_f = int(d_len / 3) if d_len % 3 == 0 else int(d_len / 3) + 1
if d_len >= 3:
d = d[d_f:2 * d_f] + d[2 * d_f:d_len] + d[0: d_f]
d_len = len(d)
d_f = int(d_len / 3) if d_len % 3 == 0 else int(d_len / 3) + 1
if d_len >= 3:
d = d[2 * d_f:d_len] + d[0: d_f] + d[1 * d_f: 2 * d_f]
d = self._encode_data_str_v2(d)
d = self._encode_data_str_v2(d)
d = self._encode_data_str_v2(d)
data_str = self._encode_string(d)
params['hashCode'] = data_str
return params
def _encode_data_str_v2(self, d):
b = len(d)
if b % 2 == 0:
return d[b // 2: b] + d[0:b // 2]
else:
return d[b // 2 + 1:b] + d[b // 2] + d[0:b // 2]
def _encode_string(self, str):
import hashlib
import base64
result = base64.b64encode(hashlib.sha256(str.encode()).digest()).decode()
return result.replace('+', '-').replace('/', '_').replace('=', '')

View File

@ -46,6 +46,7 @@ class select:
self.passengerTicketStrByAfterLate = ""
self.oldPassengerStr = ""
self.set_type = ""
self.flag = True
@staticmethod
def get_ticket_info():
@ -144,7 +145,7 @@ class select:
self.cdn_certification()
l = liftTicketInit(self)
l.reqLiftTicketInit()
getDrvicesID(self)
# getDrvicesID(self)
self.call_login()
check_user = checkUser(self)
t = threading.Thread(target=check_user.sendCheckUser)
@ -238,7 +239,7 @@ class select:
c.sendChechFace()
else:
random_time = round(random.uniform(sleep_time_s, sleep_time_t), 2)
nateMsg = ' 候补无资格' if TickerConfig.ORDER_TYPE == 2 else ""
nateMsg = ' 无候补机会' if TickerConfig.ORDER_TYPE == 2 else ""
print(f"正在第{num}次查询 随机停留时长:{random_time} 乘车日期: {','.join(TickerConfig.STATION_DATES)} 车次:{'.'.join(TickerConfig.STATION_TRAINS)} 下单无票{nateMsg} 耗时:{(datetime.datetime.now() - now).microseconds / 1000}ms")
time.sleep(random_time)
except PassengerUserException as e:

View File

@ -49,6 +49,18 @@ class query:
def check_is_need_train(self, ticket_info):
return ticket_info[3] in self.station_trains
# def sendQueryFirst(self):
# """
# 首次请求打印接口车次信息
# :return:
# """
# for station_date in self.station_dates:
# select_url = copy.copy(self.urls["select_url"])
# select_url["req_url"] = select_url["req_url"].format(station_date, self.from_station, self.to_station,
# self.session.queryUrl)
# station_ticket = self.httpClint.send(select_url)
# values = station_ticket.get("data", "")
def sendQuery(self):
"""
查询
@ -62,10 +74,10 @@ class query:
select_url["req_url"] = select_url["req_url"].format(station_date, self.from_station, self.to_station,
self.session.queryUrl)
station_ticket = self.httpClint.send(select_url)
if station_ticket.get("c_url", ""):
print(u"设置当前查询url为: {}".format(station_ticket.get("c_url", "")))
self.session.queryUrl = station_ticket.get("c_url", "") # 重设查询接口
continue
# if station_ticket.get("c_url", ""):
# print(u"设置当前查询url为: {}".format(station_ticket.get("c_url", "")))
# self.session.queryUrl = station_ticket.get("c_url", "") # 重设查询接口
# continue
value = station_ticket.get("data", "")
if not value:
print(u'{0}-{1} 车次坐席查询为空查询url: https://kyfw.12306.cn{2}, 可以手动查询是否有票'.format(
@ -77,20 +89,8 @@ class query:
if result:
for i in value['result']:
ticket_info = i.split('|')
# if TickerConfig.TICKET_TYPE is 2 and self.check_is_need_train(ticket_info):
# # 如果最后一位为1则是可以候补的不知道这些正确嘛
# if ticket_info[-2] == "1":
# nate = list(ticket_info[-1])
# for set_type in TickerConfig.SET_TYPE:
# if TickerConfig.PASSENGER_TICKER_STR(set_type) not in nate:
# continue
# print("当前订单可以候补,尝试提交候补订单")
# return {
# "secretStr": ticket_info[0],
# "seat": TickerConfig.SET_TYPE,
# "status": True,
# }
# elif TickerConfig.TICKET_TYPE is 1:
if self.session.flag:
print(f"车次:{ticket_info[3]} 出发站:{self.from_station_h} 到达站:{self.to_station_h} 历时:{ticket_info[10]} 商务/特等座:{ticket_info[32]} 一等座:{ticket_info[31]} 二等座:{ticket_info[30]} 动卧:{ticket_info[33]} 硬卧:{ticket_info[28]} 软座:{ticket_info[23]} 硬座:{ticket_info[29]} 无座:{ticket_info[26]} {ticket_info[1]}")
if ticket_info[1] == "预订" and self.check_is_need_train(ticket_info): # 筛选未在开始时间内的车次
for j in self._station_seat:
is_ticket_pass = ticket_info[j]
@ -166,6 +166,7 @@ class query:
}
else:
print(u"车次配置信息有误,或者返回数据异常,请检查 {}".format(station_ticket))
self.session.flag = False
return {"code": ticket.FAIL_CODE, "status": False, "cdn": self.httpClint.cdn, }

View File

@ -14,7 +14,7 @@ def _set_header_default():
# header_dict["Accept"] = "application/json, text/plain, */*"
header_dict["Accept-Encoding"] = "gzip, deflate"
header_dict[
"User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) 12306-electron/1.0.1 Chrome/59.0.3071.115 Electron/1.8.4 Safari/537.36"
"User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
header_dict["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
header_dict["Origin"] = "https://kyfw.12306.cn"
header_dict["Connection"] = "keep-alive"
@ -47,9 +47,8 @@ class HTTPClient(object):
:param kwargs:
:return:
"""
for kwarg in kwargs:
for k, v in kwarg.items():
self._s.cookies.set(k, v)
for k, v in kwargs.items():
self._s.cookies.set(k, v)
def get_cookies(self):
"""

View File

@ -1,78 +0,0 @@
# coding:utf-8
import base64
import requests
from hashlib import md5
class RClient(object):
def __init__(self, username, password):
self.username = username
try:
self.password = md5(password).hexdigest()
except TypeError:
self.password = md5(password.encode('utf-8')).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)
print(r)
return r.json()
def rk_create_base64(self, im, im_type, timeout=60):
"""
base64验证码识别
im: 图片字节
im_type: 题目类型
:return:
"""
params = {
'typeid': im_type,
'timeout': timeout,
'image': im,
}
params.update(self.base_params)
r = requests.post('http://api.ruokuai.com/create.json', data=params, headers=self.headers)
print(r)
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', '',)
im = open('tkcode', 'rb').read()
print(rc.rk_create(im, 6113))