美文网首页python爬虫生活不易 我用python
安卓苹果手机APP网络数据抓取(MD版)

安卓苹果手机APP网络数据抓取(MD版)

作者: hrcl2015 | 来源:发表于2018-07-05 14:13 被阅读25次

    最近在准备上岸,备考中需做大量的练习,手机APP让练习无处不在,但有个缺点,就是每次只能练习10-20道题目,不能用题海战术,海量做题。能不能把网站的题库及解析都弄下来,在本地电脑上做题呢?以下是我的思路:1、分析并爬取手机软件的题库;2、调整好格式存入xls文件中;3、导入PC版可自定义的考试系统中(如教之初考试系统免费版);4、自行设置考试模式,海量练习。

    倒腾了两天,终于搞定,后续再更新文章!

    涉及到几个点。

    1、关于手机网络数据的分析,我是用Fiddler 4进行的分析。

    2、关于excel表格的操控,之前想用xlwings模块,后因没装office,用的是wps2013政府阉割版,无法操控,后改用xlrd、xlutils、shutil、os模块自己写了一个excel操纵类对象,发现还是有问题,后卸载阉割版wps,换了wps2016最新版的,就可以操作了。后来也没换xlwings模块了,将就着用自写模块。大坑:xlrd模块好像不支持中文路径,全部换用英文路径,最后再把文件夹及文件名转换成中文的。

    3、题库分类保存。

    爬取的题库
    教之初考试系统免费版
    1、Fiddler抓包手机APP的网络请求

    Fiddler是一款非常流行并且实用的http抓包工具,它的原理是在本机开启了一个http的代理服务器,然后它会转发所有的http请求和响应,不仅如此,它还可以支持请求重放等一些高级功能。显然它是可以支持对手机应用进行http抓包的。

    设置在同一局域网下电脑端Fiddler抓取手机APP应用网络请求的步骤:

    (1)电脑端启动Fiddler,打开菜单栏中的 Tools > Fiddler Options,打开“Fiddler Options”对话框。

    Fiddler界面

    (2)在Fiddler Options”对话框切换到“Connections”选项卡,然后勾选“Allow romote computers to connect”后面的复选框,然后点击“OK”按钮。(小技巧:HTTPS标签中可以设置下拉框为...from remote clients only ,貌似就只接收远程端的网络请求了)

    Fiddler软件Connections界面 Fiddler软件HTTPS界面

    (3)在电脑端的命令行输入:ipconfig,找到本机的ip地址。(我的局域网IP:192.168.1.10)

    CMD命令行

    (4)在手机端,打开android设备的“设置”->“WLAN”,找到你要连接的网络,在上面长按,然后选择“修改网络”,弹出网络设置对话框,然后勾选“显示高级选项”。(其实苹果手机也是类似的)

    (5)在“代理”后面的输入框选择“手动”,在“代理服务器主机名”后面的输入框输入电脑的ip地址,在“代理服务器端口”后面的输入框输入8888,然后点击“保存”按钮。

    手机端WLAN代理设置

    (6)然后启动android设备中的APP应用,在fiddler中可以看到完整的请求和响应数据。

    Fiddler响应数据

    2、手机APP应用网络数据分析

    手机上打开某笔公考软件后,从Fiddler左侧栏中可以看到大量的请求链接。

    Fiddler网络请求响应

    点击上图黄色区域的链接,可看到右侧详细数据。

    请求详细数据

    在右侧详细数据栏中,我们可以看到请求的网址:POST http://xxxbi.com/android/sydw/exercises?&platform=android22&version=6.4.3&vendor=Tencent&app=gwy&deviceId=F4J/K8kXx6+C24yqFuzAiA==&av=8&kav=3 HTTP/1.1

    post请求的参数keypointId=621638&type=3&limit=15

    返回的数据为Json格式,从返回数据中我们可以找出questionIds对应的题目编号,如2084744.

    点击上上图(Fiddler网络请求响应)中红色框中的链接地址,我们可以看到右侧详细数据栏的数据

    请求详细数据

    从上图中我们可以找到ID号为2084744的题目的题干、选项、题型、答案等有用数据。

    分析基本结束,此手机APP应用的模式基本是这样:先请求15道题的ids,再根据meidaoti的ids请求题目相关数据。后续测试发现,请求questionIds时,修改参数,能一次最多请求到100道题的ids。

    另外,从左侧请求链接可以找出对应的章节分类请求链接,根据分类号再查找对应的questionids,就可以把所有的题目抓取出来。

    题库抓取基本思路

    3、xls操控

    将就着基于xlrd模块编写自用模块。

    自用的xls操作模块

    源码在此,可能因为md格式错乱。需整理。

    
    #!/usr/bin/env python3
    
    # -*- coding: utf-8 -*-
    
    """
    
    Created on 2018-05-14 12:48:07
    
    @author: wangzheng
    
    Sys_Env : Windows_AMD64 Python3.5.2
    
    Email:yaoyao12348@126.com
    
    Filename: MyXls.py
    
    Description : xls文件操控类MyXls
    
                注意:文件路径中不能有中文名,否则出错
    
    """
    
    from xlrd import open_workbook
    
    from xlutils.copy import copy
    
    import os,shutil
    
    class MyXls:
    
        def __init__(self,fpath=None,modelfpath=None,sheetindex=None,protectrow=None,overwrite=True):
    
            self.openxlspath=''#已打开的xls文件
    
            self.sheetindex=None#当前工作表索引
    
            self.rb=None#
    
            self.wb=None#workbook工作簿
    
            self.ws=None#worksheet工作表
    
            self.headrow=0#开头保护行数
    
            if (fpath is not None) and (modelfpath is not None):
    
                self.open_copy_xls(modelfpath,fpath,True)
    
            elif fpath is not None:self.open_xls(fpath)
    
            if sheetindex is not None:self.get_sheet(sheetindex)
    
            if protectrow is not None:self.headrow=protectrow
    
        def open_xls(self,fpath):
    
            path=fpath
    
            try:
    
                rb = open_workbook(path)
    
            except Exception as err:
    
                print("File not exists: "+str(err))
    
                return False
    
            #通过sheet_by_index()获取的sheet没有write()方法
    
            #rs = rb.sheet_by_index(0)
    
            #rs = rb.sheet_by_name('sheet 1')
    
            self.wb = copy(rb)
    
            self.openxlspath=path
    
            return True
    
        def get_sheet(self,sheet_index=0):
    
            sheets=sheet_index
    
            #通过get_sheet()获取的sheet有write()方法
    
            self.ws = self.wb.get_sheet(sheets)
    
            self.sheetindex=sheets
    
        def write_xls(self,row_index,column_index,data_str):
    
            row,col,data=row_index,column_index,data_str
    
            #写入数据
    
            self.ws.write(row,col,data)#write(行,列,内容),索引从0开始
    
        def write_xls_bycolname(self,row_index,column_name,data_str):
    
            column_index=self.colname_to_num(column_name)
    
            row,col,data=row_index,column_index,data_str
    
            #写入数据
    
            self.ws.write(row,col,data)#write(行,列,内容),索引从0开始
    
        def write_xls_bysheet(self,sheetindex,row_index,column_name,data_str):
    
            '''在指定工作表的指定行列表格中写入数据'''
    
            if self.sheetindex != sheetindex :self.get_sheet(sheetindex)
    
            self.write_xls_bycolname(row_index,column_name,data_str)
    
        def save_xls(self,fpath=None):
    
            if fpath is None:
    
                self.wb.save(self.openxlspath)
    
                print('saved '+self.openxlspath)
    
            else:
    
                path=fpath
    
                self.wb.save(path)#保存xls文件
    
                print('saved '+path)
    
            return True
    
        def open_copy_xls(self,model_fpath,new_fpath,overwrite=True):
    
            '''参照模板文件,复制并打开xls文件'''
    
            if os.path.exists(model_fpath) :
    
                new_fpath=self.auto_mkdir(new_fpath)
    
                if (not os.path.exists(new_fpath)) or overwrite:
    
                    #print('copy[%s]to[%s]'%(model_fpath,new_fpath))
    
                    shutil.copy(model_fpath,new_fpath)
    
                    return self.open_xls(new_fpath)
    
                else:print('新文件已存在,请修改新文件名!');return False
    
            else:print('模板文件不存在,不能复制到新文件!');return False
    
        def num_to_colname(self,col_index,start=0):
    
            #列索引转列名,基数start从0开始,0-->A
    
            if type(col_index) != int:
    
                return col_index
    
            if start==0:
    
                x=col_index+1
    
            elif start==1:
    
                x=col_index
    
            s=''
    
            flag=False#借位标志
    
            while x>26:
    
                y=x%26#取余0-25
    
                if y==0:y=26;flag=True;
    
                d=chr(y+64)#低位
    
                s=d+s
    
                x=x//26#整除取商
    
                if flag:x=x-1;flag=False;#如果借位,商要先-1
    
            g=chr(x+64)#高位
    
            s=g+s
    
            return s
    
        def colname_to_num(self,colname,start=0):
    
            #列名转列索引 A-->0,B->1,开始基数start为0
    
            if type(colname) is not str:
    
                return colname
    
            colname=colname.upper()#转成大写
    
            col = 0
    
            power  = 1
    
            #print(len(colname))#位数
    
            for i in range(len(colname) - 1, -1, -1):#range(start=0,stop,step=1)
    
                ch = colname[i] #倒序取字母
    
                #print(ch)#所在位上的字母
    
                col += (ord(ch) - ord('A') +  1 ) * power
    
                power *= 26
    
            #print(col-1)
    
            if start==0:return col-1
    
            if start==1:return col
    
        def auto_mkdir(self,fpath):
    
            '''自动补全目录,目录不存在就创建目录'''
    
            #fpath='D:\\MyPython\\粉笔公考题库提取\\678\\980\\test.txt'
    
            fpath=fpath.replace('\\','/')
    
            if not os.path.exists(fpath):
    
                plst=fpath.split(sep='/')
    
                path=''
    
                if not fpath.endswith('/'):plst=plst[:-1]
    
                for p in plst:
    
                    path=path+p+'/'
    
                    if not os.path.exists(path):os.mkdir(path)
    
                return fpath
    
    if __name__=='__main__':
    
        model_fpath='D:\\MyPython\\model.xls'
    
        new_fpath='D:\\MyPython\\abc\\123/out.xls'
    
    #    myxls=MyXls()
    
    #    myxls.open_copy_xls(model_fpath,new_fpath)
    
    #    myxls.get_sheet(0)
    
        myxls=MyXls(new_fpath,model_fpath,2,3)
    
        myxls.write_xls_bycolname(6,'K','K列6行数据')
    
    #    myxls.save_xls(new_fpath)
    
        myxls.save_xls()
    
        pass
    

    4、文件保存

    保存成xls文件,和txt文件,txt文件再转换成word文档打印出来。大概有7个大类,100+小类,12737道题。

    5、导入题库软件

    xls文件导入题库中。

    6、大功告成

    PS:如欲获取完整源码,请邮件联系我,代码和图片中有我的联系方式。
    尊重原创写作,打赏数额随意。

    相关文章

      网友评论

        本文标题:安卓苹果手机APP网络数据抓取(MD版)

        本文链接:https://www.haomeiwen.com/subject/rkhpuftx.html