From 32cec2b0f2632fc167c975d7822be441f91f5016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Wed, 28 Jul 2021 08:44:01 +0000 Subject: [PATCH 01/12] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20AP?= =?UTF-8?q?Is.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIs.py | 122 -------------------------------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 APIs.py diff --git a/APIs.py b/APIs.py deleted file mode 100644 index 5bb9064..0000000 --- a/APIs.py +++ /dev/null @@ -1,122 +0,0 @@ -import requests -from json import dumps, loads -from bs4 import BeautifulSoup - -class codemaoAPI(object): - def __init__(self,UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',debug=False): - self.debug = debug - self.ses = requests.session() - self.headers = {"Content-Type": "application/json", "User-Agent": UA} - self.log('Successfully creat a codemao user.') - - def login(self,identity,password): - self.log('getting pid...') - soup = BeautifulSoup(requests.get('https://shequ.codemao.cn', headers = self.headers).text, 'html.parser') - pid = loads(soup.find_all("script")[0].string.split("=")[1])['pid'] - self.log('Successfully get pid;pid=' + pid) - self.log('loginning...') - a = self.ses.post('https://api.codemao.cn/tiger/v3/web/accounts/login', headers = self.headers,data = dumps({"identity": identity, "password": password, "pid": pid})) - if a.status_code == 200: - self.log("Successfully login to codemao.cn") - else: - self.log('End of login to codemao.cn;response', a.status_code) - - def log(self, *msg): - if self.debug: - print(*msg) - - def send_post(self, board, title, message): - self.log('posting...') - a = self.ses.post(f'https://api.codemao.cn/web/forums/boards/{board}/posts', headers = self.headers,data = dumps({'title': title, 'content': message})) - self.log('End.response', a.status_code) - - def replies(self, postID, message): - self.log('replieing...') - a = self.ses.post(f'https://api.codemao.cn/web/forums/posts/{postID}/replies', headers = self.headers,data = dumps({'content': message})) - self.log('End.response', a.status_code) - - def __delete_work(self, workID): # BUG - self.log('deleting...') - a = self.ses.delete(f'https://api.codemao.cn/tiger/work/{workID}/temporarily', headers = self.headers) - self.log('End.response', a.status_code) - - def __recove_work(self, workID): # BUG - self.log('recoving...') - a = self.ses.patch(f'https://api.codemao.cn/tiger/work/{workID}/recover', headers = self.headers) - self.log('End.response', a.status_code) - - def __permanent_work(self, workID): # BUG - self.log('permanenting...') - a = self.ses.delete(f'https://api.codemao.cn/tiger/work/{workID}/permanently', headers = self.headers) - self.log('End.response', a.status_code) - - def delete_all_work(self): - self.log('All work are permanenting...') - a = self.ses.delete('https://api.codemao.cn/tiger/work/user/works/permanently', headers = self.headers) - self.log('End.response', a.status_code) - - def send_post_to_work_shop(self, work_shop_ID, message): - self.log('posting...') - a = self.ses.post(f'https://api.codemao.cn/web/discussions/{work_shop_ID}/comment', headers = self.headers,data = dumps({"content": message, "rich_content": message, "source": "WORK_SHOP"})) - self.log('End.response', a.status_code) - - def top_replies(self, repliesID): - self.log('On top...') - a = self.ses.put(f'https://api.codemao.cn/web/forums/replies/{repliesID}/top', headers = self.headers, - data = r'{}') - self.log('End.response', a.status_code) - - def untop_replies(self, repliesID): - self.log('Untop...') - a = self.ses.delete(f'https://api.codemao.cn/web/forums/replies/{repliesID}/top', headers = self.headers) - self.log('End.response', a.status_code) - - def like_replies(self, repliesID): - self.log('liking...') - self.ses.put(f'https://api.codemao.cn/web/forums/comments/{repliesID}/liked?source=REPLY',headers = self.headers, data = r'{}') - self.log('End.response', a.status_code) - - def unlike_replies(self, repliesID): - self.log('Unliking...') - self.ses.delete(f'https://api.codemao.cn/web/forums/comments/{repliesID}/liked?source=REPLY',headers = self.headers) - - def search_post(self,key,to):#同步执行,可能帖子太多会有点慢。。。。 - self.log('searching...') - res=[] - page=1 - keeprun=True - while keeprun: - resp=self.ses.get(f'https://api.codemao.cn/web/forums/posts/search?title={key}&limit=30&page={page}',headers=self.headers).json() - if resp['items']==[]: - break - for msg in resp['items']: - if (to!=None) and (len(res)>=to): - keeprun=False - break - res.append({'user':{'userid':msg['user']['id'],'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) - page+=1 - return res - - def logout(self): - self.log('logouting...') - a=self.ses.options('https://api.codemao.cn/tiger/v3/web/accounts/logout',headers=self.headers) - if a.status_code==204: - self.log('Successfully logout from codemao.cn') - else: - self.log('End of logout from codemao.cn;response', a.status_code) - - def like_work(self,workID): - self.log('liking...') - a=self.ses.post(f'https://api.codemao.cn/nemo/v2/works/{workID}/like',headers=self.headers,data='{}') - if a.status_code==200: - self.log('Successfully like work') - else: - self.log('End of liking;response', a.status_code) - - def unlike_work(self,workID): - self.log('unliking...') - a=self.ses.delete(f'https://api.codemao.cn/nemo/v2/works/{workID}/like',headers=self.headers) - if a.status_code==200: - self.log('Successfully unlike work') - else: - self.log('End of unliking;response', a.status_code) \ No newline at end of file -- Gitee From 1fd0ae38b615194c96f3c330157036ca80a6a061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Wed, 28 Jul 2021 08:44:08 +0000 Subject: [PATCH 02/12] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20LI?= =?UTF-8?q?CENSE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d6993e3..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 wrmdcxy - -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. -- Gitee From 8d172109ca6e1bbc17ef908396f32ca6fb9a943b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Wed, 28 Jul 2021 08:44:17 +0000 Subject: [PATCH 03/12] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20RE?= =?UTF-8?q?ADME.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index 2dffd80..0000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# **codemao-apis** -
dd
"})) -print("成功" if a.status_code == 201 else "失败") \ No newline at end of file -- Gitee From a258053c5775ac205774d164a0c1c7b9e4a02765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Wed, 28 Jul 2021 08:45:54 +0000 Subject: [PATCH 05/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E6=89=A9=E5=B1=95=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 21 ++ api.py | 191 ++++++++++++++++++ test.py | 7 + ...66\345\270\226\347\245\236\345\231\250.py" | 25 +++ 4 files changed, 244 insertions(+) create mode 100644 LICENSE create mode 100644 api.py create mode 100644 test.py create mode 100644 "\351\241\266\345\270\226\347\245\236\345\231\250.py" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d6993e3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 wrmdcxy + +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/api.py b/api.py new file mode 100644 index 0000000..d4cd648 --- /dev/null +++ b/api.py @@ -0,0 +1,191 @@ +from requests import * +from json import dumps, loads +from bs4 import BeautifulSoup +import os + + +class CodemaoApi(): + def __init__(self, UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', debug=False): + # New: api sets + self.apis = {'home': 'https://shequ.codemao.cn', + 'matomoApi': 'https://matomo.codemao.cn/piwik.js', + 'login': 'https://api.codemao.cn/tiger/v3/web/accounts/login', + 'postArticle': 'https://api.codemao.cn/web/forums/boards/{}/posts', + 'postReply': 'https://api.codemao.cn/web/forums/posts/{}/replies', + 'clearWork': 'https://api.codemao.cn/tiger/work/user/works/permanently', + 'requireWorkshop': 'https://api.codemao.cn/web/discussions/{}/comment', + 'topReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'untopReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'likeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'unlikeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'searchArticle': 'https://api.codemao.cn/web/forums/posts/search?title={}&limit=30&page={}', + 'logout': 'https://api.codemao.cn/tiger/v3/web/accounts/logout', + 'likeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', + 'unlikeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like'} + self.debug = debug + # Use abs path to create in the root path, not cwd + self.logpath = os.path.split(__file__)[0] + os.sep + 'runtime.log' + self.ses = session() + self.headers = {"Content-Type": "application/json", "User-Agent": UA} + self.log('Successfully create the main session') + + def log(self, *msg): + if self.debug: + print(*msg) + # New: temp log file in the root dir + if not os.path.exists(self.logpath): + open(self.logpath, 'w', encoding='utf-8').close() + with open(self.logpath, 'a', encoding='utf-8') as log: + msg = [str(i) for i in msg] + text = ' '.join(msg) + '\n' # list -> str + log.write(text) + + def login(self, identity, password): + # Get PID + self.log('getting pid...') + text = get(self.apis['home'], headers = self.headers).text + soup = BeautifulSoup(text, 'html.parser') + json = soup.find('script').string.split("=")[1] + pid = loads(json)['pid'] + self.log('Successfully get pid; pid:' + pid) + # Log-in + self.log('logging in...') + res = self.ses.post(self.apis['login'], headers=self.headers, data=dumps({"identity": identity, "password": password, "pid": pid})) + if res.status_code == 200: + self.log("Successfully login to codemao.cn") + else: + self.log('End of logging in to codemao.cn; response', res.status_code) + return res.json() + + def logout(self): + self.log('logging out...') + res = self.ses.options(self.apis['logout'], headers=self.headers) + if res.status_code == 204: + self.log('Successfully log-out from codemao.cn') + else: + self.log('End of logout from codemao.cn; response', res.status_code) + return res.json() + + def postArticle(self, board, title, content): + self.log('posting...') + res = self.ses.post(self.apis['postArticle'].format(board), headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 201: + self.log("Successfully post article") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def postReply(self, arid, content): + self.log('posting...') + res = self.ses.post(self.apis['postReply'].format(arid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 200: + self.log("Successfully post reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + # Not changed + def __delete_work(self, workID): # BUG + self.log('deleting...') + a = self.ses.delete(f'https://api.codemao.cn/tiger/work/{workID}/temporarily', headerss = self.headerss) + self.log('End.response', a.status_code) + + def __recove_work(self, workID): # BUG + self.log('recoving...') + a = self.ses.patch(f'https://api.codemao.cn/tiger/work/{workID}/recover', headerss = self.headerss) + self.log('End.response', a.status_code) + + def __permanent_work(self, workID): # BUG + self.log('permanenting...') + a = self.ses.delete(f'https://api.codemao.cn/tiger/work/{workID}/permanently', headerss = self.headerss) + self.log('End.response', a.status_code) + + def clearWork(self): + self.log('clearing...') + res = self.ses.delete(self.apis['clearWork'], headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def requireWorkshop(self, wsid, content): + self.log('requiring...') + res = self.ses.post(self.apis['requireWorkshop'].format(wsid), headers=self.headers, data=dumps({'content': content, 'rich_content': content, 'source': 'WORK_SHOP'})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def topReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['topReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 200: + self.log("Successfully set top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def untopReply(self, rpid): + self.log('Setting...') + res = self.ses.delete(self.apis['untopReply'].format(rpid), headers=self.headers) + if res.status_code == 200: + self.log("Successfully cancel top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def likeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['likeReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 200: + self.log("Successfully set liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['unlikeReply'].format(rpid), headers=self.headers) + if res.status_code == 200: + self.log("Successfully cancel liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def searchArticle(self, key, to): + # Not changed + self.log('searching...') + res = [] + page = 1 + keeprun = True + while keeprun: + resp=self.ses.get(self.apis['searchArticle'].format(key, page), headers=self.headers).json() + if resp['items']==[]: + break + for msg in resp['items']: + if to != None and len(res) >= to: + keeprun = False + break + res.append({'user':{'userid':msg['user']['id'], 'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) + page+=1 + return res + + def likeWork(self, wkid): + self.log('setting...') + res = self.ses.post(self.apis['likeWork'].format(wkid), headers=self.headers, data=r'{}') + if res.status_code == 200: + self.log('Successfully set liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeWork(self,workID): + self.log('setting...') + res = self.ses.delete(self.apis['unlikeWork'].format(wkid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully cancel liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..eaf0c29 --- /dev/null +++ b/test.py @@ -0,0 +1,7 @@ +from api import * + +api = CodemaoApi(debug=True) +print(api.login('', '')) +print(api.postArticle('11', 'testing', 'dd
"})) +print("成功" if a.status_code == 201 else "失败") \ No newline at end of file -- Gitee From 6ea2429ae553170be40b63d16ae058f26a38f1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Wed, 28 Jul 2021 10:45:42 +0000 Subject: [PATCH 06/12] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20?= =?UTF-8?q?=E9=A1=B6=E5=B8=96=E7=A5=9E=E5=99=A8.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...66\345\270\226\347\245\236\345\231\250.py" | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 "\351\241\266\345\270\226\347\245\236\345\231\250.py" diff --git "a/\351\241\266\345\270\226\347\245\236\345\231\250.py" "b/\351\241\266\345\270\226\347\245\236\345\231\250.py" deleted file mode 100644 index 18c0dc0..0000000 --- "a/\351\241\266\345\270\226\347\245\236\345\231\250.py" +++ /dev/null @@ -1,25 +0,0 @@ -import requests -from guimaker import inputbox -from bs4 import BeautifulSoup -from json import loads,dumps - -identity=input("用户名/手机号/邮箱:") -password=input("密码:") - - -ses = requests.session() -headers = {"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"} -print('正在寻找登录密钥...') -soup = BeautifulSoup(requests.get('https://shequ.codemao.cn', headers = headers).text, 'html.parser') -pid = loads(soup.find_all("script")[0].string.split("=")[1])['pid'] -print('秘药为:',pid) -print('正在登录') -a = ses.post('https://api.codemao.cn/tiger/v3/web/accounts/login', headers = headers,data = dumps({"identity": identity, "password": password, "pid": pid})) -if a.status_code == 200: - print("登录成功") -else: - exit("不能登录编程猫") -print('正在顶帖') -postID = inputbox(type_ = int,text="ID?") -a = ses.post(f'https://api.codemao.cn/web/forums/posts/{postID}/replies', headers = headers,data = dumps({'content': "dd
"})) -print("成功" if a.status_code == 201 else "失败") \ No newline at end of file -- Gitee From 948b089dfa1b56c30ffa8efabb4f2eee9ae15b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Fri, 30 Jul 2021 03:02:27 +0000 Subject: [PATCH 07/12] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20ap?= =?UTF-8?q?i.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.py | 191 --------------------------------------------------------- 1 file changed, 191 deletions(-) delete mode 100644 api.py diff --git a/api.py b/api.py deleted file mode 100644 index d4cd648..0000000 --- a/api.py +++ /dev/null @@ -1,191 +0,0 @@ -from requests import * -from json import dumps, loads -from bs4 import BeautifulSoup -import os - - -class CodemaoApi(): - def __init__(self, UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', debug=False): - # New: api sets - self.apis = {'home': 'https://shequ.codemao.cn', - 'matomoApi': 'https://matomo.codemao.cn/piwik.js', - 'login': 'https://api.codemao.cn/tiger/v3/web/accounts/login', - 'postArticle': 'https://api.codemao.cn/web/forums/boards/{}/posts', - 'postReply': 'https://api.codemao.cn/web/forums/posts/{}/replies', - 'clearWork': 'https://api.codemao.cn/tiger/work/user/works/permanently', - 'requireWorkshop': 'https://api.codemao.cn/web/discussions/{}/comment', - 'topReply': 'https://api.codemao.cn/web/forums/replies/{}/top', - 'untopReply': 'https://api.codemao.cn/web/forums/replies/{}/top', - 'likeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', - 'unlikeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', - 'searchArticle': 'https://api.codemao.cn/web/forums/posts/search?title={}&limit=30&page={}', - 'logout': 'https://api.codemao.cn/tiger/v3/web/accounts/logout', - 'likeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', - 'unlikeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like'} - self.debug = debug - # Use abs path to create in the root path, not cwd - self.logpath = os.path.split(__file__)[0] + os.sep + 'runtime.log' - self.ses = session() - self.headers = {"Content-Type": "application/json", "User-Agent": UA} - self.log('Successfully create the main session') - - def log(self, *msg): - if self.debug: - print(*msg) - # New: temp log file in the root dir - if not os.path.exists(self.logpath): - open(self.logpath, 'w', encoding='utf-8').close() - with open(self.logpath, 'a', encoding='utf-8') as log: - msg = [str(i) for i in msg] - text = ' '.join(msg) + '\n' # list -> str - log.write(text) - - def login(self, identity, password): - # Get PID - self.log('getting pid...') - text = get(self.apis['home'], headers = self.headers).text - soup = BeautifulSoup(text, 'html.parser') - json = soup.find('script').string.split("=")[1] - pid = loads(json)['pid'] - self.log('Successfully get pid; pid:' + pid) - # Log-in - self.log('logging in...') - res = self.ses.post(self.apis['login'], headers=self.headers, data=dumps({"identity": identity, "password": password, "pid": pid})) - if res.status_code == 200: - self.log("Successfully login to codemao.cn") - else: - self.log('End of logging in to codemao.cn; response', res.status_code) - return res.json() - - def logout(self): - self.log('logging out...') - res = self.ses.options(self.apis['logout'], headers=self.headers) - if res.status_code == 204: - self.log('Successfully log-out from codemao.cn') - else: - self.log('End of logout from codemao.cn; response', res.status_code) - return res.json() - - def postArticle(self, board, title, content): - self.log('posting...') - res = self.ses.post(self.apis['postArticle'].format(board), headers=self.headers, data=dumps({'title': title, 'content': content})) - if res.status_code == 201: - self.log("Successfully post article") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def postReply(self, arid, content): - self.log('posting...') - res = self.ses.post(self.apis['postReply'].format(arid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 200: - self.log("Successfully post reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - # Not changed - def __delete_work(self, workID): # BUG - self.log('deleting...') - a = self.ses.delete(f'https://api.codemao.cn/tiger/work/{workID}/temporarily', headerss = self.headerss) - self.log('End.response', a.status_code) - - def __recove_work(self, workID): # BUG - self.log('recoving...') - a = self.ses.patch(f'https://api.codemao.cn/tiger/work/{workID}/recover', headerss = self.headerss) - self.log('End.response', a.status_code) - - def __permanent_work(self, workID): # BUG - self.log('permanenting...') - a = self.ses.delete(f'https://api.codemao.cn/tiger/work/{workID}/permanently', headerss = self.headerss) - self.log('End.response', a.status_code) - - def clearWork(self): - self.log('clearing...') - res = self.ses.delete(self.apis['clearWork'], headers=self.headers, data=dumps({'title': title, 'content': content})) - if res.status_code == 200: - self.log("Successfully send request to workshop") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def requireWorkshop(self, wsid, content): - self.log('requiring...') - res = self.ses.post(self.apis['requireWorkshop'].format(wsid), headers=self.headers, data=dumps({'content': content, 'rich_content': content, 'source': 'WORK_SHOP'})) - if res.status_code == 200: - self.log("Successfully send request to workshop") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def topReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['topReply'].format(rpid), headers=self.headers, data=r'{}') - if res.status_code == 200: - self.log("Successfully set top reply") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def untopReply(self, rpid): - self.log('Setting...') - res = self.ses.delete(self.apis['untopReply'].format(rpid), headers=self.headers) - if res.status_code == 200: - self.log("Successfully cancel top reply") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def likeReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['likeReply'].format(rpid), headers=self.headers, data=r'{}') - if res.status_code == 200: - self.log("Successfully set liked reply") - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def unlikeReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['unlikeReply'].format(rpid), headers=self.headers) - if res.status_code == 200: - self.log("Successfully cancel liked reply") - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def searchArticle(self, key, to): - # Not changed - self.log('searching...') - res = [] - page = 1 - keeprun = True - while keeprun: - resp=self.ses.get(self.apis['searchArticle'].format(key, page), headers=self.headers).json() - if resp['items']==[]: - break - for msg in resp['items']: - if to != None and len(res) >= to: - keeprun = False - break - res.append({'user':{'userid':msg['user']['id'], 'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) - page+=1 - return res - - def likeWork(self, wkid): - self.log('setting...') - res = self.ses.post(self.apis['likeWork'].format(wkid), headers=self.headers, data=r'{}') - if res.status_code == 200: - self.log('Successfully set liked work') - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def unlikeWork(self,workID): - self.log('setting...') - res = self.ses.delete(self.apis['unlikeWork'].format(wkid), headers=self.headers) - if res.status_code == 200: - self.log('Successfully cancel liked work') - else: - self.log('End of setting; response', res.status_code) - return res.json() \ No newline at end of file -- Gitee From 90cd978c0ea79e1333ac8a0abb00910b641aed18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Fri, 30 Jul 2021 03:02:46 +0000 Subject: [PATCH 08/12] update --- api.py | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 api.py diff --git a/api.py b/api.py new file mode 100644 index 0000000..2319667 --- /dev/null +++ b/api.py @@ -0,0 +1,265 @@ +from requests import * +from json import dumps, loads +from bs4 import BeautifulSoup +import os + + +class CodemaoApi(): + def __init__(self, UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', debug=False): + # New: api sets + self.apis = {'home': 'https://shequ.codemao.cn', + 'matomoApi': 'https://matomo.codemao.cn/piwik.js', + 'login': 'https://api.codemao.cn/tiger/v3/web/accounts/login', + 'logout': 'https://api.codemao.cn/tiger/v3/web/accounts/logout', + 'cookie': 'https://shequ.codemao.cn/user/', + 'getSelfInfo1': 'https://api.codemao.cn/web/users/details', + 'getSelfInfo2': 'https://api.codemao.cn/api/user/info', + 'getUserInfo': 'https://api.codemao.cn/api/user/info/detail/{}', + 'changeSelfInfo': 'https://api.codemao.cn/tiger/v3/web/accounts/info', + 'postArticle': 'https://api.codemao.cn/web/forums/boards/{}/posts', + 'deleteArticle': 'https://api.codemao.cn/web/forums/posts/{}', + 'postReply': 'https://api.codemao.cn/web/forums/posts/{}/replies', + 'deleteReply': 'https://api.codemao.cn/web/forums/replies/{}', + 'postL2Reply': 'https://api.codemao.cn/web/forums/replies/{}/comments', + 'deleteL2Reply': 'https://api.codemao.cn/web/forums/comments/{}', + 'clearWork': 'https://api.codemao.cn/tiger/work/user/works/permanently', + 'requireWorkshop': 'https://api.codemao.cn/web/discussions/{}/comment', + 'topReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'untopReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'likeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'unlikeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'searchArticle': 'https://api.codemao.cn/web/forums/posts/search?title={}&limit=30&page={}', + 'likeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', + 'unlikeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', + 'getArticleInfo': 'https://api.codemao.cn/web/forums/posts/{}/details'} + self.debug = debug + # Use abs path to create in the root path, not cwd + self.logpath = os.path.split(__file__)[0] + os.sep + 'runtime.log' + self.ses = session() + self.headers = {"Content-Type": "application/json", "User-Agent": UA} + self.log('Successfully create the main session') + + def log(self, *msg): + if self.debug: + print(*msg) + # New: temp log file in the root dir + if not os.path.exists(self.logpath): + open(self.logpath, 'w', encoding='utf-8').close() + with open(self.logpath, 'a', encoding='utf-8') as log: + msg = [str(i) for i in msg] + text = ' '.join(msg) + '\n' # list -> str + log.write(text) + + def login(self, identity='', password=''): + if identity and password: + # Get PID + self.log('getting pid...') + text = get(self.apis['home'], headers = self.headers).text + soup = BeautifulSoup(text, 'html.parser') + json = soup.find('script').string.split("=")[1] + pid = loads(json)['pid'] + self.log('Successfully get pid; pid:' + pid) + # Log-in + self.log('logging in...') + res = self.ses.post(self.apis['login'], headers=self.headers, data=dumps({"identity": identity, "password": password, "pid": pid})) + if res.status_code == 200: + self.log("Successfully login to codemao.cn") + else: + self.log('End of logging in to codemao.cn; response', res.status_code) + else: + res = self.ses.get(self.apis['cookie'], headers=self.headers) + if res.status_code == 200: + self.log("Successfully login to codemao.cn") + else: + self.log('End of logging with cookie; response', res.status_code) + return res.json() + + def logout(self): + self.log('logging out...') + res = self.ses.options(self.apis['logout'], headers=self.headers) + if res.status_code == 204: + self.log('Successfully log-out from codemao.cn') + else: + self.log('End of logout from codemao.cn; response', res.status_code) + return res.json() + + def getSelfInfo(self): + self.log('getting...') + res1 = self.ses.get(self.apis['getSelfInfo1'], headers=self.headers) + res2 = self.ses.get(self.apis['getSelfInfo2'], headers=self.headers) + if res1.status_code == 200 and res2.status_code == 200: + self.log('Successfully get self info') + else: + self.log('End of requiring; response', res1.status_code, res2.status_code) + return res1.json().update(res2.json()) + + def getUserInfo(self, urid): + self.log('getting...') + res = self.ses.get(self.apis['getUserInfo'].format(urid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully get info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def changeSelfInfo(self, info): + self.log('changing...') + res = self.ses.patch(self.apis['changeSelfInfo'].format(urid), headers=self.headers, data=dumps(info)) + if res.status_code == 200: + self.log('Successfully change info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def postArticle(self, board, title, content): + self.log('posting...') + res = self.ses.post(self.apis['postArticle'].format(board), headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 201: + self.log("Successfully post article") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteArticle(self, arid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteArticle'].format(arid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully delete article") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def postReply(self, arid, content): + self.log('posting...') + res = self.ses.post(self.apis['postReply'].format(arid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully post reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteReply(self, cmid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteReply'].format(cmid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully delete reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def postL2Reply(self, arid, cmid, content): + self.log('posting...') + res = self.ses.post(self.apis['postL2Reply'].format(arid), headers=self.headers, data=dumps({"parent_id":cmid, "content": content}) + if res.status_code == 204: + self.log("Successfully post reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteL2Reply(self, cmid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteL2Reply'].format(cmid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully delete reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def clearWork(self): + self.log('clearing...') + res = self.ses.delete(self.apis['clearWork'], headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def requireWorkshop(self, wsid, content): + self.log('requiring...') + res = self.ses.post(self.apis['requireWorkshop'].format(wsid), headers=self.headers, data=dumps({'content': content, 'rich_content': content, 'source': 'WORK_SHOP'})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def topReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['topReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 204: + self.log("Successfully set top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def untopReply(self, rpid): + self.log('Setting...') + res = self.ses.delete(self.apis['untopReply'].format(rpid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully cancel top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def likeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['likeReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 204: + self.log("Successfully set liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['unlikeReply'].format(rpid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully cancel liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def searchArticle(self, key, to): + # Not changed + self.log('searching...') + res = [] + page = 1 + keeprun = True + while keeprun: + resp=self.ses.get(self.apis['searchArticle'].format(key, page), headers=self.headers).json() + if resp['items']==[]: + break + for msg in resp['items']: + if to != None and len(res) >= to: + keeprun = False + break + res.append({'user':{'userid':msg['user']['id'], 'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) + page+=1 + return res + + def likeWork(self, wkid): + self.log('setting...') + res = self.ses.post(self.apis['likeWork'].format(wkid), headers=self.headers, data=r'{}') + if res.status_code == 200: + self.log('Successfully set liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeWork(self, wkid): + self.log('setting...') + res = self.ses.delete(self.apis['unlikeWork'].format(wkid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully cancel liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def getArticleInfo(self, arid): + self.log('getting...') + res = self.ses.get(self.apis['getArticleInfo'].format(arid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully get info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() \ No newline at end of file -- Gitee From 2cba24e4f66d881d770adb5fa71e0311998d0de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Fri, 30 Jul 2021 03:15:29 +0000 Subject: [PATCH 09/12] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20ap?= =?UTF-8?q?i.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.py | 265 --------------------------------------------------------- 1 file changed, 265 deletions(-) delete mode 100644 api.py diff --git a/api.py b/api.py deleted file mode 100644 index 2319667..0000000 --- a/api.py +++ /dev/null @@ -1,265 +0,0 @@ -from requests import * -from json import dumps, loads -from bs4 import BeautifulSoup -import os - - -class CodemaoApi(): - def __init__(self, UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', debug=False): - # New: api sets - self.apis = {'home': 'https://shequ.codemao.cn', - 'matomoApi': 'https://matomo.codemao.cn/piwik.js', - 'login': 'https://api.codemao.cn/tiger/v3/web/accounts/login', - 'logout': 'https://api.codemao.cn/tiger/v3/web/accounts/logout', - 'cookie': 'https://shequ.codemao.cn/user/', - 'getSelfInfo1': 'https://api.codemao.cn/web/users/details', - 'getSelfInfo2': 'https://api.codemao.cn/api/user/info', - 'getUserInfo': 'https://api.codemao.cn/api/user/info/detail/{}', - 'changeSelfInfo': 'https://api.codemao.cn/tiger/v3/web/accounts/info', - 'postArticle': 'https://api.codemao.cn/web/forums/boards/{}/posts', - 'deleteArticle': 'https://api.codemao.cn/web/forums/posts/{}', - 'postReply': 'https://api.codemao.cn/web/forums/posts/{}/replies', - 'deleteReply': 'https://api.codemao.cn/web/forums/replies/{}', - 'postL2Reply': 'https://api.codemao.cn/web/forums/replies/{}/comments', - 'deleteL2Reply': 'https://api.codemao.cn/web/forums/comments/{}', - 'clearWork': 'https://api.codemao.cn/tiger/work/user/works/permanently', - 'requireWorkshop': 'https://api.codemao.cn/web/discussions/{}/comment', - 'topReply': 'https://api.codemao.cn/web/forums/replies/{}/top', - 'untopReply': 'https://api.codemao.cn/web/forums/replies/{}/top', - 'likeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', - 'unlikeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', - 'searchArticle': 'https://api.codemao.cn/web/forums/posts/search?title={}&limit=30&page={}', - 'likeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', - 'unlikeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', - 'getArticleInfo': 'https://api.codemao.cn/web/forums/posts/{}/details'} - self.debug = debug - # Use abs path to create in the root path, not cwd - self.logpath = os.path.split(__file__)[0] + os.sep + 'runtime.log' - self.ses = session() - self.headers = {"Content-Type": "application/json", "User-Agent": UA} - self.log('Successfully create the main session') - - def log(self, *msg): - if self.debug: - print(*msg) - # New: temp log file in the root dir - if not os.path.exists(self.logpath): - open(self.logpath, 'w', encoding='utf-8').close() - with open(self.logpath, 'a', encoding='utf-8') as log: - msg = [str(i) for i in msg] - text = ' '.join(msg) + '\n' # list -> str - log.write(text) - - def login(self, identity='', password=''): - if identity and password: - # Get PID - self.log('getting pid...') - text = get(self.apis['home'], headers = self.headers).text - soup = BeautifulSoup(text, 'html.parser') - json = soup.find('script').string.split("=")[1] - pid = loads(json)['pid'] - self.log('Successfully get pid; pid:' + pid) - # Log-in - self.log('logging in...') - res = self.ses.post(self.apis['login'], headers=self.headers, data=dumps({"identity": identity, "password": password, "pid": pid})) - if res.status_code == 200: - self.log("Successfully login to codemao.cn") - else: - self.log('End of logging in to codemao.cn; response', res.status_code) - else: - res = self.ses.get(self.apis['cookie'], headers=self.headers) - if res.status_code == 200: - self.log("Successfully login to codemao.cn") - else: - self.log('End of logging with cookie; response', res.status_code) - return res.json() - - def logout(self): - self.log('logging out...') - res = self.ses.options(self.apis['logout'], headers=self.headers) - if res.status_code == 204: - self.log('Successfully log-out from codemao.cn') - else: - self.log('End of logout from codemao.cn; response', res.status_code) - return res.json() - - def getSelfInfo(self): - self.log('getting...') - res1 = self.ses.get(self.apis['getSelfInfo1'], headers=self.headers) - res2 = self.ses.get(self.apis['getSelfInfo2'], headers=self.headers) - if res1.status_code == 200 and res2.status_code == 200: - self.log('Successfully get self info') - else: - self.log('End of requiring; response', res1.status_code, res2.status_code) - return res1.json().update(res2.json()) - - def getUserInfo(self, urid): - self.log('getting...') - res = self.ses.get(self.apis['getUserInfo'].format(urid), headers=self.headers) - if res.status_code == 200: - self.log('Successfully get info.') - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def changeSelfInfo(self, info): - self.log('changing...') - res = self.ses.patch(self.apis['changeSelfInfo'].format(urid), headers=self.headers, data=dumps(info)) - if res.status_code == 200: - self.log('Successfully change info.') - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def postArticle(self, board, title, content): - self.log('posting...') - res = self.ses.post(self.apis['postArticle'].format(board), headers=self.headers, data=dumps({'title': title, 'content': content})) - if res.status_code == 201: - self.log("Successfully post article") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def deleteArticle(self, arid): - self.log('posting...') - res = self.ses.delete(self.apis['deleteArticle'].format(arid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully delete article") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def postReply(self, arid, content): - self.log('posting...') - res = self.ses.post(self.apis['postReply'].format(arid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully post reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def deleteReply(self, cmid): - self.log('posting...') - res = self.ses.delete(self.apis['deleteReply'].format(cmid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully delete reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def postL2Reply(self, arid, cmid, content): - self.log('posting...') - res = self.ses.post(self.apis['postL2Reply'].format(arid), headers=self.headers, data=dumps({"parent_id":cmid, "content": content}) - if res.status_code == 204: - self.log("Successfully post reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def deleteL2Reply(self, cmid): - self.log('posting...') - res = self.ses.delete(self.apis['deleteL2Reply'].format(cmid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully delete reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def clearWork(self): - self.log('clearing...') - res = self.ses.delete(self.apis['clearWork'], headers=self.headers, data=dumps({'title': title, 'content': content})) - if res.status_code == 200: - self.log("Successfully send request to workshop") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def requireWorkshop(self, wsid, content): - self.log('requiring...') - res = self.ses.post(self.apis['requireWorkshop'].format(wsid), headers=self.headers, data=dumps({'content': content, 'rich_content': content, 'source': 'WORK_SHOP'})) - if res.status_code == 200: - self.log("Successfully send request to workshop") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def topReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['topReply'].format(rpid), headers=self.headers, data=r'{}') - if res.status_code == 204: - self.log("Successfully set top reply") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def untopReply(self, rpid): - self.log('Setting...') - res = self.ses.delete(self.apis['untopReply'].format(rpid), headers=self.headers) - if res.status_code == 204: - self.log("Successfully cancel top reply") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def likeReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['likeReply'].format(rpid), headers=self.headers, data=r'{}') - if res.status_code == 204: - self.log("Successfully set liked reply") - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def unlikeReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['unlikeReply'].format(rpid), headers=self.headers) - if res.status_code == 204: - self.log("Successfully cancel liked reply") - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def searchArticle(self, key, to): - # Not changed - self.log('searching...') - res = [] - page = 1 - keeprun = True - while keeprun: - resp=self.ses.get(self.apis['searchArticle'].format(key, page), headers=self.headers).json() - if resp['items']==[]: - break - for msg in resp['items']: - if to != None and len(res) >= to: - keeprun = False - break - res.append({'user':{'userid':msg['user']['id'], 'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) - page+=1 - return res - - def likeWork(self, wkid): - self.log('setting...') - res = self.ses.post(self.apis['likeWork'].format(wkid), headers=self.headers, data=r'{}') - if res.status_code == 200: - self.log('Successfully set liked work') - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def unlikeWork(self, wkid): - self.log('setting...') - res = self.ses.delete(self.apis['unlikeWork'].format(wkid), headers=self.headers) - if res.status_code == 200: - self.log('Successfully cancel liked work') - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def getArticleInfo(self, arid): - self.log('getting...') - res = self.ses.get(self.apis['getArticleInfo'].format(arid), headers=self.headers) - if res.status_code == 200: - self.log('Successfully get info.') - else: - self.log('End of requiring; response', res.status_code) - return res.json() \ No newline at end of file -- Gitee From baadebb8c7b01f98ce3dd419094921ddc815d73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Fri, 30 Jul 2021 03:15:48 +0000 Subject: [PATCH 10/12] 2021/7/30 --- api.py | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 api.py diff --git a/api.py b/api.py new file mode 100644 index 0000000..8e42dcc --- /dev/null +++ b/api.py @@ -0,0 +1,265 @@ +from requests import * +from json import dumps, loads +from bs4 import BeautifulSoup +import os + + +class CodemaoApi(): + def __init__(self, UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', debug=False): + # New: api sets + self.apis = {'home': 'https://shequ.codemao.cn', + 'matomoApi': 'https://matomo.codemao.cn/piwik.js', + 'login': 'https://api.codemao.cn/tiger/v3/web/accounts/login', + 'logout': 'https://api.codemao.cn/tiger/v3/web/accounts/logout', + 'cookie': 'https://shequ.codemao.cn/user/', + 'getSelfInfo1': 'https://api.codemao.cn/web/users/details', + 'getSelfInfo2': 'https://api.codemao.cn/api/user/info', + 'getUserInfo': 'https://api.codemao.cn/api/user/info/detail/{}', + 'changeSelfInfo': 'https://api.codemao.cn/tiger/v3/web/accounts/info', + 'postArticle': 'https://api.codemao.cn/web/forums/boards/{}/posts', + 'deleteArticle': 'https://api.codemao.cn/web/forums/posts/{}', + 'postReply': 'https://api.codemao.cn/web/forums/posts/{}/replies', + 'deleteReply': 'https://api.codemao.cn/web/forums/replies/{}', + 'postL2Reply': 'https://api.codemao.cn/web/forums/replies/{}/comments', + 'deleteL2Reply': 'https://api.codemao.cn/web/forums/comments/{}', + 'clearWork': 'https://api.codemao.cn/tiger/work/user/works/permanently', + 'requireWorkshop': 'https://api.codemao.cn/web/discussions/{}/comment', + 'topReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'untopReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'likeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'unlikeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'searchArticle': 'https://api.codemao.cn/web/forums/posts/search?title={}&limit=30&page={}', + 'likeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', + 'unlikeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', + 'getArticleInfo': 'https://api.codemao.cn/web/forums/posts/{}/details'} + self.debug = debug + # Use abs path to create in the root path, not cwd + self.logpath = os.path.split(__file__)[0] + os.sep + 'runtime.log' + self.ses = session() + self.headers = {"Content-Type": "application/json", "User-Agent": UA} + self.log('Successfully create the main session') + + def log(self, *msg): + if self.debug: + print(*msg) + # New: temp log file in the root dir + if not os.path.exists(self.logpath): + open(self.logpath, 'w', encoding='utf-8').close() + with open(self.logpath, 'a', encoding='utf-8') as log: + msg = [str(i) for i in msg] + text = ' '.join(msg) + '\n' # list -> str + log.write(text) + + def login(self, identity='', password=''): + if identity and password: + # Get PID + self.log('getting pid...') + text = get(self.apis['home'], headers = self.headers).text + soup = BeautifulSoup(text, 'html.parser') + json = soup.find('script').string.split("=")[1] + pid = loads(json)['pid'] + self.log('Successfully get pid; pid:' + pid) + # Log-in + self.log('logging in...') + res = self.ses.post(self.apis['login'], headers=self.headers, data=dumps({"identity": identity, "password": password, "pid": pid})) + if res.status_code == 200: + self.log("Successfully login to codemao.cn") + else: + self.log('End of logging in to codemao.cn; response', res.status_code) + else: + res = self.ses.get(self.apis['cookie'], headers=self.headers) + if res.status_code == 200: + self.log("Successfully login to codemao.cn") + else: + self.log('End of logging with cookie; response', res.status_code) + return res.json() + + def logout(self): + self.log('logging out...') + res = self.ses.options(self.apis['logout'], headers=self.headers) + if res.status_code == 204: + self.log('Successfully log-out from codemao.cn') + else: + self.log('End of logout from codemao.cn; response', res.status_code) + return res.json() + + def getSelfInfo(self): + self.log('getting...') + res1 = self.ses.get(self.apis['getSelfInfo1'], headers=self.headers) + res2 = self.ses.get(self.apis['getSelfInfo2'], headers=self.headers) + if res1.status_code == 200 and res2.status_code == 200: + self.log('Successfully get self info') + else: + self.log('End of requiring; response', res1.status_code, res2.status_code) + return dict(res1.json(), **res2.json()) + + def getUserInfo(self, urid): + self.log('getting...') + res = self.ses.get(self.apis['getUserInfo'].format(urid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully get info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def changeSelfInfo(self, info): + self.log('changing...') + res = self.ses.patch(self.apis['changeSelfInfo'].format(urid), headers=self.headers, data=dumps(info)) + if res.status_code == 200: + self.log('Successfully change info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def postArticle(self, board, title, content): + self.log('posting...') + res = self.ses.post(self.apis['postArticle'].format(board), headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 201: + self.log("Successfully post article") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteArticle(self, arid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteArticle'].format(arid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully delete article") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def postReply(self, arid, content): + self.log('posting...') + res = self.ses.post(self.apis['postReply'].format(arid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully post reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteReply(self, cmid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteReply'].format(cmid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully delete reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def postL2Reply(self, arid, cmid, content): + self.log('posting...') + res = self.ses.post(self.apis['postL2Reply'].format(arid), headers=self.headers, data=dumps({"parent_id":cmid, "content": content})) + if res.status_code == 204: + self.log("Successfully post reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteL2Reply(self, cmid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteL2Reply'].format(cmid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully delete reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def clearWork(self): + self.log('clearing...') + res = self.ses.delete(self.apis['clearWork'], headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def requireWorkshop(self, wsid, content): + self.log('requiring...') + res = self.ses.post(self.apis['requireWorkshop'].format(wsid), headers=self.headers, data=dumps({'content': content, 'rich_content': content, 'source': 'WORK_SHOP'})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def topReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['topReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 204: + self.log("Successfully set top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def untopReply(self, rpid): + self.log('Setting...') + res = self.ses.delete(self.apis['untopReply'].format(rpid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully cancel top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def likeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['likeReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 204: + self.log("Successfully set liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['unlikeReply'].format(rpid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully cancel liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def searchArticle(self, key, to): + # Not changed + self.log('searching...') + res = [] + page = 1 + keeprun = True + while keeprun: + resp=self.ses.get(self.apis['searchArticle'].format(key, page), headers=self.headers).json() + if resp['items']==[]: + break + for msg in resp['items']: + if to != None and len(res) >= to: + keeprun = False + break + res.append({'user':{'userid':msg['user']['id'], 'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) + page+=1 + return res + + def likeWork(self, wkid): + self.log('setting...') + res = self.ses.post(self.apis['likeWork'].format(wkid), headers=self.headers, data=r'{}') + if res.status_code == 200: + self.log('Successfully set liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeWork(self, wkid): + self.log('setting...') + res = self.ses.delete(self.apis['unlikeWork'].format(wkid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully cancel liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def getArticleInfo(self, arid): + self.log('getting...') + res = self.ses.get(self.apis['getArticleInfo'].format(arid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully get info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() \ No newline at end of file -- Gitee From ba523fab28527100020bcba229aec99ef6f96a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Fri, 30 Jul 2021 06:08:35 +0000 Subject: [PATCH 11/12] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20ap?= =?UTF-8?q?i.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.py | 265 --------------------------------------------------------- 1 file changed, 265 deletions(-) delete mode 100644 api.py diff --git a/api.py b/api.py deleted file mode 100644 index 8e42dcc..0000000 --- a/api.py +++ /dev/null @@ -1,265 +0,0 @@ -from requests import * -from json import dumps, loads -from bs4 import BeautifulSoup -import os - - -class CodemaoApi(): - def __init__(self, UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', debug=False): - # New: api sets - self.apis = {'home': 'https://shequ.codemao.cn', - 'matomoApi': 'https://matomo.codemao.cn/piwik.js', - 'login': 'https://api.codemao.cn/tiger/v3/web/accounts/login', - 'logout': 'https://api.codemao.cn/tiger/v3/web/accounts/logout', - 'cookie': 'https://shequ.codemao.cn/user/', - 'getSelfInfo1': 'https://api.codemao.cn/web/users/details', - 'getSelfInfo2': 'https://api.codemao.cn/api/user/info', - 'getUserInfo': 'https://api.codemao.cn/api/user/info/detail/{}', - 'changeSelfInfo': 'https://api.codemao.cn/tiger/v3/web/accounts/info', - 'postArticle': 'https://api.codemao.cn/web/forums/boards/{}/posts', - 'deleteArticle': 'https://api.codemao.cn/web/forums/posts/{}', - 'postReply': 'https://api.codemao.cn/web/forums/posts/{}/replies', - 'deleteReply': 'https://api.codemao.cn/web/forums/replies/{}', - 'postL2Reply': 'https://api.codemao.cn/web/forums/replies/{}/comments', - 'deleteL2Reply': 'https://api.codemao.cn/web/forums/comments/{}', - 'clearWork': 'https://api.codemao.cn/tiger/work/user/works/permanently', - 'requireWorkshop': 'https://api.codemao.cn/web/discussions/{}/comment', - 'topReply': 'https://api.codemao.cn/web/forums/replies/{}/top', - 'untopReply': 'https://api.codemao.cn/web/forums/replies/{}/top', - 'likeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', - 'unlikeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', - 'searchArticle': 'https://api.codemao.cn/web/forums/posts/search?title={}&limit=30&page={}', - 'likeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', - 'unlikeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', - 'getArticleInfo': 'https://api.codemao.cn/web/forums/posts/{}/details'} - self.debug = debug - # Use abs path to create in the root path, not cwd - self.logpath = os.path.split(__file__)[0] + os.sep + 'runtime.log' - self.ses = session() - self.headers = {"Content-Type": "application/json", "User-Agent": UA} - self.log('Successfully create the main session') - - def log(self, *msg): - if self.debug: - print(*msg) - # New: temp log file in the root dir - if not os.path.exists(self.logpath): - open(self.logpath, 'w', encoding='utf-8').close() - with open(self.logpath, 'a', encoding='utf-8') as log: - msg = [str(i) for i in msg] - text = ' '.join(msg) + '\n' # list -> str - log.write(text) - - def login(self, identity='', password=''): - if identity and password: - # Get PID - self.log('getting pid...') - text = get(self.apis['home'], headers = self.headers).text - soup = BeautifulSoup(text, 'html.parser') - json = soup.find('script').string.split("=")[1] - pid = loads(json)['pid'] - self.log('Successfully get pid; pid:' + pid) - # Log-in - self.log('logging in...') - res = self.ses.post(self.apis['login'], headers=self.headers, data=dumps({"identity": identity, "password": password, "pid": pid})) - if res.status_code == 200: - self.log("Successfully login to codemao.cn") - else: - self.log('End of logging in to codemao.cn; response', res.status_code) - else: - res = self.ses.get(self.apis['cookie'], headers=self.headers) - if res.status_code == 200: - self.log("Successfully login to codemao.cn") - else: - self.log('End of logging with cookie; response', res.status_code) - return res.json() - - def logout(self): - self.log('logging out...') - res = self.ses.options(self.apis['logout'], headers=self.headers) - if res.status_code == 204: - self.log('Successfully log-out from codemao.cn') - else: - self.log('End of logout from codemao.cn; response', res.status_code) - return res.json() - - def getSelfInfo(self): - self.log('getting...') - res1 = self.ses.get(self.apis['getSelfInfo1'], headers=self.headers) - res2 = self.ses.get(self.apis['getSelfInfo2'], headers=self.headers) - if res1.status_code == 200 and res2.status_code == 200: - self.log('Successfully get self info') - else: - self.log('End of requiring; response', res1.status_code, res2.status_code) - return dict(res1.json(), **res2.json()) - - def getUserInfo(self, urid): - self.log('getting...') - res = self.ses.get(self.apis['getUserInfo'].format(urid), headers=self.headers) - if res.status_code == 200: - self.log('Successfully get info.') - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def changeSelfInfo(self, info): - self.log('changing...') - res = self.ses.patch(self.apis['changeSelfInfo'].format(urid), headers=self.headers, data=dumps(info)) - if res.status_code == 200: - self.log('Successfully change info.') - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def postArticle(self, board, title, content): - self.log('posting...') - res = self.ses.post(self.apis['postArticle'].format(board), headers=self.headers, data=dumps({'title': title, 'content': content})) - if res.status_code == 201: - self.log("Successfully post article") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def deleteArticle(self, arid): - self.log('posting...') - res = self.ses.delete(self.apis['deleteArticle'].format(arid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully delete article") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def postReply(self, arid, content): - self.log('posting...') - res = self.ses.post(self.apis['postReply'].format(arid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully post reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def deleteReply(self, cmid): - self.log('posting...') - res = self.ses.delete(self.apis['deleteReply'].format(cmid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully delete reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def postL2Reply(self, arid, cmid, content): - self.log('posting...') - res = self.ses.post(self.apis['postL2Reply'].format(arid), headers=self.headers, data=dumps({"parent_id":cmid, "content": content})) - if res.status_code == 204: - self.log("Successfully post reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def deleteL2Reply(self, cmid): - self.log('posting...') - res = self.ses.delete(self.apis['deleteL2Reply'].format(cmid), headers=self.headers, data=dumps({'content': content})) - if res.status_code == 204: - self.log("Successfully delete reply") - else: - self.log('End of posting; response', res.status_code) - return res.json() - - def clearWork(self): - self.log('clearing...') - res = self.ses.delete(self.apis['clearWork'], headers=self.headers, data=dumps({'title': title, 'content': content})) - if res.status_code == 200: - self.log("Successfully send request to workshop") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def requireWorkshop(self, wsid, content): - self.log('requiring...') - res = self.ses.post(self.apis['requireWorkshop'].format(wsid), headers=self.headers, data=dumps({'content': content, 'rich_content': content, 'source': 'WORK_SHOP'})) - if res.status_code == 200: - self.log("Successfully send request to workshop") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def topReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['topReply'].format(rpid), headers=self.headers, data=r'{}') - if res.status_code == 204: - self.log("Successfully set top reply") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def untopReply(self, rpid): - self.log('Setting...') - res = self.ses.delete(self.apis['untopReply'].format(rpid), headers=self.headers) - if res.status_code == 204: - self.log("Successfully cancel top reply") - else: - self.log('End of requiring; response', res.status_code) - return res.json() - - def likeReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['likeReply'].format(rpid), headers=self.headers, data=r'{}') - if res.status_code == 204: - self.log("Successfully set liked reply") - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def unlikeReply(self, rpid): - self.log('Setting...') - res = self.ses.put(self.apis['unlikeReply'].format(rpid), headers=self.headers) - if res.status_code == 204: - self.log("Successfully cancel liked reply") - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def searchArticle(self, key, to): - # Not changed - self.log('searching...') - res = [] - page = 1 - keeprun = True - while keeprun: - resp=self.ses.get(self.apis['searchArticle'].format(key, page), headers=self.headers).json() - if resp['items']==[]: - break - for msg in resp['items']: - if to != None and len(res) >= to: - keeprun = False - break - res.append({'user':{'userid':msg['user']['id'], 'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) - page+=1 - return res - - def likeWork(self, wkid): - self.log('setting...') - res = self.ses.post(self.apis['likeWork'].format(wkid), headers=self.headers, data=r'{}') - if res.status_code == 200: - self.log('Successfully set liked work') - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def unlikeWork(self, wkid): - self.log('setting...') - res = self.ses.delete(self.apis['unlikeWork'].format(wkid), headers=self.headers) - if res.status_code == 200: - self.log('Successfully cancel liked work') - else: - self.log('End of setting; response', res.status_code) - return res.json() - - def getArticleInfo(self, arid): - self.log('getting...') - res = self.ses.get(self.apis['getArticleInfo'].format(arid), headers=self.headers) - if res.status_code == 200: - self.log('Successfully get info.') - else: - self.log('End of requiring; response', res.status_code) - return res.json() \ No newline at end of file -- Gitee From 39c3f830e227695a23a1a396b45f4a05c00ca917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=E9=92=9F?= <7406423+albert_zhong@user.noreply.gitee.com> Date: Fri, 30 Jul 2021 06:08:49 +0000 Subject: [PATCH 12/12] 2021/7/30 --- api.py | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 api.py diff --git a/api.py b/api.py new file mode 100644 index 0000000..6f7d862 --- /dev/null +++ b/api.py @@ -0,0 +1,265 @@ +from requests import * +from json import dumps, loads +from bs4 import BeautifulSoup +import os + + +class CodemaoApi(): + def __init__(self, UA='Mozilla/5.0 (Windows NT 10.0; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36', debug=False): + # New: api sets + self.apis = {'home': 'https://shequ.codemao.cn', + 'matomoApi': 'https://matomo.codemao.cn/piwik.js', + 'login': 'https://api.codemao.cn/tiger/v3/web/accounts/login', + 'logout': 'https://api.codemao.cn/tiger/v3/web/accounts/logout', + 'cookie': 'https://shequ.codemao.cn/user/', + 'getSelfInfo1': 'https://api.codemao.cn/web/users/details', + 'getSelfInfo2': 'https://api.codemao.cn/api/user/info', + 'getUserInfo': 'https://api.codemao.cn/api/user/info/detail/{}', + 'changeSelfInfo': 'https://api.codemao.cn/tiger/v3/web/accounts/info', + 'postArticle': 'https://api.codemao.cn/web/forums/boards/{}/posts', + 'deleteArticle': 'https://api.codemao.cn/web/forums/posts/{}', + 'postReply': 'https://api.codemao.cn/web/forums/posts/{}/replies', + 'deleteReply': 'https://api.codemao.cn/web/forums/replies/{}', + 'postL2Reply': 'https://api.codemao.cn/web/forums/replies/{}/comments', + 'deleteL2Reply': 'https://api.codemao.cn/web/forums/comments/{}', + 'clearWork': 'https://api.codemao.cn/tiger/work/user/works/permanently', + 'requireWorkshop': 'https://api.codemao.cn/web/discussions/{}/comment', + 'topReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'untopReply': 'https://api.codemao.cn/web/forums/replies/{}/top', + 'likeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'unlikeReply': 'https://api.codemao.cn/web/forums/comments/{}/liked?source=REPLY', + 'searchArticle': 'https://api.codemao.cn/web/forums/posts/search?title={}&limit=30&page={}', + 'likeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', + 'unlikeWork': 'https://api.codemao.cn/nemo/v2/works/{}/like', + 'getArticleInfo': 'https://api.codemao.cn/web/forums/posts/{}/details'} + self.debug = debug + # Use abs path to create in the root path, not cwd + self.logpath = os.path.split(__file__)[0] + os.sep + 'runtime.log' + self.ses = session() + self.headers = {"Content-Type": "application/json", "User-Agent": UA} + self.log('Successfully create the main session') + + def log(self, *msg): + if self.debug: + print(*msg) + # New: temp log file in the root dir + if not os.path.exists(self.logpath): + open(self.logpath, 'w', encoding='utf-8').close() + with open(self.logpath, 'a', encoding='utf-8') as log: + msg = [str(i) for i in msg] + text = ' '.join(msg) + '\n' # list -> str + log.write(text) + + def login(self, identity='', password=''): + if identity and password: + # Get PID + self.log('getting pid...') + text = get(self.apis['home'], headers = self.headers).text + soup = BeautifulSoup(text, 'html.parser') + json = soup.find('script').string.split("=")[1] + pid = loads(json)['pid'] + self.log('Successfully get pid; pid:' + pid) + # Log-in + self.log('logging in...') + res = self.ses.post(self.apis['login'], headers=self.headers, data=dumps({"identity": identity, "password": password, "pid": pid})) + if res.status_code == 200: + self.log("Successfully login to codemao.cn") + else: + self.log('End of logging in to codemao.cn; response', res.status_code) + else: + res = self.ses.get(self.apis['cookie'], headers=self.headers) + if res.status_code == 200: + self.log("Successfully login to codemao.cn") + else: + self.log('End of logging with cookie; response', res.status_code) + return res.json() + + def logout(self): + self.log('logging out...') + res = self.ses.options(self.apis['logout'], headers=self.headers) + if res.status_code == 204: + self.log('Successfully log-out from codemao.cn') + else: + self.log('End of logout from codemao.cn; response', res.status_code) + return res.json() + + def getSelfInfo(self): + self.log('getting...') + res1 = self.ses.get(self.apis['getSelfInfo1'], headers=self.headers) + res2 = self.ses.get(self.apis['getSelfInfo2'], headers=self.headers) + if res1.status_code == 200 and res2.status_code == 200: + self.log('Successfully get self info') + else: + self.log('End of requiring; response', res1.status_code, res2.status_code) + return dict(res1.json(), **res2.json()) + + def getUserInfo(self, urid): + self.log('getting...') + res = self.ses.get(self.apis['getUserInfo'].format(urid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully get info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def changeSelfInfo(self, info): + self.log('changing...') + res = self.ses.patch(self.apis['changeSelfInfo'].format(urid), headers=self.headers, data=dumps(info)) + if res.status_code == 200: + self.log('Successfully change info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def postArticle(self, board, title, content): + self.log('posting...') + res = self.ses.post(self.apis['postArticle'].format(board), headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 201: + self.log("Successfully post article") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteArticle(self, arid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteArticle'].format(arid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully delete article") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def postReply(self, arid, content): + self.log('posting...') + res = self.ses.post(self.apis['postReply'].format(arid), headers=self.headers, data=dumps({'content': content})) + if res.status_code == 204: + self.log("Successfully post reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteReply(self, cmid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteReply'].format(cmid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully delete reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def postL2Reply(self, arid, cmid, content): + self.log('posting...') + res = self.ses.post(self.apis['postL2Reply'].format(arid), headers=self.headers, data=dumps({"parent_id":cmid, "content": content})) + if res.status_code == 204: + self.log("Successfully post reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def deleteL2Reply(self, cmid): + self.log('posting...') + res = self.ses.delete(self.apis['deleteL2Reply'].format(cmid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully delete reply") + else: + self.log('End of posting; response', res.status_code) + return res.json() + + def clearWork(self): + self.log('clearing...') + res = self.ses.delete(self.apis['clearWork'], headers=self.headers, data=dumps({'title': title, 'content': content})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def requireWorkshop(self, wsid, content): + self.log('requiring...') + res = self.ses.post(self.apis['requireWorkshop'].format(wsid), headers=self.headers, data=dumps({'content': content, 'rich_content': content, 'source': 'WORK_SHOP'})) + if res.status_code == 200: + self.log("Successfully send request to workshop") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def topReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['topReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 204: + self.log("Successfully set top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def untopReply(self, rpid): + self.log('Setting...') + res = self.ses.delete(self.apis['untopReply'].format(rpid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully cancel top reply") + else: + self.log('End of requiring; response', res.status_code) + return res.json() + + def likeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['likeReply'].format(rpid), headers=self.headers, data=r'{}') + if res.status_code == 204: + self.log("Successfully set liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeReply(self, rpid): + self.log('Setting...') + res = self.ses.put(self.apis['unlikeReply'].format(rpid), headers=self.headers) + if res.status_code == 204: + self.log("Successfully cancel liked reply") + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def searchArticle(self, key, to): + # Not changed + self.log('searching...') + res = [] + page = 1 + keeprun = True + while keeprun: + resp=self.ses.get(self.apis['searchArticle'].format(key, page), headers=self.headers).json() + if resp['items']==[]: + break + for msg in resp['items']: + if to != None and len(res) >= to: + keeprun = False + break + res.append({'user':{'userid':msg['user']['id'], 'username':msg['user']['nickname']},'id':msg['id'],'title':msg['title']}) + page+=1 + return res + + def likeWork(self, wkid): + self.log('setting...') + res = self.ses.post(self.apis['likeWork'].format(wkid), headers=self.headers, data=r'{}') + if res.status_code == 200: + self.log('Successfully set liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def unlikeWork(self, wkid): + self.log('setting...') + res = self.ses.delete(self.apis['unlikeWork'].format(wkid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully cancel liked work') + else: + self.log('End of setting; response', res.status_code) + return res.json() + + def getArticleInfo(self, arid): + self.log('getting...') + res = self.ses.get(self.apis['getArticleInfo'].format(arid), headers=self.headers) + if res.status_code == 200: + self.log('Successfully get info.') + else: + self.log('End of requiring; response', res.status_code) + return res.json() \ No newline at end of file -- Gitee