这是我最近接的一个小项目,花了是整整四天多时间。

任务是将http://www.examcoo.com/index/detail/mid/7网站下所有的试卷里的试题全部提取出来,首先按照题型进行分类,接着分析出题目的类型 类别 来源 出题时间等等信息,最终将这些信息转化到excel表格中,excel中的数据有着统一的格式。其中有些信息有关医学,故而需要自行了解。

由于仅仅是是为了完成最终的任务,故而没有使用什么爬虫框架之类的,也没有使用什么数据库来保存数据,尽量做到快速高效,因为你用的东西越多越容易出错,差错控制也非常麻烦。

整个任务看似简单,但由于目标网站的试题格式非常不规范,必须有着众多的误差检测和筛选。程序的关键部分都在控制差错。

程序流程:

1.由于目标网站有着三级页面,为了控制出错,我是按照一个个二级页面来进行爬去的,当然这些都是程序来自动完成的。

2.首先提取出二级页面中所有的三级页面,爬取三级页面的所有试题,进行分类汇总,然后写入excel

3.编写程序将各个类型进行汇总

4.由于做项目时,项目经理改变了excel的数据结构,故而需要对最终excel的格式进行转化,转变为统一的格式。

技术点:

1.试题的解析部分需要自行模拟post请求

2.python操作excel

其实这次项目的技术点并没有什么,关键还是在差错控制和大局观,中间由于网站太不规范,我差一点点就要放弃了。

由于项目的程序实在太多,有近十个,还有众多说明文档,格式文档,这只贴出关键部分:

