diff --git a/env.docker.py.example b/env.docker.py.example index 1cf5f14..8a662fb 100644 --- a/env.docker.py.example +++ b/env.docker.py.example @@ -37,8 +37,11 @@ AUTO_CODE_ACCOUNT = { # 语音验证码 # 没找到比较好用的,现在用的这个是阿里云 API 市场上的,基本满足要求,价格也便宜 # 购买成功后到控制台找到 APPCODE 放在下面就可以了 -# 地址:https://market.aliyun.com/products/57126001/cmapi019902.html +# 地址:易源 https://market.aliyun.com/products/57126001/cmapi019902.html +# 2019-01-18 更新 +# 增加新的服务商 鼎信 https://market.aliyun.com/products/56928004/cmapi026600.html?spm=5176.2020520132.101.2.e27e7218KQttQS NOTIFICATION_BY_VOICE_CODE = 1 # 开启语音通知 +NOTIFICATION_VOICE_CODE_TYPE = 'dingxin' # 语音验证码服务商 可用项 dingxin yiyuan NOTIFICATION_API_APP_CODE = 'your app code' NOTIFICATION_VOICE_CODE_PHONE = 'your phone' # 接受通知的手机号 diff --git a/env.py.example b/env.py.example index 9e99118..1a0163b 100644 --- a/env.py.example +++ b/env.py.example @@ -37,8 +37,11 @@ AUTO_CODE_ACCOUNT = { # 使用 free 可用省略 # 语音验证码 # 没找到比较好用的,现在用的这个是阿里云 API 市场上的,基本满足要求,价格也便宜 # 购买成功后到控制台找到 APPCODE 放在下面就可以了 -# 地址:https://market.aliyun.com/products/57126001/cmapi019902.html +# 地址:易源 https://market.aliyun.com/products/57126001/cmapi019902.html +# 2019-01-18 更新 +# 增加新的服务商 鼎信 https://market.aliyun.com/products/56928004/cmapi026600.html?spm=5176.2020520132.101.2.e27e7218KQttQS NOTIFICATION_BY_VOICE_CODE = 1 # 开启语音通知 +NOTIFICATION_VOICE_CODE_TYPE = 'dingxin' # 语音验证码服务商 可用项 dingxin yiyuan NOTIFICATION_API_APP_CODE = 'your app code' NOTIFICATION_VOICE_CODE_PHONE = 'your phone' # 接受通知的手机号 diff --git a/py12306/app.py b/py12306/app.py index b4f1519..9fe52ee 100644 --- a/py12306/app.py +++ b/py12306/app.py @@ -104,9 +104,12 @@ class App: def test_send_notifications(cls): if Config().NOTIFICATION_BY_VOICE_CODE: # 语音通知 CommonLog.add_quick_log(CommonLog.MESSAGE_TEST_SEND_VOICE_CODE).flush() - Notification.voice_code(Config().NOTIFICATION_VOICE_CODE_PHONE, '张三', - OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format('北京', - '深圳')) + if Config().NOTIFICATION_VOICE_CODE_TYPE == 'dingxin': + voice_content = {'left_station': '广州', 'arrive_station': '深圳', 'set_type': '硬座', 'orderno': 'E123542'} + else: + voice_content = OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format('北京', + '深圳') + Notification.voice_code(Config().NOTIFICATION_VOICE_CODE_PHONE, '张三', voice_content) if Config().EMAIL_ENABLED: # 邮件通知 CommonLog.add_quick_log(CommonLog.MESSAGE_TEST_SEND_EMAIL).flush() Notification.send_email(Config().EMAIL_RECEIVER, '测试发送邮件', 'By py12306') diff --git a/py12306/config.py b/py12306/config.py index ae3b67f..74fcae5 100644 --- a/py12306/config.py +++ b/py12306/config.py @@ -44,6 +44,7 @@ class Config: # 语音验证码 NOTIFICATION_BY_VOICE_CODE = 0 + NOTIFICATION_VOICE_CODE_TYPE = '' NOTIFICATION_VOICE_CODE_PHONE = '' NOTIFICATION_API_APP_CODE = '' diff --git a/py12306/helpers/api.py b/py12306/helpers/api.py index fa9e7d4..a748d59 100644 --- a/py12306/helpers/api.py +++ b/py12306/helpers/api.py @@ -44,6 +44,7 @@ API_CONFIRM_SINGLE_FOR_QUEUE = BASE_URL_OF_12306 + '/otn/confirmPassenger/confir API_QUERY_ORDER_WAIT_TIME = BASE_URL_OF_12306 + '/otn/confirmPassenger/queryOrderWaitTime?{}' # 排队查询 API_NOTIFICATION_BY_VOICE_CODE = 'http://ali-voice.showapi.com/sendVoice?' +API_NOTIFICATION_BY_VOICE_CODE_DINGXIN = 'http://yuyin2.market.alicloudapi.com/dx/voice_notice' API_FREE_CODE_QCR_API = 'http://60.205.200.159/api' API_FREE_CODE_QCR_API_CHECK = 'http://check.huochepiao.360.cn/img_vcode' diff --git a/py12306/helpers/notification.py b/py12306/helpers/notification.py index 700b119..b6c3e42 100644 --- a/py12306/helpers/notification.py +++ b/py12306/helpers/notification.py @@ -5,6 +5,7 @@ from py12306.helpers.api import * from py12306.helpers.request import Request from py12306.log.common_log import CommonLog + class Notification(): """ 通知类 @@ -17,7 +18,10 @@ class Notification(): @classmethod def voice_code(cls, phone, name='', content=''): self = cls() - self.send_voice_code_of_yiyuan(phone, name=name, content=content) + if Config().NOTIFICATION_VOICE_CODE_TYPE == 'dingxin': + self.send_voice_code_of_dingxin(phone, name=name, info=content) + else: + self.send_voice_code_of_yiyuan(phone, name=name, content=content) @classmethod def dingtalk_webhook(cls, content=''): @@ -65,9 +69,7 @@ class Notification(): 'tNum': 'T170701001056' } response = self.session.request(url=API_NOTIFICATION_BY_VOICE_CODE + urllib.parse.urlencode(params), - method='GET', headers={ - 'Authorization': 'APPCODE {}'.format(appcode) - }) + method='GET', headers={'Authorization': 'APPCODE {}'.format(appcode)}) result = response.json() response_message = result.get('showapi_res_body.remark') if response.status_code in [400, 401, 403]: @@ -78,6 +80,35 @@ class Notification(): else: return CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_SEND_FAIL.format(response_message)).flush() + def send_voice_code_of_dingxin(self, phone, name='', info={}): + """ + 发送语音验证码 ( 鼎信 ) + 购买地址 https://market.aliyun.com/products/56928004/cmapi026600.html?spm=5176.2020520132.101.2.51547218rkAXxy + :return: + """ + appcode = Config().NOTIFICATION_API_APP_CODE + if not appcode: + CommonLog.add_quick_log(CommonLog.MESSAGE_EMPTY_APP_CODE).flush() + return False + data = { + 'tpl_id': 'TP1901174', + 'phone': phone, + 'param': 'name:{name},job_name:{left_station}到{arrive_station}{set_type},orderno:{orderno}'.format( + name=name, left_station=info.get('left_station'), arrive_station=info.get('arrive_station'), + set_type=info.get('set_type'), orderno=info.get('orderno')) + } + response = self.session.request(url=API_NOTIFICATION_BY_VOICE_CODE_DINGXIN, method='POST', data=data, + headers={'Authorization': 'APPCODE {}'.format(appcode)}) + result = response.json() + response_message = result.get('return_code') + if response.status_code in [400, 401, 403]: + return CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_FORBID).flush() + if response.status_code == 200 and result.get('return_code') == '00000': + CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_SEND_SUCCESS.format(response_message)).flush() + return True + else: + return CommonLog.add_quick_log(CommonLog.MESSAGE_VOICE_API_SEND_FAIL.format(response_message)).flush() + def send_email_by_smtp(self, to, title, content): import smtplib from email.message import EmailMessage @@ -146,5 +177,11 @@ if __name__ == '__main__': name = '张三4' content = '你的车票 广州 到 深圳 购买成功,请登录 12306 进行支付' # Notification.voice_code('13800138000', name, content) - Notification.send_email('user@email.com', name, content) - Notification.dingtalk_webhook(content) + # Notification.send_email('user@email.com', name, content) + # Notification.dingtalk_webhook(content) + Notification.voice_code('13800138000', name, { + 'left_station': '广州', + 'arrive_station': '深圳', + 'set_type': '硬座', + 'orderno': 'E123542' + }) diff --git a/py12306/log/order_log.py b/py12306/log/order_log.py index c84e356..2f90092 100644 --- a/py12306/log/order_log.py +++ b/py12306/log/order_log.py @@ -31,8 +31,9 @@ class OrderLog(BaseLog): MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE = '车票购买成功!' MESSAGE_ORDER_SUCCESS_NOTIFICATION_CONTENT = '请及时登录12306,打开 \'未完成订单\',在30分钟内完成支付!' + MESSAGE_ORDER_SUCCESS_NOTIFICATION_INFO = '\t\t车次信息:{} -> {} ( {} ),乘车日期 {},席位:{}' - MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND = '正在发送语音通知, 第 {} 次' + MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND = '正在发送语音通知...' MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT = '你的车票 {} 到 {} 购买成功,请登录 12306 进行支付' MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT = '订单号 {},请及时登录12306,打开 \'未完成订单\',在30分钟内完成支付!' @@ -53,3 +54,12 @@ class OrderLog(BaseLog): self.add_quick_log('# 车票购买成功,订单号 {} #'.format(order_id)) self.flush() return self + + @classmethod + def get_order_success_notification_info(cls, query): + from py12306.query.job import Job + assert isinstance(query, Job) + return cls.MESSAGE_ORDER_SUCCESS_NOTIFICATION_INFO.format(query.get_info_of_left_station(), + query.get_info_of_arrive_station(), + query.get_info_of_train_number(), + query.get_info_of_left_date(), query.current_seat) diff --git a/py12306/order/order.py b/py12306/order/order.py index 164b97e..61cdf7d 100644 --- a/py12306/order/order.py +++ b/py12306/order/order.py @@ -79,27 +79,35 @@ class Order: def send_notification(self): # num = 0 # 通知次数 # sustain_time = self.notification_sustain_time + info_message = OrderLog.get_order_success_notification_info(self.query_ins) + normal_message = OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.format(self.order_id) if Config().EMAIL_ENABLED: # 邮件通知 Notification.send_email(Config().EMAIL_RECEIVER, OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE, - OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.format(self.order_id)) + normal_message + info_message) if Config().DINGTALK_ENABLED: # 钉钉通知 - Notification.dingtalk_webhook( - OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.format(self.order_id)) + Notification.dingtalk_webhook(normal_message + info_message) if Config().TELEGRAM_ENABLED: # Telegram推送 - Notification.send_to_telegram( - OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.format(self.order_id)) + Notification.send_to_telegram(normal_message + info_message) if Config().SERVERCHAN_ENABLED: # ServerChan通知 Notification.server_chan(Config().SERVERCHAN_KEY, OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE, - OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.format(self.order_id)) + normal_message + info_message) if Config().PUSHBEAR_ENABLED: # PushBear通知 Notification.push_bear(Config().PUSHBEAR_KEY, OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_TITLE, - OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_EMAIL_CONTENT.format(self.order_id)) + normal_message + info_message) if Config().NOTIFICATION_BY_VOICE_CODE: # 语音通知 - OrderLog.add_quick_log(OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND.format(num)) - Notification.voice_code(Config().NOTIFICATION_VOICE_CODE_PHONE, self.user_ins.get_name(), - OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format( - self.query_ins.left_station, self.query_ins.arrive_station)) + if Config().NOTIFICATION_VOICE_CODE_TYPE == 'dingxin': + voice_info = { + 'left_station': self.query_ins.left_station, + 'arrive_station': self.query_ins.arrive_station, + 'set_type': self.query_ins.current_seat, + 'orderno': self.order_id + } + else: + voice_info = OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_CONTENT.format( + self.query_ins.left_station, self.query_ins.arrive_station) + OrderLog.add_quick_log(OrderLog.MESSAGE_ORDER_SUCCESS_NOTIFICATION_OF_VOICE_CODE_START_SEND) + Notification.voice_code(Config().NOTIFICATION_VOICE_CODE_PHONE, self.user_ins.get_name(), voice_info) # 取消循环发送通知 # while sustain_time: # TODO 后面直接查询有没有待支付的订单就可以 # num += 1