python-在python3中使用容聯雲通訊發送短信驗證碼


2020-08-15更新

今天進容聯雲官網發現其已經更新了最新版的Python SDK,可以直接 pip install ronglian_sms_sdk 即可安裝使用,具體新的使用方法可以查看官網案例:http://doc.yuntongxun.com/p/5f029ae7a80948a1006e776e

原文

容聯雲通訊是第三方平台,能夠提供短信驗證碼和語音通信等功能,這里只測試使用短信驗證碼的功能,因此只需完成注冊登錄(無需實名認證等)即可使用其短信驗證碼免費測試服務,不過免費測試服務只能給控制台中指定的三個手機號發送短信,且只能有一個短信模板可以使用.

在該網址 https://doc.yuntongxun.com/p/5a533e0c3b8496dd00dce08c 可以查看python發送短信的demo實例和源碼下載.下載后目錄如下:

 使用時,在項目目錄中新建一個文件夾(如yuntongxun)將SDK中的兩個文件 CCPRestSDK.py 和 xmltojson.py 放入該文件夾中.然后再使用DEMO中的 SendTemplateSMS.py 來調用SDK中的py文件即可.這里我們不使用官方提供的 SendTemplateSMS.py ,而是將其改造封裝成一個單例模式的類的方式調用,文件名為sms.py

# coding=utf-8

from .CCPRestSDK import REST

# 主帳號
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


class CCP(object):
    """自己封裝的發送短信的輔助類"""
    # 用來保存對象的類屬性
    instance = None

    def __new__(cls):
        # 判斷CCP類有沒有已經創建好的對象,如果沒有,創建一個對象,並且保存
        # 如果有,則將保存的對象直接返回
        if cls.instance is None:
            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 = obj

        return cls.instance

    def send_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":
            # 表示發送短信成功
            return 0
        else:
            # 發送失敗
            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
import base64
import datetime
# import urllib2
import urllib.request as urllib2 # py3.x
import json
from .xmltojson import xmltojson
from xml.dom import minidom 

class REST:
    
    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
    
    def setAccount(self,AccountSid,AccountToken):
      self.AccountSid = AccountSid;
      self.AccountToken = AccountToken;   
    
  .......
# 發送模板短信 # @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; 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 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.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) 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':'網絡錯誤'}   .......#設置包頭 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")

上述語法改寫可以通過運行項目,看具體報錯信息一步一步改成python3的寫法,直到不報錯為止,但是項目雖然不報錯了,可還是不能成功發送短信,返回的報錯信息是 {'172001':'網絡錯誤'},經過百度和自己驗證后,發現還有三處需要注意修改:

1. 運行報錯:ModuleNotFoundError: No module named 'utils'

File "/home/python/study/ihome/ihome/libs/yuntongxun/sms.py", line 3, in <module>                                                                                                                                 
    from .CCPRestSDK import REST                                                                          
  File "/home/python/study/ihome/ihome/libs/yuntongxun/CCPRestSDK.py", line 18, in <module>               
    from xmltojson import xmltojson                                                                       
  File "/home/python/.virtualenvs/flask/bin/xmltojson.py", line 23, in <module>                           
    import utils                                                                                          
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)文件頂部插入:

import ssl

# 全局取消證書驗證
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()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM