您好,登錄后才能下訂單哦!
目錄:
1.?urllib介紹
2.?功能開發http_util.py
3.?單元測試test_http_util.py,實際調用百度AI語音合成接口
4.?常見問題和解決方法
一,urllib介紹
Python在AI領域是主流開發語言,更多的軟件應用開發也開始使用Python,有非常多且好用的標準庫和第三方組件,urllib是Python自帶的標準庫,不需要安裝,用于HTTP開發,主要模塊和功能:
1.?urllib.request: 發送HTTP請求,接收處理HTTP響應
2.?urllib.error: 處理錯誤和異常,包含urllib.request拋出的異常
3.?urllib.parse: 解析URL和編碼數據
4.?urllib.robotparser: 解析robots.txt
本文介紹urllib庫中的request, error, parse三個模塊在HTTP開發時的代碼應用,并封裝成http_util,單元測試函數實際調用百度AI語音合成接口,和項目開發一致:
1,調用鑒權接口獲取token:https://openapi.baidu.com/oauth/2.0/token
2,調用語音合成接口轉換文本為語音:https://tsn.baidu.com/text2audio
開源項目:https://github.com/jextop/starter_service
示例代碼:https://github.com/rickding/HelloPython/tree/master/hello_http
├── util
│ ??└── http_util.py
│ ??└── file_util.py
│ ??└── code_util.py
├── tests
│ ??└── test_http_util.py
二,功能開發
代碼文件 | 功能要點 | |
功能開發 | http_util.py | 調用urllib發送請求,接收和處理響應 |
單元測試 | test_http_util.py | 測試封裝的功能函數,調用百度AI鑒權接口獲取access_token,調用語音合成接口將文本轉換為語音 |
輔助功能 | file_util.py | 下載文件時,保存文件 |
code_util.py | 保存文件時生成唯一名稱 |
1.?urllib.request.urlopen()可以直接調用url地址,得到響應,讀取數據,簡單HTTP請求使用起來非常方便:
from urllib import request
resp = request.urlopen(r'http://www.baidu.com')
data = resp.read()
data_str = data.decode('utf-8')
print(data_str)
2.?urllib.request.urlopen()支持Request類型參數,構造Request時配置更多的參數如header, data:
from urllib import parse
from urllib import request
req = request.Request(
????'https://tsn.baidu.com/text2audio',
????headers={
????????'Content-Type': 'application/x-www-form-urlencoded',
????},
????data=parse.urlencode({
????????'tex': 'Python開發HTTP請求和處理響應',
????}).encode('utf-8'),
????method='POST'
)
resp = request.urlopen(req)
data = resp.read()
data_str = data.decode('utf-8')
print(data_str)
3.?封裝http_data()函數,發起http請求和處理響應,注意encode()函數是對parse.urlencode()的調用封裝,將data轉換為byte數據:
import logging
from urllib import error
from urllib import parse
from urllib import request
log = logging.getLogger(__name__)
def http_data(url, headers={}, data=None, method=None):
????try:
????????req = request.Request(url, headers=headers, method=method, data=encode(data))
????????resp = request.urlopen(req)
????????data = resp.read()
????????log.info('http_data returns: %d, %s, %s' % (len(data), type(data), url))
????????return data
????except (ConnectionError, error.URLError) as e:
????????log.error('ConnectionError in http_data: %s, %s' % (url, str(e)))
????except Exception as e:
????????log.error('Exception in http_data: %s, %s' % (url, str(e)))
????return None
def encode(data):
????if isinstance(data, dict):
????????data = parse.urlencode(data)
????if isinstance(data, str):
????????data = data.encode('utf-8')
????return data
4.?封裝http_str(),將HTTP響應數據解析為字符串:
def http_str(url, headers={}, data=None, method=None):
????data = http_data(url, headers, data, method)
????return None if data is None else data.decode('utf-8')
5.?封裝http_json(),在響應數據為JSON內容時,解析為dict:
def http_json(url, headers={}, data=None, method=None):
????data = http_data(url, headers, data, method)
????return None if data is None else json.loads(data)
6.?封裝http_file(),下載文件時,返回數據為二進制文件內容,存儲到服務器或客戶端,代碼詳見http_util.http_file()函數,執行流程:
a)?拼裝請求參數,得到響應,調用resp.read()讀取二進制數據文件內容
b)?讀取頭信息Content-Disposition,是否返回了文件名稱?比如:attachment;fileName=zip.zip
c)?讀取頭信息Content-Type,解析文件格式,比如:audio/wav
d)?將文件數據保存
三,單元測試test_http_util.py
調用http_util封裝的功能函數,測試如下:
1.?test_http_str()請求http://www.baidu.com,得到字符串信息:
class HttpUtilTest(TestCase):
????def test_http_str(self):
????????ret_str = http_str('http://www.baidu.com')
????????log.info('http_str returns: %s' % ret_str[0: 20])
????????self.assertIsNotNone(ret_str)
2.?Test_http_json()調用百度鑒權接口庫,返回JSON格式數據,解析得到access_token
class HttpUtilTest(TestCase):
????def test_http_json(self):
????????ret_json = http_json('https://openapi.baidu.com/oauth/2.0/token', headers={
????????????'Content-Type': 'application/x-www-form-urlencoded',
????????}, data={
????????????'grant_type': 'client_credentials',
????????????'client_id': 'kVcnfD9iW2XVZSMaLMrtLYIz',
????????????'client_secret': 'O9o1O213UgG5LFn0bDGNtoRN3VWl2du6',
????????}, method='POST')
????????log.info('http_json returns: %s' % ret_json)
????????self.assertIsNotNone(ret_json)
????????token = ret_json.get('access_token')
????????print(token)
3.?call_http_file()調用百度AI語音合成接口,得到文本轉換成的語音數據,保存為文件:
class HttpUtilTest(TestCase):
????def call_http_file(self, token):
????????[ret, file_name, data] = http_file('https://tsn.baidu.com/text2audio', headers={
????????????'Content-Type': 'application/x-www-form-urlencoded',
????????}, data={
????????????'tex': 'Python開發異步任務調度和業務處理',
????????????'tok': token,
????????????'cuid': 'starter_service_http_util',
????????????'ctp': '1',
????????????'lan': 'zh',
????????????'spd': '6',
????????????'per': '1',
????????}, method='POST', save_to_disc=True, save_as_temp=False)
????????log.info('http_file returns: %s, %s, %s' % (ret, str(file_name), type(data)))
????????self.assertIsNotNone(ret is False or len(data) > 0)
4.?運行python manage.py test,得到語音文件<項目路徑>/tmp/http_download/xxx.mp3:
四,常見問題和解決方法
l?下載文件時,如果獲取文件名稱和類型?
解決:HTTP響應返回的頭信息中含有文件名稱和類型,但是注意這些信息可能沒有返回,代碼中要判斷信息不存在的情況:
- 頭信息Content-Disposition,包含文件名稱,比如:attachment;fileName=zip.zip
- 頭信息Content-Type,包含文件格式,比如:audio/wav
# parse file type, e.g. audio/wav
file_type = None
content_type = resp.getheader('Content-Type')
if '/' in str(content_type):
????file_type = content_type.split('/')[1]
# parse file name, e.g. attachment;fileName=zip.zip
file_name = None
disposition = resp.getheader('Content-Disposition')
if '=' in str(disposition):
????file_name = disposition.split('=')[1]
# use a new file name
if file_name is None:
????file_name = '%s.%s' % (get_code(), file_type or 'dat')
l?調用請求傳遞參數時出錯:
POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
另一個同類錯誤:
can't concat str to bytes
解決:調用urllib.parse.urlencode()將數據編碼,或者調用封裝的http_util.encode()
原因:urllib.request.Request()的data參數類型要求byte
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。