2025-03-18 08:46:50 +08:00

229 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/python
#coding: utf-8
# +-------------------------------------------------------------------
# | django-vue-lyadmin 专业版
# +-------------------------------------------------------------------
# | Author: lybbn
# +-------------------------------------------------------------------
# | QQ: 1042594286
# +-------------------------------------------------------------------
# | Date: 2023-10-21
# +-------------------------------------------------------------------
# | version: 1.0
# +-------------------------------------------------------------------
# 抖音开放平台接口
# ------------------------------
import json
import requests
import logging
from urllib import parse
from django.core.cache import cache
logger = logging.getLogger(__name__)
class douyin:
def __init__(self, client_key: str, client_secret: str):
self._client_key = client_key # 应用唯一标识
self._client_secret = client_secret # 应用密钥
self._gate_way = "https://open.douyin.com/"
def _request(self, url: str, params: dict, method: str = "post",headers=None,isJson=True) -> json:
"""
请求
:param url: 接口url
:param params: 业务参数字典,示例:{'client_secret':'xxxx','aaa':'xxxx'}
:param method: post 请求、 get请求
"""
try:
if not headers:
headers = {}
if isJson:
headers.update({'Content-Type': 'application/json'})
headers.update({'Accept': 'application/json'})
else:
headers.update({'Content-Type': 'application/x-www-form-urlencoded'})
headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36'})
if method == "post":
if isJson:
param_json = json.dumps(params)
else:
param_json = parse.urlencode(params)
response = requests.post(url=url, data=param_json, headers=headers)
else:
response = requests.get(url=url, headers=headers)
if response.status_code != 200:
return None
return json.loads(response.content)
except Exception as e:
logger.error('请求地址:{}报错,{}'.format(url,e))
return None
def create_code(self,scope,redirect_uri="",optionalScope="",state="state") -> None:
"""
生成授权链接,获取授权码打开该url后页面会出现一个二维码用户扫描该二维码即可授权,在抖音 APP 支持端内唤醒的版本内打开的话会弹出客户端原生授权页面)
生成的url链接给前端用户pc浏览器访问或ur链接地址转换成二维码用抖音app扫码(注意该URL不是用来请求的, 需要展示给用户用于扫码)
用户允许授权后将会重定向到redirect_uri的网址上并且带上code和state参数
scope: 应用授权作用域,多个授权作用域以英文逗号(,)分隔
state: 用于保持请求和回调的状态
redirect_uri:需要配置再抖音的授权回调白名单,否则报错,回调地址一定要采用https协议
"""
url = self._gate_way+"platform/oauth/connect/?client_key={}&response_type=code&scope={}&optionalScope={}&redirect_uri={}&state={}".format(self._client_key,scope,optionalScope,redirect_uri,state)
return url
def callback_code(self,data):
"""
验证处理抖音开放平台code授权回调返回的code信息
用户允许授权后将会重定向到redirect_uri的网址上并且带上code和state参数
使用apiview获取回调请求数据
"""
code = data.get("code")
state = data.get("state")
return code,state
def get_access_token(self,code):
"""
获取access_token过期时间 15 天)
当 access_token 过期(过期时间 15 天)后,可以通过该接口使用 refresh_token过期时间 30 天进行刷新。刷新后获得一个有效期为15天的 access_token但是 refresh_token 的有效期保持不变。
若 refresh_token 过期,获取 access_token 会报错error_code=10010此时需要重新引导用户授权。
注意:获取到 access_token 后授权临时票据 (code) 不要再授权刷新,否则会导致上一次获取的 code 过期。
"""
url = self._gate_way+"oauth/access_token/"
param = {
"client_secret":self._client_secret,
"code":code,
"grant_type":"authorization_code",
"client_key":self._client_key
}
return self._request(url=url,params=param,method="post")
def refresh_refresh_token(self,refresh_token):
"""
刷新 refresh_token过期时间 30 天)
该接口用于刷新 refresh_token 的有效期。使用前提:client_key 必须拥有 renew_refresh_token 权限。
刷新操作需要在 refresh_token 过期前进行。
通过旧的 refresh_token 获取新的 refresh_token调用后旧 refresh_token 会失效,新 refresh_token 有 30 天有效期。最多只能获取 5 次新的 refresh_token5 次过后需要用户重新授权。
"""
url = self._gate_way+"oauth/renew_refresh_token/"
param = {
"refresh_token":refresh_token,
"client_key":self._client_key
}
return self._request(url=url,params=param,method="post",isJson=False)
def create_client_token(self):
"""
该接口用于获取接口调用的凭证 client_token
client_token 用于不需要用户授权就可以调用的接口。
client_token 的有效时间为 2 个小时,重复获取 client_token 后会使上次的 client_token 失效(但有 5 分钟的缓冲时间,连续多次获取 client_token 只会保留最新的两个 client_token
"""
url = self._gate_way+"oauth/client_token/"
param = {
"grant_type":"client_credential",
"client_key":self._client_key,
"client_secret":self._client_secret,
}
res = self._request(url=url,params=param,method="post")
if res and "error_code" in res["data"] and res["data"]["error_code"] == 0:
access_token = res.get('data').get("access_token")
expires_in = res.get('data').get("expires_in")
cache.set("douyin_client_token"+self._client_key, access_token,expires_in - 3000)
return access_token
return None
def get_client_token(self):
"""
获取client_token
"""
client_token = cache.get("douyin_client_token"+self._client_key)
if client_token:
return client_token
return self.create_client_token()
def refresh_access_token(self,refresh_token):
"""
该接口用于刷新 access_token 的有效期;
当 access_token 过期(过期时间 15 天)后,可以通过该接口使用 refresh_token过期时间 30 天进行刷新。刷新后获得一个有效期为15天的 access_token但是 refresh_token 的有效期保持不变。
若 refresh_token 过期,获取 access_token 会报错error_code=10010此时需要重新引导用户授权。
用户可以在抖音-我-设置(右上角)-帐号与安全-授权管理 中取消对应用的授权,取消授权后原有 access_token 会立即失效。
抖音开放平台会定期对用户授权进行检查,取消不合规的 access_token 授权。
"""
url = self._gate_way+"oauth/refresh_token/"
param = {
"grant_type":"refresh_token",
"client_key":self._client_key,
"refresh_token":refresh_token,
}
return self._request(url=url,params=param,method="post",isJson=False)
def get_userinfo(self,access_token,open_id):
"""
该接口获取用户的抖音公开信息,包含昵称和头像,适用于抖音、抖音极速版
若需要获取用户手机号,需要用户额外授权 mobile_alert 权限,本接口会额外返回 encrypt_mobile 字段
open_id:通过 /oauth/access_token/ 获取的,用户唯一标识
"""
url = self._gate_way+"oauth/userinfo/"
params = {
"access_token":access_token,
"open_id":open_id
}
return self._request(url=url,params=params,method="post",isJson=False)
def get_usermobile(self):
"""
该接口在用户公开信息的基础上,额外获取用户的手机号。
需要抖音开放平台申请权限。路径:抖音开放平台控制台 > 应用详情 > 能力管理 > 用户权限 > 获取用户手机号
注意事项:
1、用户授权后获取用户公开信息接口会额外返回 encrypt_mobile 字段。
2、解密手机号使用 AES 算法解密,秘钥是 client_secret 向量 lv 是 client_secret 前 16 字节。
"""
pass
def get_userfans(self,open_id="",date_type=7):
"""
获取用户粉丝数
open_id:用户openid
date_type数字型 近7/15天输入7代表7天、15代表15天、30代表30天
https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/data-open-service/user-data/get-user-fans-count
"""
url = self._gate_way+"data/external/user/fans/"
params = {
"date_type":date_type,
"open_id":open_id
}
res = self._request(url=url,params=params,method="post",isJson=True)
if res and "error_code" in res["data"] and res["data"]["error_code"] == 0:
return res["data"]["result_list"]
return None
def get_billboard_live(self):
"""
获取直播榜数据,不需要用户授权(使用client_token)
https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/data-open-service/tops-data/live-list-data/live-list
"""
url = self._gate_way+"data/extern/billboard/live/"
client_token = self.get_access_token()
headers = {}
headers.update({'Content-Type': 'application/json'})
headers.update({'access-token': client_token})
res = self._request(url=url,method="get",headers=headers)
if res and "error_code" in res["data"] and res["data"]["error_code"] == 0:
return res["data"]["list"]
return None
def video_search(self,access_token,open_id,cursor=0,count=10,keyword=""):
"""
通过关键词搜索全站视频,类似抖音端上搜索。使用前请到 管理中心-应用详情-关键词视频管理-关键词管理 创建关键词
该接口只返回最近 1 天的视频
cursor:分页游标, 第一页请求cursor是0, response中会返回下一页请求用到的cursor, 同时response还会返回has_more来表明是否有更多的数据。
count:每页数量
keyword:关键词
https://developer.open-douyin.com/docs/resource/zh-CN/dop/develop/openapi/search-management/keywords-video-list/keywords-video
"""
url = self._gate_way+"video/search/?open_id="+open_id+"&cursor="+cursor+"&count="+count+"&keyword="+keyword
headers = {}
headers.update({'Content-Type': 'application/json'})
headers.update({'access-token': access_token})
res = self._request(url=url,method="get",headers=headers)
if res and "error_code" in res["data"] and res["data"]["error_code"] == 0:
return res["data"]
return None