这玩意也是鸽了老长时间,一开始我发现怎么做的时候就随便写了个雏形,然后也没用几次,后来又去鼓捣别的玩意,就这样给搁置了
今天晚上把它随便完善了一下
使用Python编写,需要requests库
首先要用这个脚本获取一下登录参数(token和authcode)
请务必保管好自己的token和authcode,一旦泄露,任何得到它的人都可以通过直接调用API来使用你的账号!
import gzip
import json
import random
import requests
from requests import HTTPError
def random_device_id() -> str:
"""
生成随机的设备ID(Device.Identifier),用于登录
设备ID是40个十六进制数字(字母小写,没有0x前缀)
:return: 随机设备ID字符串
"""
return hex(random.randint(0, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))[2:].rjust(40, '0')
headers = {
'x-API-Version': '2411',
'Accept-Encoding': 'gzip',
'Content-Type': 'gzipped/json'
}
def login(email: str, password: str) -> requests.Response:
data = {
'Login': email,
'Password': password,
'Version': 2411,
'Device': {
'Identifier': random_device_id(),
'Timezone': 'China Standard Time',
'Language': 'Chinese'
}
}
g = gzip.compress(json.dumps(data).encode('utf-8'))
return requests.post('https://physics-api-cn.turtlesim.com/Users/Authenticate', headers=headers, data=g)
def main():
email = input('请输入邮箱:')
password = input('请输入密码:')
resp = login(email, password)
resp.raise_for_status()
data = resp.json()
if data['Status'] == 403:
raise RuntimeError('邮箱或密码错误')
elif data['Status'] != 200:
raise RuntimeError(f'登录失败,错误{data["Status"]},信息:{data["Message"]}')
token = data['Token']
authcode = data['AuthCode']
print(f'token:{token}')
print(f'authcode:{authcode}')
if __name__ == '__main__':
try:
main()
except HTTPError as e:
print('网络或服务端错误:', e)
except RuntimeError as e:
print(e)
下面这个才是换封面脚本,登录成功得到token和authcode之后,把它以字符串的形式填到下面这个脚本的headers字典中,按提示操作即可
import gzip
import json
import os
import re
import requests
from requests import HTTPError
headers = {
'x-API-Token': token, # token,
'x-API-AuthCode': authcode, # authcode,
'x-API-Version': '2411',
'Accept-Encoding': 'gzip',
'Content-Type': 'gzipped/json'
}
def json_gzip_encode(data: dict) -> bytes:
"""
字典转JSON并用GZIP压缩
:param data: 要转换的字典
:return: 转换后的bytes
"""
return gzip.compress(json.dumps(data).encode('utf-8'))
def get_summary(content_id: str, category: str) -> requests.Response:
"""
获取实验介绍(没有电路)
:param content_id: 实验序号
:param category: 实验分区,实验区 = Experiment,黑洞区 = Discussion
:return: 响应对象
"""
data = {
'ContentID': content_id,
'Category': category
}
return requests.post('https://physics-api-cn.turtlesim.com/Contents/GetSummary',
headers=headers,
data=json_gzip_encode(data))
def submit_experiment(data: dict) -> requests.Response:
"""
更新实验
:param data: 实验的字典
:return: 响应对象
"""
return requests.post('https://physics-api-cn.turtlesim.com/Contents/SubmitExperiment',
headers=headers,
data=json_gzip_encode(data))
def upload(filename: str, policy: str, authorization: str) -> requests.Response:
"""
上传实验图片
:param filename: 图片文件名
:param policy: 由更新实验请求得到的policy字段
:param authorization: 由更新实验请求得到的authorization字段
:return: 响应对象
"""
with open(filename, 'rb') as f:
data = {
'policy': (None, policy, None),
'authorization': (None, authorization, None),
'file': ('temp.jpg', f, None)
}
return requests.post('http://v0.api.upyun.com/qphysics', files=data)
def confirm_experiment(summary_id: str, category: str, image: int) -> requests.Response:
"""
实验图片上传完成后的确认
:param summary_id: 实验序号
:param category: 实验分区,实验区 = Experiment,黑洞区 = Discussion
:param image: 图片序号
:return: 响应对象
"""
data = {
'Category': category,
'SummaryID': summary_id,
'Image': image,
'Extension': '.jpg'
}
return requests.post('https://physics-api-cn.turtlesim.com/Contents/ConfirmExperiment',
headers=headers,
data=json_gzip_encode(data))
def main():
content_id = input('请输入实验序号:').strip()
category_input = input('请输入实验分区,1=实验,2=黑洞:').strip()
filename = input('请输入图片文件名:').strip('"')
if not re.match('^[a-fA-F0-9]{24}$', content_id):
raise RuntimeError('实验序号无效')
categories = {'1': 'Experiment', '2': 'Discussion'}
if category_input not in categories:
raise RuntimeError('实验分区无效')
category = categories[category_input]
# ---------------------
# 获取实验简介
summary_resp = get_summary(content_id, category)
summary_resp.raise_for_status()
summary_json = summary_resp.json()
status = summary_json['Status']
message = summary_json['Message']
match status:
case 403:
raise RuntimeError(f'登录失效,请重新获取token和authcode({message})')
case 404:
raise RuntimeError(f'实验不存在,也可能是分区选错了!({message})')
case _ if status != 200:
raise RuntimeError(f'获取实验信息失败,错误{status},信息:{message}')
summary = summary_json['Data']
if '$type' in summary:
del summary['$type']
print('获取实验信息成功')
# ---------------------
# 更新实验
file_size = os.path.getsize(filename)
submit = {
'Request': {
'FileSize': file_size,
'Extension': '.jpg'
},
'Summary': summary
}
submit_resp = submit_experiment(submit)
submit_resp.raise_for_status()
submit_json = submit_resp.json()
status = submit_json['Status']
message = submit_json['Message']
if status == 403:
raise RuntimeError(f'这不是你的实验,无法更改封面({message})')
elif status != 200:
raise RuntimeError(f'更新实验(请求上传)失败,错误{status},信息:{message}')
print('更新实验(请求上传)成功')
# 上传
policy = submit_json['Data']['Token']['Policy']
authorization = submit_json['Data']['Token']['Authorization']
upload(filename, policy, authorization)
print('图片上传完成')
# 确认
confirm_experiment(summary_id=summary['ID'],
category=category,
image=summary['Image'] + 1)
print('更新图片序号完成')
print('更换封面成功')
if __name__ == '__main__':
try:
main()
except HTTPError as e:
print('网络或服务端错误:', e)
except OSError as e:
print('图片文件不存在', e)
except RuntimeError as e:
print(e)