python 控制手机发送短信_python-在python3中使用容联云通讯发送短信验证码

2020-08-15更新

今天进容联云官网发现其已经更新了最新版的Python SDK,可以直接 pip install ronglian_sms_sdk 即可安装使用,具体新的使用方法可以查看官网案例:http://doc.yuntongxun.com/p/5f029ae7a80948a1006e776e

原文

容联云通讯是第三方平台,能够提供短信验证码和语音通信等功能,这里只测试使用短信验证码的功能,因此只需完成注册登录(无需实名认证等)即可使用其短信验证码免费测试服务,不过免费测试服务只能给控制台中指定的三个手机号发送短信,且只能有一个短信模板可以使用.

使用时,在项目目录中新建一个文件夹(如yuntongxun)将SDK中的两个文件 CCPRestSDK.py 和 xmltojson.py 放入该文件夹中.然后再使用DEMO中的 SendTemplateSMS.py 来调用SDK中的py文件即可.这里我们不使用官方提供的 SendTemplateSMS.py ,而是将其改造封装成一个单例模式的类的方式调用,文件名为sms.py

#coding=utf-8

from .CCPRestSDK importREST#主帐号

accountSid =控制台中的ACCOUNT SID#主帐号Token

accountToken =控制台中的AUTH TOKEN#应用Id

appId =控制台中的AppID#请求地址,格式如下,不需要写http://

serverIP = 'app.cloopen.com'

#请求端口

serverPort = '8883'

#REST版本号

softVersion = '2013-12-26'

#发送模板短信

#@param to 手机号码

#@param datas 内容数据 格式为列表 例如:['12','34'],如不需替换请填 ''

#@param $tempId 模板Id

classCCP(object):"""自己封装的发送短信的辅助类"""

#用来保存对象的类属性

instance =Nonedef __new__(cls):#判断CCP类有没有已经创建好的对象,如果没有,创建一个对象,并且保存

#如果有,则将保存的对象直接返回

if cls.instance isNone:

obj= super(CCP, cls).__new__(cls)#初始化REST SDK

obj.rest =REST(serverIP, serverPort, softVersion)

obj.rest.setAccount(accountSid, accountToken)

obj.rest.setAppId(appId)

cls.instance=objreturncls.instancedefsend_template_sms(self, to, datas, temp_id):""""""result=self.rest.sendTemplateSMS(to, datas, temp_id)print('result:\n', result)#for k, v in result.iteritems():

# #if k == 'templateSMS':

#for k, s in v.iteritems():

#print '%s:%s' % (k, s)

#else:

#print '%s:%s' % (k, v)

#smsMessageSid:ff75e0f84f05445ba08efdd0787ad7d0

#dateCreated:20171125124726

#statusCode:000000

status_code = result.get("statusCode")if status_code == "000000":#表示发送短信成功

return0else:#发送失败

return -1

if __name__ == '__main__':

ccp=CCP()

ret= ccp.send_template_sms("17621081762", ["1234", "5"], 1)print(ret)

由于官方提供的代码CCPRestSDK.py是基于python2写的,本项目为python3,因此需要将其中一些python2的写法改成python3支持的语法,改写完成后为

#-*- coding: UTF-8 -*-

#Copyright (c) 2014 The CCP project authors. All Rights Reserved.

##Use of this source code is governed by a Beijing Speedtong Information Technology Co.,Ltd license

#that can be found in the LICENSE file in the root of the web site.

##http://www.yuntongxun.com

##An additional intellectual property rights grant can be found

#in the file PATENTS. All contributing project authors may

#be found in the AUTHORS file in the root of the source tree.#import md5

from hashlib import md5 #py3.x

importbase64importdatetime#import urllib2

import urllib.request as urllib2 #py3.x

importjsonfrom .xmltojson importxmltojsonfrom xml.dom importminidomclassREST:

AccountSid=''AccountToken=''AppId=''SubAccountSid=''SubAccountToken=''ServerIP=''ServerPort=''SoftVersion=''Iflog=True #是否打印日志

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

defsetAccount(self,AccountSid,AccountToken):

self.AccountSid=AccountSid;

self.AccountToken=AccountToken;

.......#发送模板短信

#@param to 必选参数 短信接收彿手机号码集合,用英文逗号分开

#@param datas 可选参数 内容数据

#@param tempId 必选参数 模板Id

defsendTemplateSMS(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;

signature= signature.encode('utf-8') #py3

#sig = md5.new(signature).hexdigest().upper()

sig = md5(signature).hexdigest().upper() #py3

#拼接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.encodestring(src.encode()).strip()

req=urllib2.Request(url)

self.setHttpHeader(req)

req.add_header("Authorization", auth)#创建包体

b=''

for a indatas:

b+='%s'%(a)

body='<?xml version="1.0" encoding="utf-8"?>'+b+'%s%s%s\

\'%(to, tempId,self.AppId)if self.BodyType == 'json':#if this model is Json ..then do next code

b='['

for a indatas:

b+='"%s",'%(a)

b+=']'body= '''{"to": "%s", "datas": %s, "templateId": "%s", "appId": "%s"}'''%(to,b,tempId,self.AppId)#req.add_data(body)

req.data = body.encode() #py3

data=''

try:

res=urllib2.urlopen(req);

data=res.read()

res.close()print(data)if self.BodyType=='json':#json格式

locations =json.loads(data)else:#xml格式

xtj=xmltojson()

locations=xtj.main(data)ifself.Iflog:

self.log(url,body,data)returnlocationsexceptException as error:print(error)ifself.Iflog:

self.log(url,body,data)return {'172001':'网络错误'}

.......#设置包头

defsetHttpHeader(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")

上述语法改写可以通过运行项目,看具体报错信息一步一步改成python3的写法,直到不报错为止,但是项目虽然不报错了,可还是不能成功发送短信,返回的报错信息是 {'172001':'网络错误'},经过百度和自己验证后,发现还有三处需要注意修改:

1. 运行报错:ModuleNotFoundError: No module named 'utils'

File "/home/python/study/ihome/ihome/libs/yuntongxun/sms.py", line 3, in

from .CCPRestSDK importREST

File"/home/python/study/ihome/ihome/libs/yuntongxun/CCPRestSDK.py", line 18, in

from xmltojson importxmltojson

File"/home/python/.virtualenvs/flask/bin/xmltojson.py", line 23, in

importutils

ModuleNotFoundError: No module named'utils'

我一开始以为是pip3中没有安装utils,后来再看上面的几行发现找的是虚拟环境中xmltojson.py而官方SDK源码中也提供了一个xmltojson.py文件,我们应该是使用这个文件,所以在开始import xmltojson时,应该写成

from .xmltojson import xmltojson

即从当前目录的xmltojson.py中导入

2.返回的报错信息是 {'172001':'网络错误'},原因是这里访问的url是https开头的,而python升级到 2.7.9 之后引入了一个新特性,当打开一个 https 链接时,会验证一次 SSL 证书。而当目标网站使用的是自签名的证书时就会抛出此异常。解决方案如下:在 sms.py或(SendTemplateSMS.py)文件顶部插入:

importssl#全局取消证书验证

ssl._create_default_https_context = ssl._create_unverified_context

3.操作完第二步之后,还是报错{'172001':'网络错误'},查看打印发现响应包体为空,说明发送数据是否有问题,后面发现给req添加请求体信息时,将原来的 py2写法:req.add_data(body),改成了py3写法:req.data = body,这时body是字符串类型,需要使用encode将其转码为byte类型,因此需要改成

req.data = body.encode()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值