From 3517364a63bae01a0542570a1f8a5180af018562 Mon Sep 17 00:00:00 2001 From: Womsxd <45663319+Womsxd@users.noreply.github.com> Date: Sun, 23 May 2021 21:24:20 +0800 Subject: [PATCH] push --- .gitignore | 129 +++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 21 ++++++++ config.json | 17 +++++++ config.py | 86 +++++++++++++++++++++++++++++++ genshin.py | 34 +++++++++++++ login.py | 30 +++++++++++ mihoyobbs.py | 82 ++++++++++++++++++++++++++++++ request.py | 26 ++++++++++ requirements.txt | 1 + run.py | 33 ++++++++++++ setting.py | 53 +++++++++++++++++++ tools.py | 48 ++++++++++++++++++ 12 files changed, 560 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 config.json create mode 100644 config.py create mode 100644 genshin.py create mode 100644 login.py create mode 100644 mihoyobbs.py create mode 100644 request.py create mode 100644 requirements.txt create mode 100644 run.py create mode 100644 setting.py create mode 100644 tools.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6e4761 --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..83040a8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Womsxd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/config.json b/config.json new file mode 100644 index 0000000..d8d1322 --- /dev/null +++ b/config.json @@ -0,0 +1,17 @@ +{ + "mihoyobbs_Login_ticket": "", + "mihoyobbs_Stuid": "", + "mihoyobbs_Stoken": "", + "mihoyobbs_Cookies": "", + "mihoyobbs": { + "bbs_Gobal": true, + "bbs_Singin": true, + "bbs_Singin_multi": true, + "bbs_Singin_multi_list": [2, 5], + "bbs_Read_posts": true, + "bbs_Like_posts": true, + "bbs_Unlike": true, + "bbs_Share": true + }, + "genshin_AutoSingin": false +} \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..ed732ed --- /dev/null +++ b/config.py @@ -0,0 +1,86 @@ +import os +import json +from tools import log + +#这里的内容会自动获取 +mihoyobbs_Login_ticket = "" +mihoyobbs_Stuid = "" +mihoyobbs_Stoken = "" +#这里填入你的米游社Cookie +mihoyobbs_Cookies = "" +#这个dist里面的内容和米游社有关 +mihoyobbs = { + #全局开关,关闭之后下面的都不执行 + "bbs_Gobal": True, + #讨论区签到 + "bbs_Singin": True, + #多个讨论区签到 + "bbs_Singin_multi": True, + #指定签到讨论区 + "bbs_Singin_multi_list": [2,5], + #浏览3个帖子 + "bbs_Read_posts": True, + #完成5次点赞 + "bbs_Like_posts": True, + #完成后取消点赞 + "bbs_Unlike": True, + #分享帖子 + "bbs_Share": True, + } +#原神自动签到 +genshin_AutoSingin = True + +path = os.path.dirname(os.path.realpath(__file__)) + +def Load_config(): + with open(f"{path}/config.json", "r") as f: + data = json.load(f) + global mihoyobbs_Login_ticket + global mihoyobbs_Stuid + global mihoyobbs_Stoken + global mihoyobbs_Cookies + global mihoyobbs + mihoyobbs_Login_ticket = data["mihoyobbs_Login_ticket"] + mihoyobbs_Stuid = data["mihoyobbs_Stuid"] + mihoyobbs_Stoken = data["mihoyobbs_Stoken"] + mihoyobbs_Cookies = data["mihoyobbs_Cookies"] + mihoyobbs["bbs_Gobal"] = data["mihoyobbs"]["bbs_Gobal"] + mihoyobbs["bbs_Singin"] = data["mihoyobbs"]["bbs_Singin"] + mihoyobbs["bbs_Singin_multi"] = data["mihoyobbs"]["bbs_Singin_multi"] + mihoyobbs["bbs_Singin_multi_list"] = data["mihoyobbs"]["bbs_Singin_multi_list"] + mihoyobbs["bbs_Read_posts"] = data["mihoyobbs"]["bbs_Read_posts"] + mihoyobbs["bbs_Like_posts"] = data["mihoyobbs"]["bbs_Like_posts"] + mihoyobbs["bbs_Unlike"] = data["mihoyobbs"]["bbs_Unlike"] + mihoyobbs["bbs_Share"] = data["mihoyobbs"]["bbs_Share"] + genshin_AutoSingin = data["genshin_AutoSingin"] + f.close() + log.info("Config加载完毕") + +def Save_config(): + with open(f"{path}/config.json","r+") as f: + data = json.load(f) + data["mihoyobbs_Login_ticket"] = mihoyobbs_Login_ticket + data["mihoyobbs_Stuid"] = mihoyobbs_Stuid + data["mihoyobbs_Stoken"] = mihoyobbs_Stoken + f.seek(0) + f.truncate() + temp_Text = json.dumps(data, sort_keys=False, indent=4, separators=(', ', ': ')) + f.write(temp_Text) + f.flush() + f.close() + log.info("Config保存完毕") + +def Clear_cookies(): + with open(f"{path}/config.json","r+") as f: + data = json.load(f) + data["mihoyobbs_Login_ticket"] = "" + data["mihoyobbs_Stuid"] = "" + data["mihoyobbs_Stoken"] = "" + data["mihoyobbs_Cookies"] = "" + f.seek(0) + f.truncate() + temp_Text = json.dumps(data, sort_keys=False, indent=4, separators=(', ', ': ')) + f.write(temp_Text) + f.flush() + f.close() + log.info("Cookie删除完毕") \ No newline at end of file diff --git a/genshin.py b/genshin.py new file mode 100644 index 0000000..0933050 --- /dev/null +++ b/genshin.py @@ -0,0 +1,34 @@ +import time +import httpx +import tools +import config +import random +import setting + +class genshin: + def __init__(self) -> None: + self.headers = { + 'Accept': 'application/json, text/plain, */*', + 'DS': tools.Get_ds(web=True, web_old=True), + 'Origin': 'https://webstatic.mihoyo.com', + 'x-rpc-app_version': setting.mihoyobbs_Version_old, + 'User-Agent': 'Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0', + 'x-rpc-client_type': setting.mihoyobbs_Client_type_web, + 'Referer': 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon', + 'Accept-Encoding': 'gzip, deflate', + 'Accept-Language': 'zh-CN,en-US;q=0.8', + 'X-Requested-With': 'com.mihoyo.hyperion', + "Cookie": config.mihoyobbs_Cookies + } + self.acc_List = self.Getacc_list() + #获取绑定的账号列表 + def Getacc_list(self) -> list: + temp_List = [] + req = httpx.get(setting.accinfo_Url, headers=self.headers) + data = req.json() + if (data["rercode"] != 0): + tools.log.warn("获取账号列表失败!") + exit() + for i in data["data"]["list"]: + temp_List.append([i["nickname"], i["game_uid"], i["region"]]) + return (temp_List) diff --git a/login.py b/login.py new file mode 100644 index 0000000..7abc1cc --- /dev/null +++ b/login.py @@ -0,0 +1,30 @@ +from tools import log +import config +import request +import setting + +def login(): + if (config.mihoyobbs_Cookies == ''): + log.error("请填入Cookies!") + exit() + temp_Cookies = {} + if ("login_ticket" in config.mihoyobbs_Cookies): + temp_Cookies = config.mihoyobbs_Cookies.split(";") + for i in temp_Cookies: + if (i.split("=")[0] == " login_ticket"): + config.mihoyobbs_Login_ticket = i.split("=")[1] + break + data = request.get(url=setting.cookieUrl.format(config.mihoyobbs_Login_ticket)) + if ("成功" in data["data"]["msg"]): + config.mihoyobbs_Stuid = str(data["data"]["cookie_info"]["account_id"]) + data = request.get(url=setting.cookieUrl2.format(config.mihoyobbs_Login_ticket, config.mihoyobbs_Stuid)) + config.mihoyobbs_Stoken = data["data"]["list"][0]["token"] + log.info("登录成功!") + log.info("正在保存Config!") + config.Save_config() + else: + log.error("cookie已失效,请重新登录米游社抓取cookie") + exit() + else: + log.error("cookie中没有'login_ticket'字段,请重新登录米游社,重新抓取cookie!") + exit() \ No newline at end of file diff --git a/mihoyobbs.py b/mihoyobbs.py new file mode 100644 index 0000000..214f5b2 --- /dev/null +++ b/mihoyobbs.py @@ -0,0 +1,82 @@ +import time +import httpx +import tools +import config +import random +import setting + + +class mihoyobbs: + def __init__(self): + self.headers = { + "DS": tools.Get_ds(web=False, web_old=False), + "cookie": f"stuid={config.mihoyobbs_Stuid};stoken={config.mihoyobbs_Stoken}", + "x-rpc-client_type": setting.mihoyobbs_Client_type, + "x-rpc-app_version": setting.mihoyobbs_Version, + "x-rpc-sys_version": "6.0.1", + "x-rpc-channel": "mihoyo", + "x-rpc-device_id": tools.Random_text(20) + tools.Random_text(12), + "x-rpc-device_name": tools.Random_text(random.randint(1, 10)), + "x-rpc-device_model": "Mi 10", + "Referer": "https://app.mihoyo.com", + "Host": "bbs-api.mihoyo.com", + "User-Agent": "okhttp/4.8.0" + } + self.postsList = self.Getlist() + #进行签到操作 + def Singin(self): + tools.log.info("正在签到......") + for i in setting.mihoyobbs_List_Use: + req = httpx.post(url=setting.signUrl.format(i["id"]), data="" ,headers=self.headers) + data = req.json() + if ("err" not in data["message"]): + tools.log.info(str(i["name"]+ data["message"])) + time.sleep(2) + else: + tools.log.info("签到失败,你的cookie可能已过期,请重新设置cookie。") + config.Clear_cookies() + exit() + #获取要帖子列表 + def Getlist(self) -> list: + temp_List = [] + tools.log.info("正在获取帖子列表......") + for i in setting.mihoyobbs_List_Use: + req = httpx.get(url=setting.listUrl.format(i["forumId"]), headers=self.headers) + data = req.json() + for n in range(10): + temp_List.append([data["data"]["list"][n]["post"]["post_id"], data["data"]["list"][n]["post"]["subject"]]) + tools.log.info("已获取{}个帖子".format(len(temp_List))) + time.sleep(2) + return (temp_List) + #看帖子 + def Readposts(self): + tools.log.info("正在看帖......") + for i in range(3): + req = httpx.get(url=setting.detailUrl.format(self.postsList[i][0]), headers=self.headers) + data = req.json() + if data["message"] == "OK": + tools.log.info("看帖:{} 成功".format(self.postsList[i][1])) + time.sleep(2) + #点赞 + def Likeposts(self): + tools.log.info("正在点赞......") + for i in range(5): + req = httpx.post(url=setting.likeUrl, headers=self.headers, + json={"post_id": self.postsList[i][0], "is_cancel": False}) + data = req.json() + if (data["message"] == "OK"): + tools.log.info("点赞:{} 成功".format(self.postsList[i][1])) + #判断取消点赞是否打开 + if (config.mihoyobbs["bbs_Unlike"] == True): + req = httpx.post(url=setting.likeUrl, headers=self.headers, + json={"post_id": self.postsList[i][0], "is_cancel": True}) + data = req.json() + if (data["message"] == "OK"): + tools.log.info("取消点赞:{} 成功".format(self.postsList[i][1])) + time.sleep(2) + def Share(self): + tools.log.info("正在分享......") + req = httpx.get(url=setting.shareUrl.format(self.postsList[0][0]), cookies=self.Cookie, headers=self.headers) + data = req.json() + if data["message"] == "OK": + tools.log.info("分享:{} 成功".format(self.postsList[0][1])) \ No newline at end of file diff --git a/request.py b/request.py new file mode 100644 index 0000000..0a1c66e --- /dev/null +++ b/request.py @@ -0,0 +1,26 @@ +import httpx + +#这里实际上应该加个"-> dict"但是考虑到请求可能失败的关系,所以直接不声明返回变量 +def get(url:str, **headers:dict): + try: + req = httpx.get(url, headers=headers) + return (req.json()) + except: + print("请求失败,网络错误!") + return ("") + +def post(url:str, data:dict, **headers:dict): + try: + req = httpx.post(url, data=data, headers=headers) + return (req.json()) + except: + print("请求失败,网络错误!") + return ("") + +def post_json(url:str, json, **headers:dict): + try: + req = httpx.post(url, json=json, headers=headers) + return (req.json()) + except: + print("请求失败,网络错误!") + return ("") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0209699 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +httpx == 0.18.1 \ No newline at end of file diff --git a/run.py b/run.py new file mode 100644 index 0000000..27e7f44 --- /dev/null +++ b/run.py @@ -0,0 +1,33 @@ +import login +import config +import setting +import mihoyobbs + +#初始化,加载配置 +config.Load_config() +#检测参数是否齐全,如果缺少就进行登入操作 +if (config.mihoyobbs_Login_ticket == "" or config.mihoyobbs_Stuid == "" or config.mihoyobbs_Stoken == ""): + #登入 + login.login() +#获取要使用的BBS列表 +#判断是否开启bbs_Singin_multi +if (config.mihoyobbs["bbs_Singin_multi"] == True): + for i in setting.mihoyobbs_List: + if (int(i["id"]) in config.mihoyobbs["bbs_Singin_multi_list"]): + setting.mihoyobbs_List_Use.append(i) +else: + #关闭bbs_Singin_multi后只签到大别墅 + for i in setting.mihoyobbs_List: + if (int(i["id"]) == 5): + setting.mihoyobbs_List_Use.append(i) +#米游社签到 +if(config.mihoyobbs["bbs_Gobal"] == True): + bbs = mihoyobbs.mihoyobbs() + if (config.mihoyobbs["bbs_Singin"] == True): + bbs.Singin() + if (config.mihoyobbs["bbs_Read_posts"] == True): + bbs.Readposts() + if (config.mihoyobbs["bbs_Like_posts"] == True): + bbs.Likeposts() + if (config.mihoyobbs["bbs_Share"] == True): + bbs.Share() diff --git a/setting.py b/setting.py new file mode 100644 index 0000000..c006674 --- /dev/null +++ b/setting.py @@ -0,0 +1,53 @@ +#米游社的Salt +mihoyobbs_Salt = "fd3ykrh7o1j54g581upo1tvpam0dsgtf" +mihoyobbs_Salt_web = "14bmu1mz0yuljprsfgpvjh3ju2ni468r" +mihoyobbs_Salt_web_old = "h8w582wxwgqvahcdkpvdhbh2w9casgfl" +#米游社的版本 +mihoyobbs_Version = "2.7.0" #Slat和Version相互对应 +mihoyobbs_Version_old = "2.3.0" +#米游社的客户端类型 +mihoyobbs_Client_type = "2" #1为ios 2为安卓 +mihoyobbs_Client_type_web = "5" #4为pc web 5为mobile web +#米游社的分区列表 +mihoyobbs_List = [{ + "id": "1", + "forumId": "1", + "name": "崩坏3", + "url": "https://bbs.mihoyo.com/bh3/" + },{ + "id": "2", + "forumId": "26", + "name": "原神", + "url": "https://bbs.mihoyo.com/ys/" + },{ + "id": "3", + "forumId": "30", + "name": "崩坏2", + "url": "https://bbs.mihoyo.com/bh2/" + },{ + "id": "4", + "forumId": "37", + "name": "未定事件簿", + "url": "https://bbs.mihoyo.com/wd/" + },{ + "id": "5", + "forumId": "34", + "name": "大别野", + "url": "https://bbs.mihoyo.com/dby/" + }] + +#Config Load之后run里面进行列表的选择 +mihoyobbs_List_Use= [] + +#米游社的API列表 +cookieUrl = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}" +cookieUrl2 = "https://api-takumi.mihoyo.com/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}" +signUrl = "https://bbs-api.mihoyo.com/apihub/sapi/signIn?gids={}" # post +listUrl = "https://bbs-api.mihoyo.com/post/api/getForumPostList?forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1" +detailUrl = "https://bbs-api.mihoyo.com/post/api/getPostFull?post_id={}" +shareUrl = "https://bbs-api.mihoyo.com/apihub/api/getShareConf?entity_id={}&entity_type=1" +likeUrl = "https://bbs-api.mihoyo.com/apihub/sapi/upvotePost" # post json + +#原神自动签到相关的设置 +act_ID = "e202009291139501" +accinfo_Url = "https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=hk4e_cn" \ No newline at end of file diff --git a/tools.py b/tools.py new file mode 100644 index 0000000..d4f95de --- /dev/null +++ b/tools.py @@ -0,0 +1,48 @@ +import logging +import time +import random +import string +import hashlib +import setting + +#Log输出 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s %(levelname)s %(message)s', + datefmt='%Y-%m-%dT%H:%M:%S') + +log = logger = logging + +#md5计算 +def MD5(text:str) -> str: + md5 = hashlib.md5() + md5.update(text.encode()) + return (md5.hexdigest()) + +#随机文本 +def Random_text(num:int) -> str: + return(''.join(random.sample(string.ascii_lowercase + string.digits, num))) + +#时间戳 +def Timestamp() -> int: + return(int(time.time())) + +#获取请求Header里的DS 当web为true则生成网页端的DS +def Get_ds(web:bool, web_old:bool) -> str: + if(web == True): + if(web_old == True): + n = setting.mihoyobbs_Salt_web_old + else: + n = setting.mihoyobbs_Salt_web + else: + n = setting.mihoyobbs_Salt + i = str(Timestamp()) + r = Random_text(6) + c = MD5("salt=" + n + "&t=" + i + "&r=" + r) + return (i + "," + r + "," + c) + +#获取明天早晨0点的时间戳 +def Nextday() -> int: + now_time = int(time.time()) + nextday_time = now_time - now_time % 86400 + time.timezone + 86400 + return (nextday_time) \ No newline at end of file