Python使用Request库实现PC端学小易(适用app版本1.0.6)

Python使用Request库实现PC端学小易app(适用app版本1.0.6)

  • 前言
  • 抓包
    • 登录操作抓包
    • 搜题操作抓包
    • 数据分析
      • 登录
      • 搜题
      • 重点
  • 代码实现
    • 导入库
    • tkinter实现简易图形界面部分
    • request库实现登录部分
    • 搜题部分
    • 整理输出至tkinter部分
    • 完整代码
  • 重点

前言

一直以来学小易只有安卓段与IOS端的app,在PC端没有开发软件,本文通过对安卓版的学小易app进行抓包获取数据,然后通过python以tkinter图形界面使用Request库模拟请求,进行模拟登录与查题操作。

抓包

登录操作抓包

在学小易登录界面抓包得到登录所需要的请求头以及获得的Response.text:
请求头
Response

搜题操作抓包

抓包

数据分析

登录

抓包数据显示,学小易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': '',#######!!!填入自己设备的deviceToken!!!###########
            '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': '',   #######!!!填入自己设备的deviceToken!!!#######
            '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_CSDN_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_CSDN_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更新后请不要再使用本段代码。

热门文章

暂无图片
编程学习 ·

ssm学习笔记——spring——AOP配置

spring中基于XMl的AOP配置1、把通知的bean也交给spring来管理2、使用aop:config标签表明开始AOP配置3、使用aop:aspect标签表明配置切面id属性:给切面提供唯一标识ref属性:是指定通知类的Id4、在aop:aspect标签的内部使用对应标签来配置通知的类型示例:让printLog方法在切…
暂无图片
编程学习 ·

Shell编程_echo/printf

目录一、Shell echo/printf 命令1、Shell显示命令-echo2、printf 命令操作常用的一些格式化字符二、test命令一、Shell echo/printf 命令Shell echo/printf 命令1、Shell显示命令-echo打印普通字符串[root@master ~]# echo "hello shell" hello shell创建和清空文件1…
暂无图片
编程学习 ·

Linux 文件系统解析(三)cache

Linux文件系统中使用了大量cache,用于提升IO性能,本篇来梳理一下这些与文件系统相关的cache,它们在内存中是如何组织管理的,它们是如何加速文件系统操作的。Dentry Cachedentry用于描述系统目录树中的一个节点,磁盘文件系统中通常没有相关结构,dentry只存在于内存之中,它…
暂无图片
编程学习 ·

利用BootStrap创建搜索框--」详解

今天学了bootstrap由于官网上没有搜索框,我要做一个网站正好需要,我就自己做了一个搜索框,话不多说直接上代码下面是jsp代码<div class="col-sm-5" id="so"><div class="input-group"><input type="text" class="…
暂无图片
编程学习 ·

聚焦Java性能优化 打造亿级流量秒杀系统【学习笔记】06_交易性能优化技术之缓存库存

文章目录本章目标7-1 交易性能瓶颈7-2 交易验证优化7-3 活动缓存库存方案一(重点)库存行锁优化扣减库存缓存化(方案一)异步同步数据库(方案二)异步消息队列rocketmq库存数据库最终一致性保证7-5 活动缓存库存方案二分布式事务7-7 rocketmq安装7-8 缓存库存接入异步化 本章…
暂无图片
编程学习 ·

MIT 计算机操作环境导论Missing Semester Lesson 10 Q&A

最后一节课,我们回答学生提出的问题:学习操作系统相关内容的推荐,比如进程,虚拟内存,中断,内存管理等你会优先学习的工具有那些?使用 Python VS Bash脚本 VS 其他语言?source script.sh 和 ./script.sh 有什么区别?各种软件包和工具存储在哪里?引用过程是怎样的? /bi…
暂无图片
编程学习 ·

两种判断对象类型的方法

两种判断对象类型的方法: 1.通过instanceof *缺点:不能准确的判断该对象是Dog的实例,如果该对象是类的子类对象也会返回true 2.对象.getClass().getName()获取对象的实例类名 (1)对象.getClass():返回该对象对应的Class对象 (2)对象.getClass().getName():该对象对应的class对…
暂无图片
编程学习 ·

什么是体感互动以及其优势在哪