main.py

  1. # -*- coding:utf-8 -*-
  2. #
  3. # 题干self.TIGANLIST a=[[选项,----],起始,终止,type,[b],[b],[b]]
  4. # 题目self.TIMULIST b=[_,题目,解析,[key,A,B,C,D,E],[c]]
  5. # 信息变量 c=[self.mc,self.lj,------]
  6. #
  7.  
  8. import re, urllib, urllib2, chardet, requests, xlwt, pprint, os, time, chardet
  9.  
  10. class spiderclass():
  11. def __init__(self):
  12. self.pid=''
  13. self.lurude=['959','1023', '1024', '1025', '1031', '1032', '1033', '1034', '1035', '1036', '1037', '1038', '1039',
  14. '957', '958', '960', '961', '963', '965', '966', '968', '969', '970', '971', '972', '973','940',
  15. '998', '999', '1000', '1002', '1003', '1008', '1009', '1013', '1014', '1015', '1016', '1021',
  16. '1022', '1040', '2535','974', '977', '979', '982', '985', '986', '989', '991', '992', '993', '994',
  17. '995', '996', '997','941', '942', '943', '944', '945', '946', '947','949', '952', '953', '954', '955', '956' ]
  18. self.mainbox6=['963']
  19. self.solved=[]
  20. self.passbox=[]
  21. self.xx=''
  22. for i in self.mainbox6:
  23. self.xx=i
  24. self.excelinit() # 初始化excel
  25. self.listinit() # 初始化列表
  26. self.tmpinit() # 初始化时间类型等等相关变量
  27. try:
  28. self.spider0(self.xx)
  29. self.writeexcel()
  30. self.excelsave() #保存excel
  31. self.solved.append(self.xx)
  32. except:
  33. print self.xx,' 出错'
  34. self.passbox.append([self.xx,self.pid])
  35. # self.spider0(self.xx)
  36. # print '二级页面完毕'
  37. # self.writeexcel()
  38. # self.excelsave() #保存excel
  39. # self.solved.append(self.xx)
  40. print self.solved
  41. print self.passbox
  42. print '出错二级页面:',self.passbox
  43.  
  44. def excelinit(self): #初始化excel
  45. self.wba1 = xlwt.Workbook(encoding='utf-8')
  46. self.wbb1 = xlwt.Workbook(encoding='utf-8')
  47. self.wba3 = xlwt.Workbook(encoding='utf-8')
  48. self.wbx = xlwt.Workbook(encoding='utf-8')
  49. self.wsa1 = self.wba1.add_sheet('mysheet')
  50. self.wsa3 = self.wba3.add_sheet('mysheet')
  51. self.wsb1 = self.wbb1.add_sheet('mysheet')
  52. self.wsx = self.wbx.add_sheet('mysheet')
  53. self.a1 = 0 #excel中的偏移量
  54. self.a3 = 0
  55. self.b1 = 0
  56. self.x = 0
  57.  
  58. def listinit(self): #初始化各个列表
  59. self.a1box = [] # 各个excel的数组
  60. self.a3box = []
  61. self.b1box = []
  62. self.xbox = []
  63.  
  64. def tmpinit(self): #初始化时间类型等等相关变量
  65. self.yt='' #用途
  66. self.sj='' #时间
  67. self.lb='' #类别
  68. self.lx='' #类型
  69. self.zk='' #所属专科
  70. self.tx='' #题型
  71. self.lj='' #题目路径
  72. self.mc='' #试卷名称
  73. self.dfl='' #大分类
  74. self.TIMULIST=[]
  75. self.TIGANLIST=[]
  76.  
  77. def excelsave(self):
  78. path=unicode(r'C:\Users\tLOMO\Desktop\excel\%s'%self.xx,'utf-8')
  79. if not os.path.exists(path):
  80. os.mkdir(path)
  81. filenamea1 = unicode(r'C:\Users\tLOMO\Desktop\excel\%s\A1.xls'%self.xx, 'utf-8') # 保存文件
  82. self.wba1.save(filenamea1)
  83. filenameb1 = unicode(r'C:\Users\tLOMO\Desktop\excel\%s\B1.xls'%self.xx, 'utf-8') # 保存文件
  84. self.wbb1.save(filenameb1)
  85. filenamea3 = unicode(r'C:\Users\tLOMO\Desktop\excel\%s\A3&4.xls'%self.xx, 'utf-8') # 保存文件
  86. self.wba3.save(filenamea3)
  87. filenamex = unicode(r'C:\Users\tLOMO\Desktop\excel\%s\X.xls'%self.xx, 'utf-8') # 保存文件
  88. self.wbx.save(filenamex)
  89.  
  90. def urllink(self, link): # 网页HTML获取以及编码转换
  91. while 1:
  92. try:
  93. html_1 = urllib2.urlopen(link, timeout=15).read()
  94. break
  95. except:
  96. pass
  97. encoding_dict = chardet.detect(html_1)
  98. web_encoding = encoding_dict['encoding']
  99. if web_encoding == 'utf-8' or web_encoding == 'UTF-8':
  100. html = html_1
  101. else:
  102. html = html_1.decode('gbk', 'ignore').encode('utf-8')
  103. return html
  104.  
  105. def spider3(self, string): # 用于得到答案解析
  106. try:
  107. jiexi = re.findall('<div>(.*?)</div><div class="mar', string, re.S)
  108. return jiexi[0]
  109. except:
  110. return u'没有解析'
  111.  
  112. def postrequest(self, pid, temp1, temp2, tokenpid): # 模拟post请求
  113. url = 'http://www.examcoo.com/editor/comment/index'
  114. payload = {'id': None, 'sdtId': None, 'pid': None, 'p': 1, 'l': 0, 'msgid': 0, 'cmid': 0, 'tid': 0,
  115. 'verifydtid': 0, 'tokenpid': None}
  116. payload['id'] = temp1
  117. payload['stdId'] = temp2
  118. payload['pid'] = pid
  119. payload['tokenpid'] = tokenpid
  120. while 1:
  121. try:
  122. r = requests.post(url, data=payload)
  123. break
  124. except:
  125. pass
  126. return self.spider3(r.text)
  127.  
  128. def spider4(self, string): # 得到各个选项及正确答案
  129. list = ['']
  130. choicerange = re.findall('radioWrapper(.*?)/div></div', string, re.S)
  131. if choicerange:
  132. num = len(choicerange)
  133. numindex = 65 # 选项A的ascii码
  134. for i in range(num):
  135. choice = []
  136. word = chr(numindex)
  137. if choicerange[i].find('dijitRadioCheckedDisabled') + 1:
  138. list[0] += word
  139. select = re.findall('Content">(.*?)<', choicerange[i], re.S)[0]
  140. select=select.strip().replace(' ','')
  141. choice.append(select)
  142. list.append(choice)
  143. numindex += 1
  144. else:
  145. choicerange = re.findall('checkBoxWrapper(.*?)/div></div', string, re.S)
  146. if choicerange:
  147. num = len(choicerange)
  148. numindex = 65 # 选项A的ascii
  149. for i in range(num):
  150. choice = []
  151. word = chr(numindex)
  152. if choicerange[i].find('dijitCheckBoxCheckedDisabled') + 1:
  153. list[0] += word
  154. select = re.findall('Content">(.*?)<', choicerange[i], re.S)[0]
  155. select = select.strip().replace(' ', '')
  156. choice.append(select)
  157. list.append(choice)
  158. numindex += 1
  159. return list
  160.  
  161. def spider2(self, pid, list, tokenpid): # 对每一个题目进行分析得到题目以及解析
  162. length = len(list)
  163. TIMULIST = [] # 总题目列表
  164. for i in range(length):
  165. selection = self.spider4(list[i]) # 得到选项及正确答案
  166. if selection[0]:
  167. TIMU = [] # 单个题目列表
  168. question = re.findall('subjectBox">(.*?)<sp', list[i], re.S)[0].replace(' ','').replace('(' ,'').replace(')','').strip() # 得到问题
  169. id = re.findall('anchor="(.*?)"', list[i], re.S)[0] # 得到stdid
  170. stdId = "s\d_" + id + "_%s" % (str(i + 1)) # 得到id
  171. jiexi = self.postrequest(pid, id, stdId, tokenpid).replace('<br>', ' ') # 得到答案解析
  172. TIMU.append(i + 1) #实际位置
  173. TIMU.append(question)
  174. TIMU.append(jiexi)
  175. TIMU.append(selection)
  176. TIMULIST.append(TIMU)
  177. return TIMULIST
  178.  
  179. def catchexcept(self, str, string): # 提取文本并捕获异常
  180. try:
  181. return re.findall(str, string, re.S)[0]
  182. except:
  183. return ' '
  184.  
  185. def spider6(self, string): # 爬取profile中的内容
  186. list = []
  187. list.append(self.catchexcept('paperName">(.*?)<', string))
  188. return list
  189.  
  190. def spider5(self, tempb): # 得对综合题干进行处理,得到题干以及对应的位置
  191. TIGAN = []
  192. for i in tempb:
  193. tempc = []
  194. tigan = re.findall('blockBox.*?>(.*?)</div', i[0], re.S)
  195. for k in tigan:
  196. if k.strip() == ' ':
  197. tigan.remove(k)
  198. if k.strip() == '<br type="_bogus">':
  199. tigan.remove(k)
  200. for d in range(len(tigan)):
  201. tigan[d]=tigan[d].replace(' ',' ')
  202. point=['~','-','~','—','-','——','一'] #提取出题干的作用域
  203. tip=0
  204. lenght1=len(tigan)
  205. if lenght1:
  206. for n in range(lenght1-1,-1,-1):
  207. for b in point:
  208. end = re.findall('\(\d+%s(\d+)'%b, tigan[n], re.S)
  209. index=n
  210. if end:
  211. tip=1
  212. break
  213. if tip:
  214. break
  215. if not end:
  216. for n in range(lenght1 - 1, -1, -1):
  217. for b in point:
  218. end = re.findall('(\d+%s(\d+)' % b, tigan[n], re.S)
  219. index = n
  220. if end:
  221. tip = 1
  222. break
  223. if tip:
  224. break
  225. if not end: #如果搜索不到point里的字符则尝试匹配B1类型
  226. if len(tigan)>=4: #如果tiagn的长度大于4,则可能是B1类型
  227. if 'A' in tigan[0] and 'B' in tigan[1]: #尝试匹配B1类型
  228. tempc.append(tigan)
  229. tempc.append(int(i[1]))
  230. tempc.append(None)
  231. tempc.append('b1')
  232. TIGAN.append(tempc)
  233. if 'A' in tigan[1] and 'B' in tigan[2]: #尝试匹配B1类型
  234. tempc.append(tigan[1:])
  235. tempc.append(int(i[1]))
  236. tempc.append(None)
  237. tempc.append('b1')
  238. TIGAN.append(tempc)
  239. else: #正常情况下,则做常规设置
  240. for y in range(index,-1,-1): #去掉题干中无用的信息
  241. del tigan[y]
  242. if len(tigan)>0:
  243. if len(tigan):
  244. tempc.append(tigan)
  245. tempc.append(int(i[1]))
  246. tempc.append(int(end[0]))
  247. if len(tigan)>4:
  248. tempc.append('b1')
  249. else:
  250. tempc.append('a3')
  251. TIGAN.append(tempc)
  252. else:
  253. tempc.append(tigan)
  254. tempc.append(int(i[1]))
  255. tempc.append(int(end[0]))
  256. tempc.append('wrong')
  257. else:
  258. tempc.append(tigan)
  259. tempc.append(int(i[1]))
  260. tempc.append(int(end[0]))
  261. tempc.append('wrong')
  262. for e in range(len(TIGAN)-1): #设置end为None的题干的end值
  263. if TIGAN[e][2]==None:
  264. TIGAN[e][2]=TIGAN[e+1][1]-1
  265. try:
  266. if TIGAN[-1][2]==None: #若最后一项的end为None则设为500
  267. TIGAN[-1][2]=500
  268. except:
  269. pass
  270. return TIGAN
  271.  
  272. def split1(self): # 得到A1和A3和B1题型
  273. deletelist = []
  274. for i in self.TIGANLIST:
  275. start = i[1]
  276. end = i[2]
  277. type = i[3]
  278. if i[0] is not []:
  279. for j in range(start, end + 1):
  280. try: # 当为最后一项时,用异常捕获
  281. i.append(self.TIMULIST[j - 1])
  282. deletelist.append(j - 1)
  283. except:
  284. break
  285. if type == 'b1':
  286. self.b1box.append(i)
  287. elif type=='a3':
  288. if i[4][3][2] != ['']:
  289. self.a3box.append(i)
  290. else:
  291. self.TIGANLIST.remove(i)
  292. for j in range(start, end + 1):
  293. deletelist.append(j - 1)
  294. deletelist.reverse()
  295. for i in deletelist:
  296. try:
  297. del self.TIMULIST[i]
  298. except:
  299. pass
  300.  
  301. def split2(self): #从A1中分离得到A1和X题型
  302. delete=[]
  303. for i in range(len(self.TIMULIST)):
  304. if len(self.TIMULIST[i][3][0])>1:
  305. self.xbox.append(self.TIMULIST[i])
  306. delete.append(i)
  307. delete.reverse()
  308. for i in delete:
  309. del self.TIMULIST[i]
  310.  
  311. def split4(self): #去掉A1中的空项
  312. deletelist=[]
  313. for i in range(len(self.TIMULIST)):
  314. if self.TIMULIST[i][3][2]==['']:
  315. deletelist.append(i)
  316. deletelist.reverse()
  317. for j in deletelist:
  318. del self.TIMULIST[j]
  319. for i in self.TIMULIST:
  320. self.a1box.append(i)
  321.  
  322. def split6(self): #去掉A3&4中的空项
  323. deletelist = []
  324. for i in range(len(self.a3box)):
  325. if self.a3box[i][4][3][2] == ['']:
  326. deletelist.append(i)
  327. deletelist.reverse()
  328. for j in deletelist:
  329. del self.a3box[j]
  330.  
  331. def writea1(self): #单选
  332. for i in range(len(self.a1box)):
  333. self.wsa1.write(self.a1,16,'A1') #题型
  334. self.wsa1.write(self.a1,0,self.a1box[i][1]) #题目
  335. self.wsa1.write(self.a1,9,self.a1box[i][3][0]) #答案
  336. self.wsa1.write(self.a1,10,self.a1box[i][2]) #解析
  337. self.wsa1.write(self.a1, 12, self.a1box[i][4][0]) #时间
  338. self.wsa1.write(self.a1, 18, self.a1box[i][4][1]) #名称
  339. self.wsa1.write(self.a1, 17, self.a1box[i][4][2]) #路径
  340. self.wsa1.write(self.a1,11,self.a1box[i][4][3]) #用途
  341. self.wsa1.write(self.a1,13,self.a1box[i][4][4]) #类别
  342. self.wsa1.write(self.a1,14,self.a1box[i][4][5]) #类型
  343. self.wsa1.write(self.a1, 15, self.a1box[i][4][6]) #专科
  344. self.wsa1.write(self.a1, 19, self.a1box[i][4][7]) #大分类
  345. for j in range(len(self.a1box[i][3])-1):
  346. self.wsa1.write(self.a1,j+1,self.a1box[i][3][j+1])#选项
  347. self.a1+=1
  348.  
  349. def writex(self): #多选
  350. for i in range(len(self.xbox)):
  351. self.wsx.write(self.x, 16, 'X') #题型
  352. self.wsx.write(self.x,0,self.xbox[i][1])
  353. self.wsx.write(self.x,9,self.xbox[i][3][0])
  354. self.wsx.write(self.x,10,self.xbox[i][2])
  355. self.wsx.write(self.x, 12, self.xbox[i][4][0]) # 时间
  356. self.wsx.write(self.x, 18, self.xbox[i][4][1]) # 名称
  357. self.wsx.write(self.x, 17, self.xbox[i][4][2]) # 路径
  358. self.wsx.write(self.x, 11, self.xbox[i][4][3]) # 用途
  359. self.wsx.write(self.x, 13, self.xbox[i][4][4]) # 类别
  360. self.wsx.write(self.x, 14, self.xbox[i][4][5]) # 类型
  361. self.wsx.write(self.x, 15, self.xbox[i][4][6]) # 专科
  362. self.wsx.write(self.x, 19, self.xbox[i][4][7]) # 大分类
  363. for j in range(len(self.xbox[i][3])-1):
  364. self.wsx.write(self.x,j+1,self.xbox[i][3][j+1])
  365. self.x+=1
  366.  
  367. def writea3(self): #题干为情景
  368. for i in range(len(self.a3box)):
  369. self.wsa3.write(self.a3, 16, 'A3&4') # 题型
  370. for j in range(len(self.a3box[i][0])):
  371. self.wsa3.write(self.a3,j,self.a3box[i][0][j]) #题干选项
  372. self.wsa3.write(self.a3, 12, self.a3box[i][4][4][0]) # 时间
  373. self.wsa3.write(self.a3, 18, self.a3box[i][4][4][1]) # 名称
  374. self.wsa3.write(self.a3, 17, self.a3box[i][4][4][2]) # 路径
  375. self.wsa3.write(self.a3, 11, self.a3box[i][4][4][3]) # 用途
  376. self.wsa3.write(self.a3, 13, self.a3box[i][4][4][4]) # 类别
  377. self.wsa3.write(self.a3, 14, self.a3box[i][4][4][5]) # 类型
  378. self.wsa3.write(self.a3, 15, self.a3box[i][4][4][6]) # 专科
  379. self.wsa3.write(self.a3, 19, self.a3box[i][4][4][7]) # 大分类
  380. self.a3+=1
  381. for k in range(len(self.a3box[i])-4):
  382. self.wsa3.write(self.a3 , 1, self.a3box[i][k + 4][1]) #题目
  383. self.wsa3.write(self.a3 , 9, self.a3box[i][k + 4][3][0])#答案
  384. self.wsa3.write(self.a3 , 10, self.a3box[i][k + 4][2]) #解析
  385. tmplist=self.a3box[i][k+4][3]
  386. for m in range(len(tmplist)-1):
  387. self.wsa3.write(self.a3,m+2,tmplist[m+1]) #选项
  388. self.a3+=1
  389. self.a3+=1
  390.  
  391. def writeb1(self): #题干为选项
  392. for i in range(len(self.b1box)):
  393. self.wsb1.write(self.b1, 16, 'B1') # 题型
  394. for j in range(len(self.b1box[i][0])):
  395. self.wsb1.write(self.b1,j,self.b1box[i][0][j])
  396. self.wsb1.write(self.b1, 12, self.b1box[i][4][4][0]) # 时间
  397. self.wsb1.write(self.b1, 18, self.b1box[i][4][4][1]) # 名称
  398. self.wsb1.write(self.b1, 17, self.b1box[i][4][4][2]) # 路径
  399. self.wsb1.write(self.b1, 11, self.b1box[i][4][4][3]) # 用途
  400. self.wsb1.write(self.b1, 13, self.b1box[i][4][4][4]) # 类别
  401. self.wsb1.write(self.b1, 14, self.b1box[i][4][4][5]) # 类型
  402. self.wsb1.write(self.b1, 15, self.b1box[i][4][4][6]) # 专科
  403. self.wsb1.write(self.b1, 19, self.b1box[i][4][4][7]) # 大分类
  404. self.b1+=1
  405. for k in range(len(self.b1box[i])-4):
  406. self.wsb1.write(self.b1 , 1, self.b1box[i][k + 4][1])
  407. self.wsb1.write(self.b1 , 9, self.b1box[i][k + 4][3][0])
  408. self.wsb1.write(self.b1 , 10, self.b1box[i][k + 4][2])
  409. tmplist=self.b1box[i][k+4][3]
  410. for m in range(len(tmplist)-1):
  411. self.wsb1.write(self.b1,m+2,tmplist[m+1])
  412. self.b1+=1
  413. self.b1+=1
  414.  
  415. def findpath(self,html):
  416. one = re.findall('naviState">(.*?)</span></td>', html, re.S)[0] # 找到试卷路径的大致位置
  417. two = re.findall('href.*?>(.*?)</a>', one, re.S)
  418. sjpath = ''
  419. for i in two[2:]:
  420. sjpath += '\\' + i # 得到试卷的路径
  421. return sjpath
  422.  
  423. def writeexcel(self): # 将结果分别写入excel
  424. self.writea1()
  425. self.writeb1()
  426. self.writea3()
  427. self.writex()
  428.  
  429. def split(self):
  430. self.split1() # 得到others和A3和B1题型
  431. self.split2() #从A1中分离得到A1和X题型
  432. self.split4() #去除掉A1中的空项
  433.  
  434. def finddfl(self):
  435. dflbox=['主治类','药学类','护理类']
  436. string=self.mc+self.lj
  437. for i in dflbox:
  438. if i in string:
  439. self.dfl=i
  440.  
  441. def findyt(self):
  442. ytbox=['临床执业医师','临床执业助理医师','中医执业医师','中医执业助理医师','中西医结合执业医师',
  443. '中西医结合助理医师','口腔执业医师','口腔执业助理医师','公卫执业医师','公卫执业助理医师',
  444. '执业药师资格','初级卫生专业技术资格','中级卫生专业技术资格','内科主治医师','内科主治医师',
  445. '外科主治医师','妇产科主治医师','初级药士','初级药师','主管药师','初级中药士','初级中药师',
  446. '主管中药师','临床医学检验技士','临床医学检验技师','临床医学检验主管技师','执业护士','初级护师',
  447. '主管护师','RDPAC认证']
  448. string=self.mc+self.lj
  449. for i in ytbox:
  450. if i in string:
  451. self.yt=i
  452.  
  453. def findlb(self):
  454. lbbox=['模拟','真题','全真']
  455. string = self.mc + self.lj
  456. if lbbox[0] in string:
  457. self.lb='模拟题'
  458. elif lbbox[1] in string:
  459. self.lb='真题'
  460. elif lbbox[2] in string:
  461. self.lb='真题'
  462. else:
  463. self.lb='练习题'
  464.  
  465. def findlx(self):
  466. lxbox=['基础综合','专业综合','实践综合','中医基础','中医临床医学','西医及临床医学','中西医结合临床医学',
  467. '临床综合','药学(中药学)专业知识(一)','药学(中药学)专业知识(二)','药事管理与法规','综合知识与技能(药学、中药学)',
  468. '基础知识','相关专业知识','专业知识','专业实践能力','专业实务','RDPAC认证']
  469. string = self.mc + self.lj
  470. for i in lxbox:
  471. if i in string:
  472. self.lx = i
  473.  
  474. def findzk(self):
  475. zkbox=['外科','中医','口腔','精神病','消化内科','内科护理','护理','内科','神经外科','妇产科','中西医','卫生统计','流行病','中药','药理','心理'
  476. ,'微生物','伦理','免疫','生理','病理','职业病','环境卫生','麻醉']
  477. string = self.mc + self.lj
  478. for i in zkbox:
  479. if i in string:
  480. self.zk = i+'学'
  481.  
  482. def findsj(self):
  483. string = self.mc + self.lj
  484. time=re.findall('.*?(20[0-9]{2})', string, re.S)
  485. if len(time):
  486. self.sj=time[0]
  487.  
  488. def findtotal(self):
  489. self.findyt()
  490. self.findlb()
  491. self.findlx()
  492. self.findzk()
  493. self.findsj()
  494. self.finddfl()
  495.  
  496. def spider1(self,pid): # 对卷面进行解析
  497. self.tmpinit() #初始化变量
  498. self.pid=pid
  499. link = r'http://www.examcoo.com/editor/do/view/id/%s'%pid
  500. print ' '+pid+' 三级页面开始处理'
  501. html = self.urllink(link) # 得到html代码
  502. profile = self.spider6(re.findall('profile(.*?)/div></div>', html, re.S)[0]) # 得到profile中的试卷名
  503. self.mc=profile[0]
  504. self.lj=self.findpath(html) #得到试卷的路径
  505. self.findtotal() #得到试卷用途类别类型等
  506. tokenpid = re.findall('tokenpid = "(.*?)"', html, re.S)[0] # 提取出tokenppid
  507. tempb = re.findall('blockCon(.*?)s\d_.*?_(.*?)"', html, re.S) # 得到综合题干内容
  508. self.TIGANLIST = self.spider5(tempb) # 得对综合题干进行处理,得到题干以及对应的位置
  509. tempa = re.findall('s\d_(.*?)id=', html, re.S) # 提取出所有问题
  510. self.TIMULIST= self.spider2(pid, tempa, tokenpid) # 对每一个题目进行分析得到题目以及解析
  511. for f in range(len(self.TIMULIST)):
  512. self.TIMULIST[f].append([self.sj,self.mc,self.lj,self.yt,self.lb,self.lx,self.zk,self.dfl])
  513. self.split() #分离各个题型
  514. print ' '+pid+' 三级页面处理完毕'
  515. return
  516.  
  517. def spider0(self,id): # 次级页面主处理函数
  518. tmp = ''
  519. pidlist = []
  520. urlsub='http://www.examcoo.com/paperlist/index/k/%s'%id
  521. print id+' 二级页面开始处理'
  522. for i in range(20):
  523. url=urlsub+'/p/%d'%(i+1)
  524. html1 = self.urllink(url)
  525. newpidlist = re.findall('top">(.*?)</td>', html1, re.S)
  526. if newpidlist[0]==tmp:
  527. break
  528. for j in newpidlist:
  529. pidlist.append(j)
  530. if i==0:
  531. tmp=newpidlist[0]
  532. print pidlist
  533. a=0
  534. for i in pidlist:
  535. a+=1
  536. if a==30000:
  537. break
  538. else:
  539. self.spider1(i)
  540. print id+' 该二级页面处理完毕'
  541.  
  542. def spider(self): # 主页面处理函数
  543. url = 'http://www.examcoo.com/index/detail/mid/7'
  544. html = self.urllink(url)
  545. mainlist = re.findall('catSubBox(.*?)</table></div>', html, re.S)
  546. a=[]
  547. for i in mainlist:
  548. if not i.find('examTableOnly') + 1: # 若有主题
  549. firsttitle = re.findall('examTable">.*?<b>(.*?)</b>', i, re.S)[0] # 主题名
  550. tmp0 = re.findall('course(.*?)</tbody', i, re.S)[0]
  551. tmp1 = re.findall('<tr>.*?</tr>', tmp0, re.S)
  552. for j in tmp1:
  553. secondtitle = re.findall('<span>(.*?)</', j, re.S)[0] # 二级标题
  554. thirdtitle = re.findall('href="(.*?)">(.*?)</a>', j, re.S) # 三级标题
  555. for p in thirdtitle:
  556. indexnum=re.findall('k/(.*?)/p',p[0],re.S)[0]
  557. a.append(indexnum)
  558. else: # 若无主题
  559. sublist = re.findall('<td(.*?)</td', i, re.S)
  560. titlemain = re.findall('<b>(.*?)</b>', sublist[0], re.S)[0] # 主标题
  561. titlesub = re.findall('href="(.*?)">(.*?)</a>', sublist[1], re.S) # 副标题
  562. for q in titlesub:
  563. indexnum=re.findall('k/(.*?)/p',q[0],re.S)[0]
  564. a.append(indexnum)
  565. for s in a:
  566. self.spider0(s)
  567. self.writeexcel() #将结果分别写入excel
  568.  
  569. if __name__ == "__main__":
  570. a = time.time()
  571. newclass = spiderclass()
  572. print '耗时', time.time() - a

