最近在准备上岸,备考中需做大量的练习,手机APP让练习无处不在,但有个缺点,就是每次只能练习10-20道题目,不能用题海战术,海量做题。能不能把网站的题库及解析都弄下来,在本地电脑上做题呢?以下是我的思路:1、分析并爬取手机软件的题库;2、调整好格式存入xls文件中;3、导入PC版可自定义的考试系统中(如教之初考试系统免费版);4、自行设置考试模式,海量练习。
涉及到几个点。
1、关于手机网络数据的分析,我是用Fiddler4进行的分析。
2、关于excel表格的操控,之前想用xlwings模块,后因没装office,用的是wps2013政府阉割版,无法操控,后改用xlrd、xlutils、shutil、os模块自己写了一个excel操纵类对象,发现还是有问题,后卸载阉割版wps,换了wps2016最新版的,就可以操作了。后来也没换xlwings模块了,将就着用自写模块。大坑:xlrd模块好像不支持中文路径,全部换用英文路径,最后再把文件夹及文件名转换成中文的。
3、题库分类保存。
1、Fiddler抓包手机APP的网络请求
设置在同一局域网下电脑端Fiddler抓取手机APP应用网络请求的步骤:
(1)电脑端启动Fiddler,打开菜单栏中的Tools>FiddlerOptions,打开“FiddlerOptions”对话框。
(2)在FiddlerOptions”对话框切换到“Connections”选项卡,然后勾选“Allowromotecomputerstoconnect”后面的复选框,然后点击“OK”按钮。(小技巧:HTTPS标签中可以设置下拉框为...fromremoteclientsonly,貌似就只接收远程端的网络请求了)
(3)在电脑端的命令行输入:ipconfig,找到本机的ip地址。(我的局域网IP:192.168.1.10)
(4)在手机端,打开android设备的“设置”->“WLAN”,找到你要连接的网络,在上面长按,然后选择“修改网络”,弹出网络设置对话框,然后勾选“显示高级选项”。(其实苹果手机也是类似的)
(5)在“代理”后面的输入框选择“手动”,在“代理服务器主机名”后面的输入框输入电脑的ip地址,在“代理服务器端口”后面的输入框输入8888,然后点击“保存”按钮。
(6)然后启动android设备中的APP应用,在fiddler中可以看到完整的请求和响应数据。
2、手机APP应用网络数据分析
手机上打开某笔公考软件后,从Fiddler左侧栏中可以看到大量的请求链接。
点击上图黄色区域的链接,可看到右侧详细数据。
post请求的参数keypointId=621638&type=3&limit=15
返回的数据为Json格式,从返回数据中我们可以找出questionIds对应的题目编号,如2084744.
点击上上图(Fiddler网络请求响应)中红色框中的链接地址,我们可以看到右侧详细数据栏的数据
从上图中我们可以找到ID号为2084744的题目的题干、选项、题型、答案等有用数据。
另外,从左侧请求链接可以找出对应的章节分类请求链接,根据分类号再查找对应的questionids,就可以把所有的题目抓取出来。
3、xls操控
将就着基于xlrd模块编写自用模块。
源码在此,可能格式错乱。需整理。
'''python
#!/usr/bin/envpython3
#-*-coding:utf-8-*-
"""
Createdon2018-05-1412:48:07
@author:wangzheng
Sys_Env:Windows_AMD64Python3.5.2
Filename:MyXls.py
Description:xls文件操控类MyXls
注意:文件路径中不能有中文名,否则出错
fromxlrdimportopen_workbook
fromxlutils.copyimportcopy
importos,shutil
classMyXls:
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(fpathisnotNone)and(modelfpathisnotNone):
self.open_copy_xls(modelfpath,fpath,True)
eliffpathisnotNone:self.open_xls(fpath)
ifsheetindexisnotNone:self.get_sheet(sheetindex)
ifprotectrowisnotNone:self.headrow=protectrow
defopen_xls(self,fpath):
path=fpath
try:
rb=open_workbook(path)
exceptExceptionaserr:
print("Filenotexists:"+str(err))
returnFalse
#通过sheet_by_index()获取的sheet没有write()方法
#rs=rb.sheet_by_index(0)
#rs=rb.sheet_by_name('sheet1')
self.wb=copy(rb)
self.openxlspath=path
returnTrue
defget_sheet(self,sheet_index=0):
sheets=sheet_index
#通过get_sheet()获取的sheet有write()方法
self.ws=self.wb.get_sheet(sheets)
self.sheetindex=sheets
defwrite_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开始
defwrite_xls_bycolname(self,row_index,column_name,data_str):
column_index=self.colname_to_num(column_name)
defwrite_xls_bysheet(self,sheetindex,row_index,column_name,data_str):
'''在指定工作表的指定行列表格中写入数据'''
ifself.sheetindex!=sheetindex:self.get_sheet(sheetindex)
self.write_xls_bycolname(row_index,column_name,data_str)
defsave_xls(self,fpath=None):
iffpathisNone:
self.wb.save(self.openxlspath)
print('saved'+self.openxlspath)
else:
self.wb.save(path)#保存xls文件
print('saved'+path)
defopen_copy_xls(self,model_fpath,new_fpath,overwrite=True):
'''参照模板文件,复制并打开xls文件'''
ifos.path.exists(model_fpath):
new_fpath=self.auto_mkdir(new_fpath)
if(notos.path.exists(new_fpath))oroverwrite:
#print('copy[%s]to[%s]'%(model_fpath,new_fpath))
shutil.copy(model_fpath,new_fpath)
returnself.open_xls(new_fpath)
else:print('新文件已存在,请修改新文件名!');returnFalse
else:print('模板文件不存在,不能复制到新文件!');returnFalse
defnum_to_colname(self,col_index,start=0):
#列索引转列名,基数start从0开始,0-->A
iftype(col_index)!=int:
returncol_index
ifstart==0:
x=col_index+1
elifstart==1:
x=col_index
s=''
flag=False#借位标志
whilex>26:
y=x%26#取余0-25
ify==0:y=26;flag=True;
d=chr(y+64)#低位
s=d+s
x=x//26#整除取商
ifflag:x=x-1;flag=False;#如果借位,商要先-1
g=chr(x+64)#高位
s=g+s
returns
defcolname_to_num(self,colname,start=0):
#列名转列索引A-->0,B->1,开始基数start为0
iftype(colname)isnotstr:
returncolname
colname=colname.upper()#转成大写
col=0
power=1
#print(len(colname))#位数
foriinrange(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)
ifstart==0:returncol-1
ifstart==1:returncol
defauto_mkdir(self,fpath):
'''自动补全目录,目录不存在就创建目录'''
#fpath='D:\\MyPython\\粉笔公考题库提取\\678\\980\\test.txt'
fpath=fpath.replace('\\','/')
ifnotos.path.exists(fpath):
plst=fpath.split(sep='/')
path=''
ifnotfpath.endswith('/'):plst=plst[:-1]
forpinplst:
path=path+p+'/'
ifnotos.path.exists(path):os.mkdir(path)
returnfpath
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更新后,加入了防抓取数据的功能,貌似安卓5.1以上的都不能抓取了。
据资深网友反应,使用安卓模拟器(系统版本4.4)还可以抓到明文数据,有兴趣的读者可以试一试。