体感互动通常指的是隔空互动,通过体感设备,来检测人体,通过景物深度处理技术把人物从摄像头捕捉到的画面中分离出来; 随着手指的挥动、在不接触任何物体的情况下做出手势,根据自己的要求发出一些信号,画面就会做出相应的变化,例如对图片、视频进行放大缩小、拖拽、旋转、播…
暂无图片
编程学习 ·

荣耀X10 Max发布在即 屏幕优势显著

前一阵就听说了荣耀X10 Max将在7月2日发布的消息,不知不觉中已经只剩不到一周的时间了,作为今年唯一的5G大屏手机,人们关注的无非是它的屏幕,以及各项配置。刚刚荣耀X10 Max又有了更多的爆料信息,下面就跟大家来聊一聊这款即将发布的5G大屏手机。荣耀X10 Max采用了一块7.0…
暂无图片
编程学习 ·

老鸟带你回顾新人Java不容错过的八本好书

回头看看, 我进入Java 领域已经快15个年头了, 虽然学的也一般, 但是分享下我的心得,估计也能帮大家少走点弯路。 [入门] 我在2001年之前是C/C++阵营, 有C和面向对象的基础, 后来转到Java ,发现没有指针的Java真是好简单, 另外Java 的类库好用的让人哭啊。 后来我就看《…
暂无图片
编程学习 ·

【机器学习】图神经网络

图神经网络是一种直接在图结构上运行的神经网络。GNN 的一个典型应用是节点分类。本质上,图中的每个节点都与一个标签相关联,我们的目的是预测没有 ground-truth 的节点的标签。 将node编码到特征空间:将卷积神经网络中的方法泛化到graph中,用邻居节点来update该节点的feat…
暂无图片
编程学习 ·

献给mac新手,Mac日常软件APP推荐

不少初入Mac 或者 Macbook 的朋友会因为 macOS 系统的独特性而感到新奇又迷惑,它不仅在操作逻辑上和 Windows 大相径庭,软件生态也是截然不同。初用 macOS 系统时可能会一头雾水,完全不知道自己应该去哪里下载 App,也不知道有哪些常用的 App。其实 Mac 上有很多精致又好用的…
暂无图片
编程学习 ·

注意力机制以及应用

注意力机制以及应用注意力机制的由来encoder-decoder简单原理说明global和hard以及localCNN中的attentionself-attention Attention成为了越来越来模型里绕不过去的坎,好像不过怎么样都加一个,那么注意力机制到底是什么以及计算流程和具体应用有哪些呢,今天来简单罗列一下。…
暂无图片
编程学习 ·

cpu寻址问题

20根地址线,16根数据线,cpu按字节编址和按字编址的寻址范围,分别是1M和512k,但是16根数据线,表明一次向存储单元读写位数16位,那为什么按字编址会是512k而不是1M呢,请解答一下,谢谢
暂无图片
编程学习 ·

inotify 安装配合rsync

inotify是细粒度的实时监控结合rsync备份 inotify安装 yum install inotify-tools [root@nfs01 ~]# cd /proc/sys/fs/inotify/ [root@nfs01 inotify]# ls max_queued_events max_user_instances max_user_watches 最大可容纳事件(相当于一个池) 每个用户可以运行的进程…
暂无图片
编程学习 ·

面试题 17.10. 主要元素(摩尔投票法)

面试题 17.10. 主要元素 (摩尔投票法)方法一:Map方法(不满足题目空间复杂度)方法二:摩尔投票法面试题 17.10. 主要元素 题目链接:https://leetcode-cn.com/problems/find-majority-element-lcci/方法一:Map方法(不满足题目空间复杂度) class Solution { public int m…
暂无图片
编程学习 ·

IO Workload Characterization Revisited: A Data-Mining Approach

文章目录摘要1 介绍2 研究背景2.1 相关工作2.2 FTL2.3 工作负载分析在SSD 中的应用3 总览4 表征IO Trace4.1 参数定义4.2 IO Trace 数据收集4.3 特征定义 本文发表于: IEEE TRANSACTIONS ON COMPUTERS, VOL. 63, NO. 12, DECEMBER 2014 摘要 在过去的几十年中,IO工作负载表征…