需求分析
老婆单位最近要会计考试了,我问她有什么可以帮忙的没有,她向我提了一个需求:考试是在一个网上平台上,目前可以在平台上进行不限次数模拟考试,但是模拟考试每次题目只有20道,想把模拟考试的题目保存下来。我看了一个她的模拟考试页面,里面可以显示答案,想了一下,就是将网页中的题目、选项、答案都用保存到EXCEL中,便一口答应。
coding 过程
将模拟考试的的页面保存下来一份,开始分析结构和需要的字段,这里我使用xpath
来解析html
(主要是不会BeautifulSoup
),由于 xpath
不熟练,还要看着文档一步一步调试,这一部分最耗时。
题目和答案都相对比较容易,但是选择题的选项是不固定的,99%都是4个选项,也有3个、5个和6个的,这样的话和题目对应起来的时候不能按4的倍数来搞,稍微费了一点脑筋。最后将得到的题目列表、答案列表、选项列表对应项合并起来,每个题目一个list
最后再使用pandas
将结果写进EXCEL
中。
代码
import pandas as pd
from lxml import etree
import os
def html_unpack(html):
"""将html 中包含的题目保存出来
输出为元组,第一部分为选择题,第二部分为判断题
"""
# 使用 xpath 来解析 html 中需要的字段
s = etree.HTML(html)
# 匹配选择题
choice_questions = s.xpath('//div[@data-current="exam/exam/question/types/answer/choice:content"]/div/text()')
# 匹配判断题
judgement_questions = s.xpath('//div[@data-current="exam/exam/question/types/answer/judgement:content"]/div/text()')
# 匹配全部答案
answer = s.xpath('//div[@class="show-answer"]/div/div/div/text()')
# 匹配选择题的选项部分
choice_options_part1 = s.xpath('//span[@class="pull-left option-num"]/text()')
choice_options_part2 = s.xpath('//div[@class="answer-options m-left"]/text()')
# 将获取的数据规范一下,去掉换行
answer_options = list(map(lambda x :x[0]+x[1], zip(choice_options_part1, choice_options_part2)))
choice_questions = [[i.strip().replace('\u3000',' ')] for i in choice_questions if i.strip()]
judgement_questions = [[i.strip()] for i in judgement_questions if i.strip()]
answer = [[i.strip().replace("标准答案:","")] for i in answer]
# 将每道选择题的选项合并到一个列表中。由于选项不是固定4个,所以需要处理一下。
answer_options_list = [[] for i in range(choice_options_part1.count('A.'))]
j = -1
for i in answer_options:
if i[0] == "A":
j += 1
answer_options_list[j].append(i)
# 将选择题按题目、答案、选项的顺序排好,格式为 [[question1, answer1, opention1], ...]
result_choice = list(map(lambda x: x[0]+x[1]+x[2], zip(choice_questions, answer[:16], answer_options_list)))
# 将判断题按题目、答案的顺序排好,格式为 [[question1, answer1], ...]
result_judgement = list(map(lambda x: x[0]+x[1], zip(judgement_questions, answer[16:])))
return result_choice, result_judgement
def read_html(path):
with open(path, 'r', encoding = 'utf-8') as f:
result = f.read()
return result
def main():
# 获取文件列表
file_list = ['2/123/'+ i for i in os.listdir('2/123') if "html" in i]
# 循环处理每个文件,并将处理后的结果汇总
result_choice = []
result_judgement = []
for i in file_list:
html = read_html(i) # 调用读取函数
result = html_unpack(html) # 调用解析函数
result_choice += result[0] # 保存选择题
result_judgement += result[1] # 保存判断题
# 使用pandas 将处理好的文件写进 excel 中
# 选择题的选项列不固定,有时有五个选项,有时有六个选项,这里有个小BUG,如果列名和选项个数不对应,会报错。
choice_df = pd.DataFrame(result_choice, columns=['题目', '答案', 'option1', 'option2', 'option3', 'option4', 'option5', 'option6'])
judgement_dfd = pd.DataFrame(result_judgement, columns=['题目', '答案'])
# 数据按题目去重
choice_df = choice_df.drop_duplicates('题目')
judgement_dfd = judgement_dfd.drop_duplicates('题目')
with pd.ExcelWriter('会计自测4.xls') as writer:
choice_df.to_excel(writer,sheet_name='选择',index=None)
judgement_dfd.to_excel(writer,sheet_name='判断',index=None)
if __name__ == "__main__":
main()
输出
试着跑了125套模拟题,速度很快,3秒内出结果。就是保存125个模拟考页面比较麻烦,花了将近1个小时才保存完,因为这是一次性的需求,也懒得再去分析网站写爬虫了。