四、Python-Redis、加密和解密、mock接口開發、網絡請求


(一)Redis

1、數據庫分為關系型數據庫和非關系型數據庫:

(1)關系型數據庫分為:MySQL、Oracle、SQL Server、SQLite...

  數據庫

  表

  SQL語句

(2)非關系型數據庫分為:NoSQL(Redis、MongoDB...)

  key-value

  Redis:存在內存里面,做緩存用。

  MongoDB:放在磁盤里面。

 

2、Redis(Remote Dictionary Server):(摘自:http://www.redis.cn/)

  Redis 是一個開源(BSD許可)的,內存中的數據結構存儲系統,它可以用作數據庫、緩存和消息中間件。 它支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與范圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內置了 復制(replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁盤持久化(persistence), 並通過 Redis哨兵(Sentinel)和自動 分區(Cluster)提供高可用性(high availability)。

 

3、Redis與其他key-value緩存產品的特點:

(1)Redis支持數據的持久化,將內存中的數據保存在磁盤中,重啟后再次可以加載使用;

(2)Redis不僅支持簡單的key-value類型的數據,還支持list、set、zset、hash數據結構存儲;

(3)Redis支持數據備份,master-slave模式的數據備份。

 

4、根據自己的需求到官網下載安裝:https://redis.io/download

 

5、Redis 命令參考:http://doc.redisfans.com/

 

6、數據結構:

(1)String:字符串,最基本的數據類型,最大能存儲512MB。

(2)Hash:散列,是一個string類型的field和value的映射表,特別適合用於存儲對象。(存儲、讀取、修改用戶屬性)

(3)List:列表,是簡單的字符串類別,按照插入順序排序。

(4)Set:集合,是string類型的無序集合,通過hash表實現的。

(5)Sorted Set:有序集合,是string類型元素的集合,且不允許重復的成員。

 

7、連接Redis:如圖所示,填寫自己的配置:

(1)配置信息填寫:

 

 

(2)測試連接:

 

 

(3)查看當前庫里的信息,都是key-value 結構:

 

 

8、使用Python來操作Redis-String類型,相當於字典類型

(1)Python中使用connection連接Redis

import redis
r = redis.Redis(host='118.24.3.40',
                password='HK139bc&*',
                port=6379,
                db=2,
                decode_responses=True
                )

 

(2)Python中利用跳板機ssh遠程連接redis

from sshtunnel import SSHTunnelForwarder # ssh連接庫
import redis # redis模塊
server = SSHTunnelForwarder(
        ssh_address_or_host= , # ssh地址
        ssh_username=     , # ssh連接的用戶名                    
        ssh_password=  ,  # ssh連接的用戶名
        remote_bind_address=('遠程機器地址', 端口號))

server.start()
r=redis.Redis(host='redis地址', port=server.local_bind_port, decode_responses=True)
server.close() #關閉連接

 

(3)string類型:添加數據

import redis
r = redis.Redis(host='118.24.3.40',
                password='HK139bc&*',
                port=6379,
                db=2,
                decode_responses=True
                )
#string
r.set('iphone','{"price":6999,"count":50}')

執行這個程序后,去Redis客戶端查看是否有該數據存在:

 

(4)string類型:獲取數據

r.set('students','{"name":John,"age":15,"hobby":"playing Games"}')
print(r.get('students'))

  執行結果為:

 

(5)string類型:刪除數據

import redis
r = redis.Redis(host='118.24.3.40',
                password='HK139bc&*',
                port=6379,
                db=2,
                decode_responses=True
                )
r.set('礦泉水','{"price":10.5,"count":20}')
data = r.get('礦泉水')
r.delete('礦泉水')

 

(6)string類型:修改數據

import redis
r = redis.Redis(host='118.24.3.40',
                password='HK139bc&*',
                port=6379,
                db=2,
                decode_responses=True
                )
r.set('礦泉水','{"price":10.5,"count":20}')
r.set('礦泉水','xxxx')

 

(7)bytes:字節類型(上傳一個圖片或者下載一個圖片會遇到這個字節類型)

# bytes類型通過wb寫入
f = open('a.jpg','wb')
f.write('xxx')

         bytes類型和字符串類型相互轉換

data = r.get('礦泉水')
data.decode()  # bytes類型轉換成字符串
s='hello'
s.encode()     # 字符串轉換成bytes類型

 

(8)Python中設置過期時間:(指定某個key的過期時間)

expire_time = 60 * 60 * 24
r.set('Bob_session','sdgx312vsdrq',expire_time)

Redis客戶端過期時間顯示:

 

 

 9、使用Python來操作Redis-hash類型,相當於二維字典

(1)Hash添加數據

r.hset('salary','Ann','{"money":2500}')
r.hset('salary','Sarah','{"money":5500}')
r.hset('salary','Sun','{"money":3860}')
r.hset('salary','Beans','{"money":7800}')

  Redis客戶端查看新增的數據:

 

(2)Hash獲取數據

# 獲取單個數據
print(r.hget('salary','Ann'))

# 獲取所有的數據
int(r.hgetall('salary'))

 

(3)Hash-當含有bytes類型,需要變成正常的字典類型

d = r.hgetall('students')
new_d  = {}
for k,v in d.items():
     new_d[k.decode()] = v.decode()
print(new_d)

  從根源上解決Bytes類型問題:

r = redis.Redis(host='118.24.3.40',
                password='HK139bc&*',
                port=6379,
                db=2,
                decode_responses=True     # 解決Bytes類型問題
                )

 

(4)Hash-修改數據

(5)Hash-刪除數據

r.hdel('salary','Bob')

 

(6)設置過期時間

# 指定某個key的過期時間
r.expire('salary',1000) 

 

10、String和Hush(Redis客戶端展示)

(1)String

 

 (2)Hash

(3)從Redis取數據:Key是什么,Key的類型是什么

(4)刪掉大Key值:

r.delete('students')

 

11、Redis其他命令:

# 獲取當前數據庫有多少key
print(r.keys())

# 獲取具體的某個開頭的key進行匹配
print(r.keys('s*'))

#查看key的類型
print(r.type('students'))

# 清空當前數據庫里面所有的key
print(r.flushdb()) 

# 清空所有數據庫里面所有的key
print(r.flushall())

#判斷Key存不存在
print(r.exists('students'))    

 

12、Redis-管道:批量操作

(1)Python中建立管道,批量執行操作

p= r.pipeline()  #建立管道

p.hset('salary','Ann','{"money":2500}')
p.hset('salary','Sarah','{"money":5500}')
p.hset('salary','Sun','{"money":3860}')
p.hset('salary','Beans','{"money":7800}')

# 執行,返回一個list,這個list里面是每個命令執行的結果
p.execute() 

 

(2)使用管道和不用管道對比時間:

import redis
import time

r = redis.Redis(host='118.24.3.40',
                password='HK139bc&*',
                port=6379,
                db=2,
                decode_responses=True
                )
# 不用管道:
start_time =time.time()
for i in range(100):
    r.set('key%s'%i,'%s'%i)
print('不用管道的時間',time.time() - start_time)

# 使用管道:
start_time =time.time()
p = r.pipeline()
for i in range(100):
    p.set('pipeline_key%s'%i,'%s'%i)
p.execute()
print('用管道的時間',time.time() - start_time)

執行最后的結果為:

 

13、Python里新增數據帶有文件夾,key里有冒號:就會有文件夾

r.set('product:water','{"count":1,"price":5}')
r.set('product:apple','{"count":1,"price":15}')
r.set('product:melon','{"count":1,"price":35}')

  在Redis客戶端中可以查看到添加的文件夾里數據信息

 

 

14、當前服務器需要向另外一個服務器進行Redis數據遷移

編程分析:

 

r = redis.Redis(host='118.24.3.40',
                 password='HK139bc&*',
                 port=6379,
                 db=14,
                 decode_responses=True
                 )

r2 = redis.Redis(host='118.24.3.40',
                 password='HK139bc&*',
                 port=6378,
                 db=14,
                 decode_responses=True
                 )
p = r2.pipeline()

for k in r.keys():
     key_type = r.type(k)
     if key_type == 'string':
         value = r.get(k)
         p.set(k,value)
     elif key_type =='hash':
         hash_data = r.hgetall(k) # {'XX':XXX}
         for field,data in hash_data.items():
             p.hset(k,field,data)
p.execute()

 

15、若需要多個數據庫操作,需要循環數據庫:(一般用不到)

for i in range(17):
    r = redis.Redis(host='118.24.3.40',
                    password='HK139bc&*',
                    port=6379,
                    db=i,
                    decode_responses=True
                    )
    r2 = redis.Redis(host='118.24.3.40',
                    password='HK139bc&*',
                    port=6379,
                    db=i,
                    decode_responses=True
                    )

 

(二)加密和解密

1、加密,md5是一種不可逆,同時也是常見的加密方式,需要導入hashlib模塊:

(1)實例1代碼:

import hashlib

s = '123456'

# 對字符串進行加密
m = hashlib.md5(s) 

 # 加密后的結果用二進制表示 
result = m.hexdigest() 
print(result)

 

(2)執行結果報錯,這是因為MD5必須傳Bytes類型的:hashlib.md5()

 

 (3)解決方法:將字符串轉換成bytes類型

#導入hashlib模塊
import hashlib

# 定義字符串
s = '123456'

# 將字符串轉換成bytes類型
s =s.encode()

# 對字符串進行加密
m = hashlib.md5(s) 

# 加密后的結果用二進制表示 
result = m.hexdigest()  
print(result)

執行結果為:

 

(4)同樣的字符串,MD5出來的結果都一樣

 

(5)加鹽,例如設置用戶表

import hashlib

# 密碼+隨機字符串(隨機字符串就叫鹽值)
s = '123=123' + 'djsjks51@#$$' 

# 轉換成bytes
s = s.encode()   
m = hashlib.md5(s)  # bytes,不可逆
result = m.hexdigest()
print(result)

 

(6)定義函數

def my_md5(s):
    s = str(s)
    s = s.encode()
    m = hashlib.md5(s)
    result = m.hexdigest()
    return result

 

2、加密主要有兩種方式:對稱加密和非對稱加密

(1)對稱加密:對稱加密算法在加密和解密時使用的是同一個秘鑰。

對稱加密的模式是:甲方選擇某一種加密規則,對信息進行加密;乙方使用同一種規則,對信息進行解密;

客戶端和服務端進行通信,采用對稱加密,若使用同一個秘鑰很容易破解,若使用不同的秘鑰,秘鑰的管理和傳輸成本又較高;

(2)非對稱加密:非對稱加密算法需要兩個秘鑰來進行加密和解密,分別為:公開密碼(公鑰)和私有秘鑰(私鑰)。

乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰是保密的。

甲方獲取乙方的公鑰,然后用它對信息加密。

(3)http和https

常規的http請求,明文傳播;

https可以認為是:http + TLS ,TLS是傳輸層加密協議,前身是SSL協議

 

3、解密(撞庫解密)

(1)拖庫與撞庫:

 拖庫是指黑客盜取了網站的數據庫。撞庫是指黑客用拖庫獲得的用戶名和密碼在其它網站批量嘗試登陸,進而盜取更有價值的東西。由於一些用戶在多個網站用相同的用戶名和密碼,所以撞庫是有一定成功率的。要想撞庫,必須得知道密碼的明文,也就是用戶真正輸入的密碼。

(2)MD5實際上只能破解比較簡單的密碼

 

 4、Base64加密:是可以破解的

(1)例如百度搜索“動畫片”url中里面是轉譯密文

https://www.baidu.com/s?wd=%E5%8A%A8%E7%94%BB%E7%89%87&rsv_spt=1&rsv_iqid=0xcc0d32ae00192d4f&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_enter=0&rsv_dl=tb&oq=%25E5%258A%25A0%25E5%25AF%2586%25E6%2592%259E%25E5%25BA%2593&rsv_t=298fJqJmONwDQA1vi18GP009wC%2Fh67nlOij54DtqzQ7X6efhzWNd7AcKIyB6FO0SBNyM&rsv_btype=t&inputT=10055&rsv_pq=b07987030011a206&rsv_sug3=80&rsv_sug1=32&rsv_sug7=101&bs=%E5%8A%A0%E5%AF%86%E6%92%9E%E5%BA%93

(2)Base64使用:

import base64
# 一般用於傳輸數據過程中
# 加密
s = 'sjfkjdkjxh1145646你好'
r = base64.b64encode(s.encode())
result =r.decode()
print(result)

# 解密
r = base64.b64decode('c2pma2pka2p4aDExNDU2NDbkvaDlpb0=')
print(r.decode)

 

(三)mock接口開發:開發接口,模擬數據

1、Python中可安裝flash模塊或fastapi模塊:

# 建議安裝FastAPI接口
pip install fastapi

# 若安裝了FastAPI,還需要安裝一個ASGI服務器,用於生產如Uvicorn或Hypercorn
pip install uvicorn

# 或者安裝Flask
pip install Flask

 

2、FastAPI (摘自:https://fastapi.tiangolo.com/)

FastAPI是一種現代、快速(高性能)的Web框架,快速編碼,更少的錯誤,直觀簡易,短而健壯,基於API的開放標准:OpenAPI(舊稱Swagger)和JSON Schema。

 

3、如何mock接口開發:

(1)例如銀行姓名需要查詢產品、開戶接口

# Product 
{
"code":0,
"data":[
{"id":1,"product_name":"XXX"},
{"id":2,"product_name":"XXX"},
{"id":3,"product_name":"XXX"},
{"id":4,"product_name":"XXX"},
{"id":5,"product_name":"XXX"}
]
}

 

(2)使用fastapi編寫接口

import fastapi   # 自動生成一個API接口文檔
import uvicorn

# 啟動一個服務
server = fastapi.FastAPI()

@server.get('/login')
def login(username:str,password:str):
    return {'username':username,'password':password}
uvicorn.run(server,port=8800,debug=True)

執行結果如下:

 

 (3)復制url在瀏覽器打開,添加參數:http://127.0.0.1:8800/login

 

 (4)在http://127.0.0.1:8800/login,再次補充其他參數:http://127.0.0.1:8800/login?username=Ann&password=123456

 

 (5)定義一個不加參數的接口:

@server.get('/test')
def test():
    return {'msg':'hello world!'}
uvicorn.run(server,port=8800,debug=True)

  在瀏覽器打開輸入url:http://127.0.0.1:8800/test,就可以看到無參數的接口信息

 

 (6)查看接口文檔:http://127.0.0.1:8800/docs(根據設置的端口進行查看)

 

 (7)在接口文檔中修改參數進行執行

 

 執行結果如下:

 

(8)定義一個product接口:

import fastapi
import uvicorn
server = fastapi.FastAPI()

@server.get('/product')
def test():
    return {
        'code':0,
        'data':[
            {'product_name': '基金1號', 'status': 0},
            {'product_name': '基金2號', 'status': 2},
            {'product_name': '基金3號', 'status': 1},
            {'product_name': '基金4號', 'status': 0},
            {'product_name': '基金5號', 'status': 1}
        ]
    }

 

執行結果是:

   

注: http://127.0.0.1指的是本機的IP地址

若想別人訪問你的地址需要加上host:,例如:

# 自己訪問自己,無需加host

uvicorn.run(server,port=8800,debug=True)

# 若別人訪問你的地址,需要加上host

uvicorn.run(server,port=8800,debug=True,host='0.0.0.0')

# http://127.0.0.1:8800/product
# http://192.168.1.xx:8800/product

 

 (9)定義一個支付pay的接口

import fastapi
import uvicorn
server = fastapi.FastAPI()

@server.get('/pay')
def pay(money:float,status:str):
    if status == '0':
        return {'code':1, 'status':'fail'}
    elif status=='1':
        return {'code':0, 'status':'success','balance':money}

uvicorn.run(server,port=8800,debug=True)

 

打開瀏覽器,url中輸入:http://127.0.0.1:8800/pay?money=1&status=0,如圖所示:

 

  

pay接口中,status加上默認值1:

@server.get('/pay')

# status加上默認值1
def pay(money:float,status='1'):
    if status == '0':
        return {'code':1, 'status':'fail'}
    elif status=='1':
        return {'code':0, 'status':'success','balance':money}

uvicorn.run(server,port=8800,debug=True)

 

接口文檔中顯示默認值1:

 

 

  (10)定義一個注冊接口

@server.post('/register')
def register(username:str,password:str,cpassword:str):
    if username.strip() and password.strip() and cpassword.strip():
        if password.strip() != cpassword.strip():
            return {'code':-1, 'msg':'兩次輸入的密碼不一致!'}
        else:
            sql = 'select * from app_myuser where username="%s";'%username
            if tools.execute_sql(sql):
                return {'code':-1, 'msg':'用戶已經存在!'}
            else:
                p = tools.my_md5(password)
                insert_sql = 'insert into app_myuser (username,password) values ("%s","%s");'%(username,p)
                tools.execute_sql(insert_sql)
                return {'code':0, 'msg':'注冊成功!'}
    else:
        return {'code':-1, 'msg':'必填參數不能為空!'}

 

前往postman應用中,進行接口測試:

 

 (11)定義一個登錄接口:

@server.post('/login')
def login(username:str=Form(...),password:str=Form(...)):
    if username.strip() and password.strip():
        p = tools.my_md5(password)
        sql = 'select * from app_myuser where username="%s" and password="%s";' % (username,p)
        if tools.execute_sql(sql):
            return {'code': 0, 'msg': '登錄成功!'}
        else:
            return {'code':-1, 'msg':'輸入的賬號/密碼不存在!'}
    else:
        return {'code':-1, 'msg':'必填參數不能為空!'}

 

 4、flask:開發接口

(1)安裝flask模塊:

pip install flask

 

(2)用flask定義一個登錄接口:

# flask 是一個輕量級web開發框架
import flask

import tools

# 因為flask返回的是一個字符串,故需要導入JSON模塊
import json
server = flask.Flask(__name__)


@server.route('/login',methods=['post','get'])
def login():
    username = flask.request.values.get('username')
    password = flask.request.values.get('password')

    # flask.json.get('xxxx')           # 如果入參是json類型的話,使用這樣的方式
    # flask.request.cookies.get('xxx') # 獲取cookie里面的數據
    # flask.request.headers.get('xx')
    # flask.request.files.get("xxx")   # 文件

    if username.strip() and password.strip():
        p = tools.my_md5(password)
        query_sql = 'select * from app_myuser where username= "%s" and passwd="%s";' % (username, p)
        print(query_sql)
        if tools.execute_sql(query_sql):
            return json.dumps({'code': '0', 'msg': '登錄成功'},ensure_ascii=False)
        else:
            return json.dumps({'code': '-1', 'msg': '輸入的用戶名/密碼錯誤'})
    else:
        return json.dumps({'code': '-1', 'msg': '不能為空'})


server.run(host='0.0.0.0',port=8999,debug=True)

 

(3)定義一個注冊接口:

import flask

import tools

# 因為flask返回的是一個字符串,故需要導入JSON模塊
import json
server = flask.Flask(__name__)

@server.route('/reg',methods=['post','get'])
def reg():
    username = flask.request.values.get('username')
    password = flask.request.values.get('password')
    cpassword = flask.request.values.get('cpassword')
    if username.strip() and password.strip() and cpassword.strip():
        if password.strip() != cpassword.strip():
            return json.dumps({'code': -1, 'msg': '兩次輸入的密碼不一樣'})
        else:
            sql='select * from app_myuser where username="%s";'%username
            if tools.execute_sql(sql):
                return json.dumps({'code':-1,'msg':'用戶已經存在'})
            else:
                p = tools.my_md5(password)
                insert_sql = 'insert into app_myuser (username,passwd) value ("%s","%s");'%(username,p)
                tools.execute_sql(insert_sql)
                return json.dumps({'code':0,'msg':'注冊成功!'},ensure_ascii=False)

    else:
        return json.dumps({'code':-1,'msg':'必填參數不能為空'})


server.run(host='0.0.0.0',port=8999,debug=True)

 

(四)網絡請求:做接口自動化

1、Python自帶的模塊發送網絡請求:urllib

(1)安裝urllib模塊

import urllib

 

(2)urllib模塊:get請求

from urllib import request
import json

url = 'http://127.0.0.1:8999/login?username=Bob&password=123456'

# get請求
req = request.urlopen(url)

dic = json.loads(req.read().decode())

print(dic)

 

(3)urllib模塊:post請求

# post請求
from urllib import request
from urllib.parse import urlencodeimport json

url = 'http://127.0.0.1:8999/login'
data ={'username':'Ann01','password':'123456'}
req = request.urlopen(url,urlencode(data).encode())
dic = json.loads(req.read().decode())
print(dic)

 

2、requests模塊

(1)接口測試的請求方式:get、post、傳cookie、傳文件、傳json、傳headers

(2)安裝requests模塊

pip install requests

 

(3)使用requests查看請求

import requests
import json

url = 'http://127.0.0.1:8999/login'
data ={'username':'Ann01','password':'123456'}

r = requests.get(url,data)

# 字典類型
print(r.json)

# 字符串格式
print(r.text)

# bytes類型的
print(r.content)

#返回的狀態碼:200、404、500、502
print(r.status_code)

 

(4)get請求方式(根據使用情況選擇不同的方法):

# 字典格式,為了獲取某個字段的值:d.get('XXX')
r.json

# 字符串格式:接口返回結果不處理,直接存入庫里或者json文件里面
r.text

# bytes類型,例如下載一個圖片
r.content

#返回的狀態碼
r.status_code

 

(5)post請求方式:

r = requests.post(url,data)

print(r.json())

print(r.text)

print(r.content)

print(r.status_code)

 

(6)post請求url中,有時會遇到url帶有參數,這時候需要:

r = requests.post(url,data,params={"version":1.0)
# params是把參數傳到url后頭的

 

(7)傳cookie:

# url=http://www.nnzhp.cn/
# cookie:PHPSESSID=8a97d6ac860319bf067a674b8b5a8e34

cookie = {'PHPSESSID':'8a97d6ac860319bf067a674b8b5a8e34'}
r = requests.post(url,data=data,params={"version":1.0},cookies=cookie)

 

(8)傳headers:

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36','cookie':'PHPSESSID':'8a97d6ac860319bf067a674b8b5a8e34'}
r = requests.post(url,data=data,params={"version":1.0},headers=headers)

 

(9)傳json和傳文件

# 傳json

r = requests.post(url,json=data)
print(r.json())

# 傳文件

url = 'http://api.nnzhp.cn/api/file/file_upload'
data = {'file':open('XXX.xls','rb')} 
r = requests.post(url,files=data)

 

(10)下載文件

#下載文件

r = requests.get('https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3086278442,1750390944&fm=26&gp=0.jpg')

f = open('dog.jpg','wb')
print(r.content)
f.close()

 

注:有時會遇到https的報錯,這時需要:

r = requests.get('https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3086278442,1750390944&fm=26&gp=0.jpg',verify=False)

 


免責聲明!

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



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