文章目录
短信验证
- 发送短信验证码的前提:
- 用户名,手机号,图形验证码验证均无误
- 需要的参数:手机号,用户输入的图形验证码,uuid
- 手机号验证:首先不为空,手机号的格式正确,手机号没被注册过
做新的接口,所需要的内容都要验证,不论之前验证过与否
发送手机验证码功能实现
分析
- 业务处理流程
- 检查图形验证码是否正确
- 检查是否在60s内有发送记录
- 生成短信验证码
- 保存短信验证码与发送记录
- 发送短信
- 获取参数,验证参数,成功后再发送短信
- 请求方法:POST
- url定义:
/sms_codes/
- 请求参数:url路径参数
参数 | 类型 | 前端是否必须传 | 描述 |
---|---|---|---|
mobile | 字符串 | 是 | 用户输入的手机号 |
image_code_id | UUID | 是 | js生成的图片uuid号 |
由于是post请求,在向后端发起请求时,需要附带csrf_token
- 在verifications下新建forms.py文件,用form表单传参
from django import forms
from django.core.validators import RegexValidator
from apps.users.models import Users
from django_redis import get_redis_connection
"""
RegexValidator
classRegexValidator(regex = None,message = None,code = None,inverse_match = None,flags = 0)
参数:
正则表达式 - 如果没有None,则覆盖regex。可以是正则表达式字符串或预编译的正则表达式。
消息 - 如果不是None,则覆盖message。
代码 - 如果不是None,则覆盖code。
inverse_match - 如果不是None,则覆盖inverse_match。
flags - 如果不是None,则覆盖flags。在这种情况下, regex必须是正则表达式字符串,或者 TypeError被引发。
regex
要在提供的value或正在编译的正则表达式中搜索的正则表达式模式 。默认情况下,提出了一个 ValidationError具有message 和code如果没有找到匹配。
该标准的行为可以通过设置被逆转inverse_match到True,在这种情况下ValidationError,当比赛引发的发现。默认情况下,匹配任何字符串(包括空字符串)。
message
ValidationErrorif验证使用的错误消息 失败。默认为。"Enter a valid value"
code
ValidationError if验证使用的错误代码失败。默认为"invalid"。
inverse_match
匹配模式regex。默认为False。
flags
编译正则表达式字符串时使用的标志 regex。如果regex是预编译的正则表达式,并且flags被覆盖,TypeError则引发。默认为0。
"""
#创建手机号的校验器
mobile_validator = RegexValidator(r'1[3-9]\d{9}$','手机号码格式不正确')
class CheckImagCodeForm(forms.Form):
"""
检验图形验证码
要想使django中的表单验证前端传入的数据是否正确,我们需要用到Django中的forms。
常用的Field:
使用Field可以是对数据验证的第一步。你期望这个提交上来的数据是什么类型,那么就使用什么类型的Field。
CharField:用来接收文本。
参数:
max_length:这个字段值的最大长度。
min_length:这个字段值的最小长度。
required:如果没有写这个参数,即默认required=True,即这个字段不能为空。
error_messages:在某个条件验证失败的时候,给出错误信息。
"""
mobile = forms.CharField(max_length=11,
min_length=11,
validators=[mobile_validator], #通过字段的validators 参数将验证模型添加到模型字段
error_messages={'min_length':'手机号长度有误',
'max_length':'手机号长度有误',
'required':'手机号不能为空'}) #正则校验器
image_code_id = forms.UUIDField(error_messages={'required':'图片UUID不能为空'})#验证uuid的格式
text = forms.CharField(max_length=4,
min_length=4,
error_messages={'min_length':'图片验证码长度有误',
'max_length':'图片验证码长度有误',
'required':'图片验证码不能为空'})
def clean(self): #多字段一起验证
clean_data = super().clean() #继承Form的方法
#重写方法
mobile_num = clean_data.get('mobile') #用户输入的手机号
image_uuid = clean_data.get('image_code_id')#当前图形验证码的uuid
image_text = clean_data.get('text')#用户输入的图形验证码的文本信息
#如果填写的手机号mobile_num和Users中已有的手机号相等
if Users.objects.filter(mobile=mobile_num):
raise forms.ValidationError('手机号已经注册!请重新输入!')
con_redis = get_redis_connection(alias='verify_codes') #连接redis库
img_key = 'img_{}'.format(image_uuid) #将生成的uuid拼接,为了去redis库中查找对应的图形验证码
#提取img_key相对应的图形验证码的bytes类型
real_image_code_origin = con_redis.get(img_key) #redis中取出来的值是bytes类型
# if real_image_code_origin:
# real_image_code = real_image_code_origin.decode('utf-8')
# else:
# real_image_code = None
#下面这行代码等同于上四行代码,三元运算符
real_image_code = real_image_code_origin.decode('utf-8') if real_image_code_origin else None #数据库取出的图形验证码
# img_key取出来就删掉,如果验证成功,这个图形验证码就没用了,对应的img_key就没用了
# 如果验证失败,就生成新的图形验证码,再暂存到库中,这个图形验证码也没用了
con_redis.delete(img_key)
# 如果对应img_key的图形验证码不存在或者用户输入的图形验证码和库中提取转化的不一样
if (not real_image_code) or (image_text != real_image_code):
raise forms.ValidationError('图形验证失败')
#检查是否在60s内,60s内不能重复发验证码
前端代码
- auth.js
$(function () {
let $username = $('#user_name'); // 选择id为user_name的网页元素,需要定义一个id为user_name
let $img = $(".form-item .captcha-graph-img img"); // 获取图像标签
let sImageCodeId = ""; // 定义图像验证码ID值
let $mobile = $('#mobile'); // 选择id为mobile的网页元素,需要定义一个id为mobile
let $smsCodeBtn = $('.form-item .sms-captcha'); // 获取短信验证码按钮元素,需要定义一个id为input_smscode
let $imgCodeText = $('#input_captcha'); // 获取用户输入的图片验证码元素,需要定义一个id为input_captcha
// 1、图像验证码逻辑
generateImageCode(); // 生成图像验证码图片
$img.click(generateImageCode); // 点击图片验证码生成新的图片验证码图片
// 2、判断用户名是否注册
$username.blur(function () {
fn_check_usrname();
});
// 3、判断用户手机号是否注册
$mobile.blur(function () {
fn_check_mobile();
});
// 4、发送短信逻辑
$smsCodeBtn.click(function () {
// 判断手机号是否输入
if (fn_check_mobile() !== "success") {
return
}
// 判断用户是否输入图片验证码
let text = $imgCodeText.val(); // 获取用户输入的图片验证码文本
if (!text) {
message.showError('请填写验证码!');
return
}
// 判断是否生成的UUID
if (!sImageCodeId) {
message.showError('图片UUID为空');
return
}
// 正常获取参数
let SdataParams = {
"mobile": $mobile.val(), // 获取用户输入的手机号
"text": text, // 获取用户输入的图片验证码文本
"image_code_id": sImageCodeId // 获取图片UUID
};
// for test
// let SdataParams = {
// "mobile": "1886608", // 获取用户输入的手机号
// "text": "ha3d", // 获取用户输入的图片验证码文本
// "image_code_id": "680a5a66-d9e5-4c3c-b8ea" // 获取图片UUID
// };
// 向后端发送请求
$.ajax({
// 请求地址
url: "/sms_codes/",
// 请求方式
type: "POST",
data: JSON.stringify(SdataParams),
// 请求内容的数据类型(前端发给后端的格式)
contentType: "application/json; charset=utf-8",
// 响应数据的格式(后端返回给前端的格式)
dataType: "json",
async: false // 关掉异步功能
})
.done(function (res) {
if (res.errno === "0") {
// 倒计时60秒,60秒后允许用户再次点击发送短信验证码的按钮
message.showSuccess('短信验证码发送成功');
let num = 60;
// 设置一个计时器
let t = setInterval(function () {
if (num === 1) {
// 如果计时器到最后, 清除计时器对象
clearInterval(t);
// 将点击获取验证码的按钮展示的文本恢复成原始文本
$smsCodeBtn.html("获取验证码");
// // 将点击按钮的onclick事件函数恢复回去
// $(".get_code").attr("onclick", "sendSMSCode();");
} else {
num -= 1;
// 展示倒计时信息
$smsCodeBtn.html(num + "秒");
}
}, 1000);
} else {
message.showError(res.errmsg);
}
})
.fail(function(){
message.showError(res.errmsg);
});
});
// 生成一个图片验证码的编号,并设置页面中图片验证码img标签的src属性
function generateImageCode() {
// 1、生成一个图片验证码随机编号
sImageCodeId = generateUUID();
// 2、拼接请求url /image_codes/<uuid:image_code_id>/
let imageCodeUrl = "/image_codes/" + sImageCodeId + "/";
// 3、修改验证码图片src地址
$img.attr('src', imageCodeUrl)
}
// 生成图片UUID验证码
function generateUUID() {
let d = new Date().getTime();
if (window.performance && typeof window.performance.now === "function") {
d += performance.now(); //use high-precision timer if available
}
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}
// 判断用户名是否已经注册
function fn_check_usrname() {
let sUsername = $username.val(); // 获取用户名字符串
if (sUsername === "") {
message.showError('用户名不能为空!');
return
}
// test()方法 判断字符串中是否匹配到正则表达式内容,返回的是boolean值 ( true / false )
if (!(/^\w{5,20}$/).test(sUsername)) {
message.showError('请输入5-20个字符的用户名');
return
}
// 发送ajax请求,去后端查询用户名是否存在
$.ajax({
url: '/usernames/' + sUsername + '/',
type: 'GET',
dataType: 'json',
})
.done(function (res) {
if (res.data.count !== 0) {
message.showError(res.data.username + '已注册,请重新输入!')
} else {
message.showInfo(res.data.username + '能正常使用!')
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
});
}
function fn_check_mobile() {
let sMobile = $mobile.val(); // 获取用户输入的手机号码字符串
let SreturnValue = "";
if (sMobile === "") {
message.showError('手机号不能为空!');
return
}
if (!(/^1[345789]\d{9}$/).test(sMobile)) {
message.showError('手机号码格式不正确,请重新输入!');
return
}
$.ajax({
url: '/mobiles/' + sMobile + '/',
type: 'GET',
dataType: 'json',
async: false
})
.done(function (res) {
if (res.data.count !== 0) {
message.showError(res.data.mobile + '已注册,请重新输入!');
SreturnValue = ""
} else {
message.showSuccess(res.data.mobile + '此手机号可以使用');
SreturnValue = "success"
}
})
.fail(function () {
message.showError('服务器超时,请重试!');
SreturnValue = ""
});
return SreturnValue
}
// get cookie using jQuery
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// Setting the token on the AJAX request
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
});
后端代码
apps/verifications/views.py
from django.shortcuts import render
from django.http import HttpResponse,JsonResponse
from django_redis import get_redis_connection
from utils.captcha.captcha import captcha #utils/captcha/captcha.py captcha实例
from apps.verifications import constants
import logging
from utils.json_fun import to_json_data
from django.views import View
from apps.users import models
from apps.users.models import Users
import json
import random
import string
from django_redis import get_redis_connection
from utils.res_code import Code, error_map
from apps.verifications.forms import CheckImagCodeForm
from utils.yuntongxun.sms import CCP
#导入日志器
logger = logging.getLogger('django')
class ImageCode(View):
"""
/verifications/image_codes/
"""
def get(self,request,image_code_id):
# 见captcha.py的最后一行,即输出的元组
text,image = captcha.generate_captcha() #图片展示给用户看,text要临时存入数据库
con_redis = get_redis_connection(alias='verity_codes') #连接指定的redis库
img_key = 'img_{}'.format(image_code_id) #拼接成img_xxx形式
# con_redis.setex(img_key,300,text) #暂存300s
con_redis.setex(img_key,constants.IMAGE_CODE_REDIS_EXPIRES,text) #常量一般单独放置,尽量不改源代码,方便以后修改维护
logger.info('Image_code: {}'.format(text)) #后台日志直接打印,方便调试
return HttpResponse(content=image,content_type='image/jpg')
# 1.请求方式 不需要修改数据库,只是去数据库查,用GET
# 2.参数 判断用户名是否存在,传递用户名参数 路由传参比较方便 re_path
class CheckUsernameView(View):
"""
Check whether the user exists
GET usernames/(?P<username>|w{5,20})/ #用正则,需要满足这样的方式
"""
def get(self,request,username):
count = models.Users.objects.filter(username=username).count() #统计此用户名的个数
data = { #data放具体内容
'count': count,
'username': username,
}
# return JsonResponse({'data': data})
return to_json_data(data=data) #传一个参数默认传给第一个参数,考虑到位置用关键字传参
class CheckMobileView(View):
"""
GET mobiles/(?P<mobile>\w{5,20})/
"""
def get(self,request,mobile):
count = models.Users.objects.filter(mobile=mobile).count()
data = {
'count': count,
'mobile': mobile,
}
# return JsonResponse({'data': data})
return to_json_data(data=data)
#手机号:不空,格式正确,没被注册过
#验证码:不为空,与数据库存入的数据对比
#uuid:格式正确
class SmsCodesView(View):
"""
send mobile sms code
POST /sms_codes/
"""
# 1 获取参数
def post(self,request):
# 验证参数 发送短信 保存短信验证码 返回信息给前端
json_data = request.body#body的内容是bytes格式 bytes decode成str解码 str encode bytes编码
if not json_data: #如果不存在
return to_json_data(errno=Code.PARAMERR,errmsg=error_map[Code.PARAMERR]) #字典获取也可用get
dict_data = json.loads(json_data.decode('utf8')) #json转字典
# 2 验证参数 要多个字段一起验证,用form表单验证方便
form = CheckImagCodeForm(data=dict_data)
if form.is_valid(): #验证通过
#3 保存短信验证码
mobile = form.cleaned_data.get('mobile')
# sms_num = ''
# for i in range(6):
# sms_num += random.choice(string.digits) 注释这三行等同于下一行
sms_num = ''.join([random.choice(string.digits) for _ in range(constants.SMS_CODE_NUMS)]) #_是占位符,相当于上面的i
con_redis = get_redis_connection(alias='verify_codes')#连接redis数据库
pl = con_redis.pipeline() #优化机制,使两个一起存入,节省时间,管道是redis提供的
sms_text_fmt = 'sms_{}'.format(mobile) #手机验证码的键
sms_flg_fmt = 'sms_flag_{}'.format(mobile) #发送标记,用于判断是否发送过
try:
pl.setex(sms_flg_fmt,constants.SEND_SMS_CODE_INTERVAL,constants.SMS_CODE_TEMP_ID) #设置标记为1,用模板1发送短信验证码
pl.setex(sms_text_fmt,constants.SMS_CODE_REDIS_EXPIRES,sms_num) #短信验证码内容
pl.execute()
except Exception as e:
logger.debug('redis执行异常:{}'.format(e))
return to_json_data(errno=Code.UNKOWNERR,errmsg=error_map[Code.UNKOWNERR]) #返回错误信息给前端:未知错误
#4 发送短信验证码 #只是测试,为了节省短信费,直接在后台返回验证码发送成功
#实际运行时将下两行代码注释,用下面注释的代码
logger.info('发送短信验证码[正常][mobile: %s,sms_code: %s]' % (mobile, sms_num))
return to_json_data(errno=Code.OK, errmsg='短信验证码发送成功')
# 4 发送短信验证码
# try:
# result = CCP().send_template_sms(mobile,
# [sms_num,constants.SMS_CODE_WRITE],#有效期
# constants.SMS_CODE_TEMP_ID) #发送短信的模板
# except Exception as e:
# logger.error('发送短信验证码[异常][moble: %s,message: %s]' % (mobile,e))
# return to_json_data(errno=Code.SERVERERR,errmsg=error_map[Code.SERVERERR])#返回给前端:内部错误
# else:
# if result == 0: #对应sms.py中的if result == 0
# logger.info('发送短信验证码[正常][mobile: %s,sms_code: %s]' % (mobile,sms_num))
# return to_json_data(errno=Code.OK,errmsg='短信验证码发送成功')
# else:
# logger.warning('发送短信验证码[失败][mobile: %s]' % mobile)
# return to_json_data(errno=Code.SMSFAIL,errmsg=error_map[Code.SMSFAIL])
else:
#定义一个错误信息列表
err_msg_list = []
for item in form.errors.get_json_data().values():
err_msg_list.append(item[0].get('message'))
err_msg_str = '/'.join(err_msg_list) #拼接错误信息为一个字符串
return to_json_data(errno=Code.PARAMERR,errmsg=err_msg_str)
verifications/constants.py
#图形验证码redis有效期,单位秒
IMAGE_CODE_REDIS_EXPIRES = 5 * 60
#短信验证码位数
SMS_CODE_NUMS = 6
#短信发送模板
SMS_CODE_TEMP_ID = 1
#发送间隔
SEND_SMS_CODE_INTERVAL = 60
#短信验证码有效期,单位秒
SMS_CODE_REDIS_EXPIRES = 5 * 60
utils/yuntongxun/CCPRestSDK.py
# -*- coding: UTF-8 -*-
from hashlib import md5
import base64
import datetime
from urllib import request as urllib2
import json
from .xml_to_json import xmltojson
class REST:
AccountSid = ''
AccountToken = ''
AppId = ''
SubAccountSid = ''
SubAccountToken = ''
ServerIP = ''
ServerPort = ''
SoftVersion = ''
Iflog = False # 是否打印日志
Batch = '' # 时间戳
BodyType = 'xml' # 包体格式,可填值:json 、xml
# 初始化
# @param serverIP 必选参数 服务器地址
# @param serverPort 必选参数 服务器端口
# @param softVersion 必选参数 REST版本号
def __init__(self, ServerIP, ServerPort, SoftVersion):
self.ServerIP = ServerIP
self.ServerPort = ServerPort
self.SoftVersion = SoftVersion
# 设置主帐号
# @param AccountSid 必选参数 主帐号
# @param AccountToken 必选参数 主帐号Token
def setAccount(self, AccountSid, AccountToken):
self.AccountSid = AccountSid
self.AccountToken = AccountToken
# 设置子帐号
#
# @param SubAccountSid 必选参数 子帐号
# @param SubAccountToken 必选参数 子帐号Token
def setSubAccount(self, SubAccountSid, SubAccountToken):
self.SubAccountSid = SubAccountSid
self.SubAccountToken = SubAccountToken
# 设置应用ID
#
# @param AppId 必选参数 应用ID
def setAppId(self, AppId):
self.AppId = AppId
def log(self, url, body, data):
print('这是请求的URL:')
print(url)
print('这是请求包体:')
print(body)
print('这是响应包体:')
print(data)
print('********************************')
# 创建子账号
# @param friendlyName 必选参数 子帐号名称
def CreateSubAccount(self, friendlyName):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SubAccounts?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# xml格式
body = '''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\
<friendlyName>%s</friendlyName>\
</SubAccount>\
''' % (self.AppId, friendlyName)
if self.BodyType == 'json':
# json格式
body = '''{"friendlyName": "%s", "appId": "%s"}''' % (friendlyName, self.AppId)
data = ''
req.data = body.encode()
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 获取子帐号
# @param startNo 可选参数 开始的序号,默认从0开始
# @param offset 可选参数 一次查询的最大条数,最小是1条,最大是100条
def getSubAccounts(self, startNo, offset):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/GetSubAccounts?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
# auth = base64.encodestring(src).strip()
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# xml格式
body = '''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\
<startNo>%s</startNo><offset>%s</offset>\
</SubAccount>\
''' % (self.AppId, startNo, offset)
if self.BodyType == 'json':
# json格式
body = '''{"appId": "%s", "startNo": "%s", "offset": "%s"}''' % (self.AppId, startNo, offset)
data = ''
req.data = body.encode()
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 子帐号信息查询
# @param friendlyName 必选参数 子帐号名称
def querySubAccount(self, friendlyName):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/QuerySubAccountByName?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
# auth = base64.encodestring(src).strip()
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# 创建包体
body = '''<?xml version="1.0" encoding="utf-8"?><SubAccount><appId>%s</appId>\
<friendlyName>%s</friendlyName>\
</SubAccount>\
''' % (self.AppId, friendlyName)
if self.BodyType == 'json':
body = '''{"friendlyName": "%s", "appId": "%s"}''' % (friendlyName, self.AppId)
data = ''
req.data = body.encode()
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
print(error)
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 发送模板短信
# @param to 必选参数 短信接收彿手机号码集合,用英文逗号分开
# @param datas 可选参数 内容数据
# @param tempId 必选参数 模板Id
def sendTemplateSMS(self, to, datas, tempId):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SMS/TemplateSMS?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
# auth = base64.encodestring(src).strip()
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# 创建包体
b = ''
for a in datas:
b += '<data>%s</data>' % (a)
body = '<?xml version="1.0" encoding="utf-8"?><SubAccount><datas>' + b + '</datas><to>%s</to><templateId>%s</templateId><appId>%s</appId>\
</SubAccount>\
' % (to, tempId, self.AppId)
if self.BodyType == 'json':
# if this model is Json ..then do next code
b = '['
for a in datas:
b += '"%s",' % (a)
b += ']'
body = '''{"to": "%s", "datas": %s, "templateId": "%s", "appId": "%s"}''' % (to, b, tempId, self.AppId)
req.data = body.encode()
data = ''
try:
# 查找相关资料后确定为,Python 2.7.9 之后版本引入了一个新特性:
# 当你urllib.urlopen一个 https 的时候会验证一次 SSL 证书,
# 当目标使用的是自签名的证书时就会爆出该错误消息。
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 外呼通知
# @param to 必选参数 被叫号码
# @param mediaName 可选参数 语音文件名称,格式 wav。与mediaTxt不能同时为空。当不为空时mediaTxt属性失效。
# @param mediaTxt 可选参数 文本内容
# @param displayNum 可选参数 显示的主叫号码
# @param playTimes 可选参数 循环播放次数,1-3次,默认播放1次。
# @param respUrl 可选参数 外呼通知状态通知回调地址,云通讯平台将向该Url地址发送呼叫结果通知。
# @param userData 可选参数 用户私有数据
# @param maxCallTime 可选参数 最大通话时长
# @param speed 可选参数 发音速度
# @param volume 可选参数 音量
# @param pitch 可选参数 音调
# @param bgsound 可选参数 背景音编号
def landingCall(self, to, mediaName, mediaTxt, displayNum, playTimes, respUrl, userData, maxCallTime, speed, volume,
pitch, bgsound):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/Calls/LandingCalls?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
# auth = base64.encodestring(src).strip()
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# 创建包体
body = '''<?xml version="1.0" encoding="utf-8"?><LandingCall>\
<to>%s</to><mediaName>%s</mediaName><mediaTxt>%s</mediaTxt><appId>%s</appId><displayNum>%s</displayNum>\
<playTimes>%s</playTimes><respUrl>%s</respUrl><userData>%s</userData><maxCallTime>%s</maxCallTime><speed>%s</speed>
<volume>%s</volume><pitch>%s</pitch><bgsound>%s</bgsound></LandingCall>\
''' % (
to, mediaName, mediaTxt, self.AppId, displayNum, playTimes, respUrl, userData, maxCallTime, speed, volume,
pitch, bgsound)
if self.BodyType == 'json':
body = '''{"to": "%s", "mediaName": "%s","mediaTxt": "%s","appId": "%s","displayNum": "%s","playTimes": "%s","respUrl": "%s","userData": "%s","maxCallTime": "%s","speed": "%s","volume": "%s","pitch": "%s","bgsound": "%s"}''' % (
to, mediaName, mediaTxt, self.AppId, displayNum, playTimes, respUrl, userData, maxCallTime, speed, volume,
pitch, bgsound)
req.data = body.encode()
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 语音验证码
# @param verifyCode 必选参数 验证码内容,为数字和英文字母,不区分大小写,长度4-8位
# @param playTimes 可选参数 播放次数,1-3次
# @param to 必选参数 接收号码
# @param displayNum 可选参数 显示的主叫号码
# @param respUrl 可选参数 语音验证码状态通知回调地址,云通讯平台将向该Url地址发送呼叫结果通知
# @param lang 可选参数 语言类型
# @param userData 可选参数 第三方私有数据
def voiceVerify(self, verifyCode, playTimes, to, displayNum, respUrl, lang, userData):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/Calls/VoiceVerify?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
# auth = base64.encodestring(src).strip()
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# 创建包体
body = '''<?xml version="1.0" encoding="utf-8"?><VoiceVerify>\
<appId>%s</appId><verifyCode>%s</verifyCode><playTimes>%s</playTimes><to>%s</to><respUrl>%s</respUrl>\
<displayNum>%s</displayNum><lang>%s</lang><userData>%s</userData></VoiceVerify>\
''' % (self.AppId, verifyCode, playTimes, to, respUrl, displayNum, lang, userData)
if self.BodyType == 'json':
# if this model is Json ..then do next code
body = '''{"appId": "%s", "verifyCode": "%s","playTimes": "%s","to": "%s","respUrl": "%s","displayNum": "%s","lang": "%s","userData": "%s"}''' % (
self.AppId, verifyCode, playTimes, to, respUrl, displayNum, lang, userData)
req.data = body.encode()
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# IVR外呼
# @param number 必选参数 待呼叫号码,为Dial节点的属性
# @param userdata 可选参数 用户数据,在<startservice>通知中返回,只允许填写数字字符,为Dial节点的属性
# @param record 可选参数 是否录音,可填项为true和false,默认值为false不录音,为Dial节点的属性
def ivrDial(self, number, userdata, record):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch;
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/ivr/dial?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
req.add_header("Accept", "application/xml")
req.add_header("Content-Type", "application/xml;charset=utf-8")
req.add_header("Authorization", auth)
# 创建包体
body = '''<?xml version="1.0" encoding="utf-8"?>
<Request>
<Appid>%s</Appid>
<Dial number="%s" userdata="%s" record="%s"></Dial>
</Request>
''' % (self.AppId, number, userdata, record)
req.data = body.encode()
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 话单下载
# @param date 必选参数 day 代表前一天的数据(从00:00 – 23:59),目前只支持按天查询
# @param keywords 可选参数 客户的查询条件,由客户自行定义并提供给云通讯平台。默认不填忽略此参数
def billRecords(self, date, keywords):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/BillRecords?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# 创建包体
body = '''<?xml version="1.0" encoding="utf-8"?><BillRecords>\
<appId>%s</appId><date>%s</date><keywords>%s</keywords>\
</BillRecords>\
''' % (self.AppId, date, keywords)
if self.BodyType == 'json':
# if this model is Json ..then do next code
body = '''{"appId": "%s", "date": "%s","keywords": "%s"}''' % (self.AppId, date, keywords)
req.data = body.encode()
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 主帐号信息查询
def queryAccountInfo(self):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/AccountInfo?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
body = ''
req.add_header("Authorization", auth)
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 短信模板查询
# @param templateId 必选参数 模板Id,不带此参数查询全部可用模板
def QuerySMSTemplate(self, templateId):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/SMS/QuerySMSTemplate?sig=" + sig
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# 创建包体
body = '''<?xml version="1.0" encoding="utf-8"?><Request>\
<appId>%s</appId><templateId>%s</templateId></Request>
''' % (self.AppId, templateId)
if self.BodyType == 'json':
# if this model is Json ..then do next code
body = '''{"appId": "%s", "templateId": "%s"}''' % (self.AppId, templateId)
req.data = body.encode()
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main2(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 呼叫结果查询
# @param callsid 必选参数 呼叫ID
def CallResult(self, callSid):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/CallResult?sig=" + sig + "&callsid=" + callSid
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
body = ''
req.add_header("Authorization", auth)
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 呼叫状态查询
# @param callid 必选参数 一个由32个字符组成的电话唯一标识符
# @param action 可选参数 查询结果通知的回调url地址
def QueryCallState(self, callid, action):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/ivr/call?sig=" + sig + "&callid=" + callid
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
self.setHttpHeader(req)
req.add_header("Authorization", auth)
# 创建包体
body = '''<?xml version="1.0" encoding="utf-8"?><Request>\
<Appid>%s</Appid><QueryCallState callid="%s" action="%s"/>\
</Request>\
''' % (self.AppId, callid, action)
if self.BodyType == 'json':
# if this model is Json ..then do next code
body = '''{"Appid":"%s","QueryCallState":{"callid":"%s","action":"%s"}}''' % (self.AppId, callid, action)
req.data = body.encode()
data = ''
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 语音文件上传
# @param filename 必选参数 文件名
# @param body 必选参数 二进制串
def MediaFileUpload(self, filename, body):
self.accAuth()
nowdate = datetime.datetime.now()
self.Batch = nowdate.strftime("%Y%m%d%H%M%S")
# 生成sig
signature = self.AccountSid + self.AccountToken + self.Batch
sig = md5(signature.encode()).hexdigest().upper()
# 拼接URL
url = "https://" + self.ServerIP + ":" + self.ServerPort + "/" + self.SoftVersion + "/Accounts/" + self.AccountSid + "/Calls/MediaFileUpload?sig=" + sig + "&appid=" + self.AppId + "&filename=" + filename
# 生成auth
src = self.AccountSid + ":" + self.Batch
auth = base64.encodebytes(src.encode()).decode().strip()
req = urllib2.Request(url)
req.add_header("Authorization", auth)
if self.BodyType == 'json':
req.add_header("Accept", "application/json")
req.add_header("Content-Type", "application/octet-stream")
else:
req.add_header("Accept", "application/xml")
req.add_header("Content-Type", "application/octet-stream")
# 创建包体
req.data = body.encode()
try:
res = urllib2.urlopen(req)
data = res.read()
res.close()
if self.BodyType == 'json':
# json格式
locations = json.loads(data)
else:
# xml格式
xtj = xmltojson()
locations = xtj.main(data)
if self.Iflog:
self.log(url, body, data)
return locations
except Exception as error:
if self.Iflog:
self.log(url, body, data)
return {'172001': '网络错误'}
# 子帐号鉴权
def subAuth(self):
if self.ServerIP == "":
print('172004')
print('IP为空')
if int(self.ServerPort) <= 0:
print('172005')
print('端口错误(小于等于0)')
if self.SoftVersion == "":
print('172013')
print('版本号为空')
if self.SubAccountSid == "":
print('172008')
print('子帐号为空')
if self.SubAccountToken == "":
print('172009')
print('子帐号令牌为空')
if self.AppId == "":
print('172012')
print('应用ID为空')
# 主帐号鉴权
def accAuth(self):
if self.ServerIP == "":
print('172004')
print('IP为空')
if int(self.ServerPort) <= 0:
print('172005')
print('端口错误(小于等于0)')
if self.SoftVersion == "":
print('172013')
print('版本号为空')
if self.AccountSid == "":
print('172006')
print('主帐号为空')
if self.AccountToken == "":
print('172007')
print('主帐号令牌为空')
if self.AppId == "":
print('172012')
print('应用ID为空')
# 设置包头
def setHttpHeader(self, req):
if self.BodyType == 'json':
req.add_header("Accept", "application/json")
req.add_header("Content-Type", "application/json;charset=utf-8")
else:
req.add_header("Accept", "application/xml")
req.add_header("Content-Type", "application/xml;charset=utf-8")
utils/yuntongxun/sms.py
# -*- coding:utf-8 -*-
# 说明:主账号,登陆云通讯网站后,可在"控制台-应用"中看到开发者主账号ACCOUNT SID
from utils.yuntongxun.CCPRestSDK import REST
_accountSid = '开发者主账号中的ACCOUNT SID'
# 说明:主账号Token,登陆云通讯网站后,可在控制台-应用中看到开发者主账号AUTH TOKEN
_accountToken = '开发者主账号中的AUTH TOKEN'
# 请使用管理控制台首页的APPID或自己创建应用的APPID
_appId = '开发者主账号中的AppID(默认)'
# 说明:请求地址,生产环境配置成app.cloopen.com
_serverIP = 'app.cloopen.com'
# 说明:请求端口 ,生产环境为8883
_serverPort = "8883"
# 说明:REST API版本号保持不变
_softVersion = '2013-12-26'
class CCP(object):
"""发送短信的辅助类"""
def __new__(cls, *args, **kwargs):
# 判断是否存在类属性_instance,_instance是类CCP的唯一对象,即单例
if not hasattr(CCP, "_instance"):
cls._instance = super(CCP, cls).__new__(cls, *args, **kwargs)
cls._instance.rest = REST(_serverIP, _serverPort, _softVersion)
cls._instance.rest.setAccount(_accountSid, _accountToken)
cls._instance.rest.setAppId(_appId)
return cls._instance
def send_template_sms(self, to, datas, temp_id):
"""
发送模板短信
:param to: 发给哪个手机号(‘18866666666’)
:param datas: ['6666', 5] 短信验证码6666和过期时间5分钟
:param temp_id: ‘1’ 内容模板id
:return:
"""
# @param to 手机号码
# @param datas 内容数据 格式为数组 例如:{'12','34'},如不需替换请填 ''
# @param temp_id 模板Id
res = None
try:
res = self.rest.sendTemplateSMS(to, datas, temp_id)
except Exception as e:
print(e)
# 如果云通讯发送短信成功,返回的字典数据result中statuCode字段的值为"000000"
if res.get("statusCode") == "000000":
# 返回0 表示发送短信成功
return 0
else:
# 返回-1 表示发送失败
return -1
if __name__ == '__main__':
ccp = CCP()
# 注意: 测试的短信模板编号为1
result = None
while True:
result = ccp.send_template_sms('18866666666', ['6666', 5], "1")
if result == 0:
print('短信验证码发送成功!')
break
utils/yuntongxun/xml_to_json.py
# -*- coding: utf-8 -*-
# python xml.etree.ElementTree
import os
import xml.etree.ElementTree as ET
from xml.dom import minidom
class xmltojson:
# global var
SHOW_LOG = True
# XML file
XML_PATH = None
a = {}
m = []
def get_root(self, path):
"""
parse the XML file,and get the tree of the XML file
finally,return the root element of the tree.
if the XML file dose not exist,then print the information
"""
tree = ET.fromstring(path)
return tree
def get_element_tag(self, element):
"""
return the element tag if the element is not None.
"""
if element is not None:
return element.tag
else:
print('the element is None!')
def get_element_attrib(self, element):
"""
return the element attrib if the element is not None.
"""
if element is not None:
return element.attrib
else:
print('the element is None!')
def get_element_text(self, element):
"""
return the text of the element.
"""
if element is not None:
return element.text
else:
print('the element is None!')
def get_element_children(self, element):
"""
return the element children if the element is not None.
"""
if element is not None:
return [c for c in element]
else:
print('the element is None!')
def get_elements_tag(self, elements):
"""
return the list of tags of element's tag
"""
if elements is not None:
tags = []
for e in elements:
tags.append(e.tag)
return tags
else:
print('the elements is None!')
def get_elements_attrib(self, elements):
"""
return the list of attribs of element's attrib
"""
if elements is not None:
attribs = []
for a in elements:
attribs.append(a.attrib)
return attribs
else:
print('the elements is None!')
def get_elements_text(self, elements):
"""
return the dict of element
"""
if elements is not None:
text = []
for t in elements:
text.append(t.text)
return dict(zip(self.get_elements_tag(elements), text))
else:
print('the elements is None!')
def main(self, xml):
# root
root = self.get_root(xml)
# children
children = self.get_element_children(root)
children_tags = self.get_elements_tag(children)
children_attribs = self.get_elements_attrib(children)
i = 0
# 获取二级元素的每一个子节点的名称和值
for c in children:
p = 0
c_children = self.get_element_children(c)
dict_text = self.get_elements_text(c_children)
if dict_text:
# print (children_tags[i])
if children_tags[i] == 'TemplateSMS':
self.a['templateSMS'] = dict_text
else:
if children_tags[i] == 'SubAccount':
k = 0
for x in children:
if children_tags[k] == 'totalCount':
self.m.append(dict_text)
self.a['SubAccount'] = self.m
p = 1
k = k + 1
if p == 0:
self.a[children_tags[i]] = dict_text
else:
self.a[children_tags[i]] = dict_text
else:
self.a[children_tags[i]] = c.text
i = i + 1
return self.a
def main2(self, xml):
# root
root = self.get_root(xml)
# children
children = self.get_element_children(root)
children_tags = self.get_elements_tag(children)
children_attribs = self.get_elements_attrib(children)
i = 0
# 获取二级元素的每一个子节点的名称和值
for c in children:
p = 0
c_children = self.get_element_children(c)
dict_text = self.get_elements_text(c_children)
if dict_text:
if children_tags[i] == 'TemplateSMS':
k = 0
for x in children:
if children_tags[k] == 'totalCount':
self.m.append(dict_text)
self.a['TemplateSMS'] = self.m
p = 1
k = k + 1
if p == 0:
self.a[children_tags[i]] = dict_text
else:
self.a[children_tags[i]] = dict_text
else:
self.a[children_tags[i]] = c.text
i = i + 1
return self.a