Python使用Request库实现PC端学小易app(适用app版本1.0.6)(经反映已不适用!!!)
前言抓包登录操作抓包搜题操作抓包数据分析登录搜题重点
代码实现导入库tkinter实现简易图形界面部分request库实现登录部分搜题部分整理输出至tkinter部分完整代码
重点
前言
一直以来学小易只有安卓段与IOS端的app,在PC端没有开发软件,本文通过对安卓版的学小易app进行抓包获取数据,然后通过python以tkinter图形界面使用Request库模拟请求,进行模拟登录与查题操作。
抓包
登录操作抓包
在学小易登录界面抓包得到登录所需要的请求头以及获得的Response.text:
搜题操作抓包
数据分析
登录
抓包数据显示,学小易app的登录操作即向https://app.51xuexiaoyi.com/api/v1/login发送username和password两个参数,服务器收到后Response用户的唯一的api_token。
搜题
搜题操作是向https://app.51xuexiaoyi.com/api/v1/searchQuestion发送keyword,服务器收到后Response题目与答案
重点
登录时学小易app将账号的识别码(唯一的api_token)发回设备的同时,还获取了设备的识别码,即手机的deviceToken。在使用下面代码前,需要自己使用HTTPCanary对自己手机上的学小易app进行抓包,找到自己手机的deviceToken并填入下面代码中的device字符串里。这样学小易才会认为你的电脑和手机是同一个设备在进行搜索。在代码中,将device参数留空同样可以使用代码成功搜题,但是有较大可能会让学小易检测到并对账号进行一天冻结。
代码实现
导入库
import tkinter
import requests
import json
from js2py
import eval_js
import re
tkinter实现简易图形界面部分
class win1():
def __init__(self
):
def login_t():
usernm
= usernm1
.get
()
passwd
= passwd1
.get
()
win
.destroy
()
Mooc
.login
(usernm
, passwd
)
win
= tkinter
.Tk
()
win
.title
("学小易搜题PC版 By Samuel")
win
.resizable
(0, 0)
usernm1
= tkinter
.Entry
(win
,width
=30)
usernm1
.grid
(column
=1,row
=0)
passwd1
= tkinter
.Entry
(win
,width
= 30)
passwd1
.grid
(column
=1,row
=1)
tag1
= tkinter
.Label
(win
,text
="账号")
tag1
.grid
(row
=0,column
=0)
tag2
= tkinter
.Label
(win
,text
="密码")
tag2
.grid
(row
=1,column
=0)
btn
= tkinter
.Button
(win
,text
="登录",command
=login_t
)
btn
.grid
(row
=0,column
=2,rowspan
=2)
win
.mainloop
()
class w2():
def __init__(self
):
global txt
def check():
text
= test2
.get
()
Mooc
.check_test
(text
)
win2
= tkinter
.Tk
()
win2
.title
("学小易搜题PC版 By Samuel")
win2
.resizable
(0, 0)
test2
= tkinter
.Entry
(win2
, width
=30)
test2
.grid
(column
=1, row
=0)
tag1
= tkinter
.Label
(win2
, text
="输入题目")
tag1
.grid
( column
=0,row
=0)
btn
= tkinter
.Button
(win2
, text
="查询", command
=check
,width
=20)
btn
.grid
(row
=0, column
=2, rowspan
=2)
txt
= tkinter
.Text
(win2
,)
txt
.grid
(row
=2,column
=0,rowspan
=10,columnspan
=3)
win2
.mainloop
()
request库实现登录部分
def login(self
,usernm
,passwd
):
headers
= {
'platform': 'android',
'app-version': '1.0.6',
'content-type': "application/json; charset=utf-8",
'accept-encoding': 'gzip',
'user-agent': 'okhttp/3.11.0'
}
data
= {
"username": usernm
,
"password": passwd
}
url
= 'https://app.51xuexiaoyi.com/api/v1/login'
resq
= requests
.post
(url
,headers
=headers
,json
=data
)
text
= resq
.text
text_list
=text
.split
(",")
if "200" in text_list
[0]:
api_token
= re
.findall
('api_token":"(.*?)"', text_list
[2])[0]
userid
= re
.findall
('userid":"(.*?)"', text_list
[3])[0]
f
= open('token.txt','w')
f
.write
("api_token:"+api_token
+"\n"+"userid:"+userid
)
f
.close
()
wi2
= w2
()
else:
print("登录失败,请检查您的账号密码是否正确")
w1
=win1
()
搜题部分
def check_test(self
,keyword
):
f
= open('token.txt','r')
content
= f
.read
()
tokens
= re
.findall
("api_token:(.*?)\n",content
)[0]
url
= "https://app.51xuexiaoyi.com/api/v1/searchQuestion"
t
= eval_js
("new Date().getTime()")
t
= str(t
)
data
= {
"keyword":keyword
}
headers
={
'token': tokens
,
'device': '',
'platform': 'android',
'User-Agent': 'okhttp/3.11.0',
'app-version': '1.0.6',
't': t
,
'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
'Accept-Encoding': "gzip, deflate, br"
}
resq
= requests
.post
(url
, headers
=headers
, data
=data
)
result
= resq
.json
()
code
= re
.findall
("'code': (.*?)",result
)
if code
== "500":
result
="账号异常,请联系管理员或代码作者更新"
txt
.delete
("0.0","end")
txt
.insert
("insert",result
)
elif code
== "200":
self
.analysis
(result
)
else:
print("网络连接异常,请检查网络连接")
整理输出至tkinter部分
def analysis(self
,content
):
content
= str(content
)
results
= re
.findall
("{'q': '(.*?)', 'a': '(.*?)'}", content
)
for item
in results
:
txt
.insert
('insert', item
[0] + "\n" + "答案:" + item
[1] + "\n")
完整代码
import tkinter
import requests
import json
from js2py
import eval_js
import re
class xuexiaoyi():
def analysis(self
, content
):
content
= str(content
)
results
= re
.findall
("{'q': '(.*?)', 'a': '(.*?)'}", content
)
txt
.delete
('0.0', 'end')
if len(results
) != 0:
for item
in results
:
txt
.insert
('insert', item
[0] + "\n" + "答案:" + item
[1] + "\n")
else:
txt
.insert
('insert', "未找到答案,请重新修改关键词")
def login(self
,usernm
,passwd
):
headers
= {
'platform': 'android',
'app-version': '1.0.6',
'content-type': "application/json; charset=utf-8",
'accept-encoding': 'gzip',
'user-agent': 'okhttp/3.11.0'
}
data
= {
"username": usernm
,
"password": passwd
}
url
= 'https://app.51xuexiaoyi.com/api/v1/login'
resq
= requests
.post
(url
,headers
=headers
,json
=data
)
text
= resq
.text
text_list
=text
.split
(",")
if "200" in text_list
[0]:
api_token
= re
.findall
('api_token":"(.*?)"', text_list
[2])[0]
userid
= re
.findall
('userid":"(.*?)"', text_list
[3])[0]
f
= open('token.txt','w')
f
.write
("api_token:"+api_token
+"\n"+"userid:"+userid
)
f
.close
()
wi2
= w2
()
else:
print("登录失败,请检查您的账号密码是否正确")
w1
=win1
()
def check_test(self
,keyword
):
f
= open('token.txt','r')
content
= f
.read
()
tokens
= re
.findall
("api_token:(.*?)\n",content
)[0]
url
= "https://app.51xuexiaoyi.com/api/v1/searchQuestion"
t
= eval_js
("new Date().getTime()")
t
= str(t
)
data
= {
"keyword":keyword
}
headers
={
'token': tokens
,
'device': '',
'platform': 'android',
'User-Agent': 'okhttp/3.11.0',
'app-version': '1.0.6',
't': t
,
'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
'Accept-Encoding': "gzip, deflate, br"
}
resq
= requests
.post
(url
, headers
=headers
, data
=data
)
result
= resq
.json
()
code
= result
['code']
if code
== 500:
result
="账号异常,请联系管理员或代码作者更新"
txt
.delete
("0.0","end")
txt
.insert
("insert",result
)
elif code
== 200:
self
.analysis
(result
)
else:
result
="网络连接异常,请检查网络连接"
txt
.delete
("0.0","end")
txt
.insert
("insert",result
)
class win1():
def __init__(self
):
def login_t():
usernm
= usernm1
.get
()
passwd
= passwd1
.get
()
win
.destroy
()
Mooc
.login
(usernm
, passwd
)
win
= tkinter
.Tk
()
win
.title
("学小易搜题PC版By__Samuel三木耳")
win
.resizable
(0, 0)
usernm1
= tkinter
.Entry
(win
,width
=30)
usernm1
.grid
(column
=1,row
=0)
passwd1
= tkinter
.Entry
(win
,width
= 30)
passwd1
.grid
(column
=1,row
=1)
tag1
= tkinter
.Label
(win
,text
="账号")
tag1
.grid
(row
=0,column
=0)
tag2
= tkinter
.Label
(win
,text
="密码")
tag2
.grid
(row
=1,column
=0)
btn
= tkinter
.Button
(win
,text
="登录",command
=login_t
)
btn
.grid
(row
=0,column
=2,rowspan
=2)
win
.mainloop
()
class w2():
def __init__(self
):
global txt
def check():
text
= test2
.get
()
Mooc
.check_test
(text
)
win2
= tkinter
.Tk
()
win2
.title
("学小易搜题PC版By__Samuel三木耳")
win2
.resizable
(0, 0)
test2
= tkinter
.Entry
(win2
, width
=30)
test2
.grid
(column
=1, row
=0)
tag1
= tkinter
.Label
(win2
, text
="输入题目")
tag1
.grid
( column
=0,row
=0)
btn
= tkinter
.Button
(win2
, text
="查询", command
=check
,width
=20)
btn
.grid
(row
=0, column
=2, rowspan
=2)
txt
= tkinter
.Text
(win2
,)
txt
.grid
(row
=2,column
=0,rowspan
=10,columnspan
=3)
win2
.mainloop
()
if __name__
== '__main__':
try:
Mooc
= xuexiaoyi
()
f
= open('token.txt', 'r')
content
= f
.read
()
f
.close
()
t
= re
.findall
("api_token:(.*?)\n", content
)
if len(t
) != 0:
wi2
= w2
()
except:
w1
= win1
()
重点
headers中的device参数最好是自己抓包得到的自己手机的deviceToken,否则如果手机电脑两个设备不断的切换着使用,学小易会检测到。device参数留空同样能用,但基本上查了一两次账号就会被冻结,得不偿失。代码运行一次执行登录操作之后,会在代码源目录生成一个token.txt文件,里面记录了使用者账号的userid和api_token,下次运行代码时便会跳过登录操作,直接使用api_token开始搜题不要频繁的进行登录操作,包括但不限于(在两个设备间不断的进行切换操作,在一个设备不断的进行登录request)该代码现在仅局限于1.0.6版本使用 ,app更新后请不要再使用本段代码。