说明文档

  1. 最终的文档包含五个文件,其中A1A2类型的题目放在了一起存于A11finalA12final中,A3A4类型的题目存于A3文件中
  2.  
  3. 1.试题题型说明
  4. 1.1 A1型题(单句型最佳选择题)(特点:即为单个的单选题,题干为简单的问答)
  5. 细胞坏死的主要形态标志是
  6. A、线粒体肿胀
  7. ×B、核碎裂
  8. C、胞质嗜酸性增强
  9. D、胞质脂滴增加
  10. E、自噬泡增多
  11. 1.2 A2型题(病例摘要型最佳选择题)(特点:与A1结构一致,但题干为一案例)
  12. 35岁女性,3周前感冒伴咽痛,2周前已痊愈。近5天颈前疼痛明显,有低热来门诊。查体:T37.8℃,皮肤无汗,甲状腺Ⅱ°大,右叶硬,明显触痛拒按,WBC7.8×109/L.临床诊断最可能是
  13. A、甲状腺右叶囊肿出血
  14. B、甲状腺癌伴出血
  15. C、慢性淋巴性甲状腺炎
  16. D、急性化脓性甲状腺炎
  17. ×E、亚急性甲状腺炎
  18. 1.3 A3型题(病例组型最佳选择题)(特点:题干为一个案例,后面跟着多个问题,问题之间没有直接联系)
  19. 13题共用题干)
  20. 35岁男性,因饱餐和饮酒后6小时出现中上腹疼痛,放射至两侧腰部,伴有呕吐2次,为胃内容物,自觉口干,出冷汗。查体:T38℃,四肢厥冷,脉搏116次/分,血压10/6kPa,腹膨胀,全腹弥漫性压痛、反跳痛和肌紧张,肝浊音界存在,移动性浊音阳性,肠鸣音消失。
  21. 1.根据病人的临床表现,不应考虑的诊断是
  22. A、穿孔性阑尾炎
  23. B、胃十二指肠溃疡穿孔
  24. C、绞窄性肠梗阻
  25. D、急性胰腺炎
  26. ×E、急性盆腔炎
  27. 2.患者经检查诊断为急性出血坏死性胰腺炎,如行腹腔穿刺,可能抽出液体的颜色是
  28. A、无色清亮液体
  29. ×B、棕褐色液体
  30. C、胆汁样液体
  31. D、脓性液体
  32. E、血性液体
  33. 3.治疗方针应是
  34. A、胃肠减压,密切观察病情变化
  35. B、中药与针刺
  36. C、补液抗炎
  37. ×D、紧急手术
  38. E、纠正休克后手术
  39. 1.4 A4型题(病例串型最佳选择题)(特点:结构与A3一致,但问题循序渐进,相互关联)
  40. 13题共用题干)
  41. 18岁女性,2年来觉下前牙咬东西无力,近期牙齿感觉松动。检查下前牙松动Ⅰ度。牙龈红肿,有牙石,其它牙龈微肿。
  42. 1.采集病史重点了解
  43. A、有无外伤史
  44. ×B、家族史
  45. C、不良习惯
  46. D、口腔卫生习惯
  47. E、有无服药史
  48. 2.重点检查项目是
  49. A、牙髓活力
  50. ×BX线片
  51. C、松动度
  52. D、外周血象
  53. E、牙周附着丧失水平
  54. 3.根据上述检查初步印象为牙周炎,有助于进一步确定诊断的检查是
  55. A、全身头颅X线
  56. ×B、龈下菌斑细菌学检查
  57. C、局部组织病理检查
  58. D、药物过敏试验
  59. E、内分泌检查
  60. 1.5 B1型题(又称标准配伍题)(特点:题干为多个选项,后面为多个问题)
  61. 12共用备选答案)
  62. A、血源性
  63. B、腺源性
  64. C、损伤性
  65. D、牙源性
  66. E、医源性
  67. 1.新生儿颌骨骨髓炎感染来源多为(A
  68. 2.化脓性颌骨骨髓炎感染来源多为(D
  69. 1.6 X型题(特点:即为单个的多选题)
  70. 感染性休克病人治疗原则是
  71. ×A、及时清除化脓病灶
  72. ×B、迅速扩充有效血容量
  73. ×C、应用血管活性药物
  74. ×D、吸氧×E、维护心肺脑肾等重要脏器功能
  75.  
  76. 2.其他信息
  77. 大分类=[‘主治类’,’药学类’,’护理类’]
  78.  
  79. 小分类=['临床执业医师','临床执业助理医师','中医执业医师','中医执业助理医师','中西医结合执业医师','中西医结合助理医师','口腔执业医师','口腔执业助理医师','公卫执业医师','公卫执业助理医师','执业药师资格','初级卫生专业技术资格','中级卫生专业技术资格','内科主治医师','内科主治医师','外科主治医师','妇产科主治医师','初级药士','初级药师','主管药师','初级中药士','初级中药师','主管中药师','临床医学检验技士','临床医学检验技师','临床医学检验主管技师','执业护士','初级护师','主管护师','RDPAC认证']
  80.  
  81. 题型编号={A1&2:11 , A3&4:12, B1:13, X:14}
  82.  
  83. 年份:为出卷时间,由于部分试卷未给出出卷时间,故可能空缺
  84.  
  85. 类别=['模拟','真题',’练习题’]
  86.  
  87. 所属专科=['外科学','中医学','口腔学','精神病学','消化内科学','内科护理学','护理学','内科学','神经外科学','妇产科学','中西医学','卫生统计学','流行病学','中药学','药理学','心理学','微生物学','伦理学','免疫学','生理学','病理学','职业病学','环境卫生学','麻醉学']
  88.  
  89. 类型=['基础综合','专业综合','实践综合','中医基础','中医临床医学','西医及临床医学','中西医结合临床医学','临床综合','药学(中药学)专业知识(一)','药学(中药学)专业知识(二)','药事管理与法规综合知识与技能(药学、中药学)','基础知识','相关专业知识','专业知识','专业实践能力','专业实务',' RDPAC认证']
  90.  
  91. 题目路径:即该试题所对应的试卷在原网站中的索引
  92.  
  93. 所属试卷名:即该试题所在的原试卷的试卷名
  94.  
  95. ##注释:1.每个题目都有小分类,类型和类别这三种信息,不一定有所属专科类型,时间信息和大分类信息
  96.  
  97. 3.可能存在的误差或错误
  98. 总体来说,试题中存在少量不不规范或者错误的地方,在试题被实际使用前最好手动检查一下有没有错误
  99. 3.1 极少数试题中存在无关的信息,例如HTML标签,原网站上的无关信息等
  100. 3.2部分试题由于原网站本身结构的不规范,可能导致试题结构的不规范
  101. 3.3 极少数A3&4B1题目的选项中可能存在多余的选项(非常少)

格式文档

python网页爬虫小项目开发的更多相关文章

  1. Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱(转)

    原文:http://www.52nlp.cn/python-网页爬虫-文本处理-科学计算-机器学习-数据挖掘 曾经因为NLTK的缘故开始学习Python,之后渐渐成为我工作中的第一辅助脚本语言,虽然开 ...

  2. 【Python】Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱

    本文转载自:https://www.cnblogs.com/colipso/p/4284510.html 好文 mark http://www.52nlp.cn/python-%E7%BD%91%E9 ...

  3. 找python爬虫小项目?github给你准备好了!

    前言 即使我们都是程序员,但我们也并非都会修电脑,都会做酷炫的ppt,都会优化系统卡顿.其实程序员也是分行业.分专业的,就像医生也分内外科.呼吸科.神经科神的. 作为非专业的python选手,或者非专 ...

  4. Python网页爬虫(一)

    很多时候我们想要获得网站的数据,但是网站并没有提供相应的API调用,这时候应该怎么办呢?还有的时候我们需要模拟人的一些行为,例如点击网页上的按钮等,又有什么好的解决方法吗?这些正是python和网页爬 ...

  5. python 的一些小项目

    1.在线教育平台(视频播放) 2.仿微信网页版(语音.视频.文字聊天) 3.高德API + Python 解决租房问题 4.仿知乎 5.Django打造文件分享系统.文件管理.搜索引擎(仿云盘) 6. ...

  6. python 网页爬虫+保存图片+多线程+网络代理

    今天,又算是浪费了一天了.python爬虫,之前写过简单的版本,那个时候还不懂原理,现在算是收尾吧. 以前对网页爬虫不了解,感觉非常神奇,但是解开这面面纱,似乎里面的原理并不是很难掌握.首先,明白一个 ...

  7. python网页爬虫开发之一

    1.beautifulsoap4 和 scrapy解析和下载网页的代码区别 bs可以离线解释html文件,但是获取html文件是由用户的其他行为的定义的,比如urllib或者request : 而sc ...

  8. python网页爬虫开发之三

    1.抓取目录页后用lxml进行页面解析,获取抓取列表 python3.6 urlparse模块变为urllib.parse 2.Python中有一个专门生成各类假数据的库:Faker 3.python ...

  9. python网页爬虫开发之六-Selenium使用

    chromedriver禁用图片,禁用js,切换UA selenium 模拟chrome浏览器,此时就是一个真实的浏览器,一个浏览器该加载的该渲染的它都加载都渲染,所以爬取网页的速度很慢.如果可以不加 ...

随机推荐

  1. 基于ABP模块组件与依赖注入组件的项目插件开发

    注意,阅读本文,需要先阅读以下两篇文章,并且对依赖注入有一定的基础. 模块系统:http://www.cnblogs.com/mienreal/p/4537522.html 依赖注入:http://w ...

  2. 连接redis错误:ERR Client sent AUTH, but no password is set

    问题原因:没有设置redis的密码 解决:命令行进入Redis的文件夹: D:\Redis-x64-3.2.100>redis-cli.exe 查看是否设置了密码: 127.0.0.1:6379 ...

  3. 论文笔记【一】Chinese NER Using Lattice LSTM

    论文:Chinese NER Using Lattice LSTM 论文链接:https://arxiv.org/abs/1805.02023 论文作者:Yue Zhang∗and Jie Yang∗ ...

  4. Netbeans and Remote Host for C/C++ Developing

    Netbeans and Remote Host for C/C++ Developing 很久以来,因为我不适应在 Linux 下使用 Vim, GCC, GDB 开发 C/C++ 程序,所以我一直 ...

  5. PTA编程总结3—抓老鼠啊~亏了还是赚了?

    题目: 某地老鼠成灾,现悬赏抓老鼠,每抓到一只奖励10元,于是开始跟老鼠斗智斗勇:每天在墙角可选择以下三个操作:放置一个带有一块奶酪的捕鼠夹(T),或者放置一块奶酪(C),或者什么也不放(X).捕鼠夹 ...

  6. Lintcode97-Maximum Depth of Binary Tree-Easy

    97. Maximum Depth of Binary Tree Given a binary tree, find its maximum depth. The maximum depth is t ...

  7. Linux下Java环境安装

    本节主要讲解Linux(Centos 6.5)下Java环境的安装 1. 卸载机器上默认安装的JDK 在Linux环境下一般会默认安装jdk,为了自己项目的开发部署,一般情况要重新装jdk,而且自己装 ...

  8. ubuntu 16.04 的IP地址变更

    网上google 出来的,全是让你变更 /etc/network/interfaces 这个文件. 可是,我以前设置过的静态地址,全没反映在这个文件里. 这回再变更的话,肯定也不是这个. 然后进入/e ...

  9. Iris 语录

    Iris:hello,Loki first congratulatioins to you to upgrade to V2You really did a big progress in v0 an ...

  10. HTML辅助方法

    顾名思义,HTML辅助方法(HTML Helper)就是用来辅助产生HTML之用,在开发View的时候一定会面对许多HTML标签,处理这些HTML的工作非常繁琐,为了降低View的复杂度,可以使用HT ...