Python爬取信息学在线题库
最近在研究用Python写爬虫,老师给了我一个网站练手,正好趁热打铁(笑)。
前言
- 本项目开源: GitHub
- 题库版权归属 http://lib.nbdp.net 所有,本文只做学习交流之用。
- 如侵删。
网页分析
- 按F12查看首页源码,可以看到试卷链接是固定的格式。
- 随便点了一份试卷,如图:
按F12看光光,看到虽然右上角写着
不是VIP用户,无法查看答案
,但是正确答案就写在HTML里(为良心网站点赞):- 选择题的正确答案的Class跟其他答案的Class相比多了个
xz
后缀: - 填空题的答案就用全透明的字体写在原处:
- 显示答案的JS:
- 选择题的正确答案的Class跟其他答案的Class相比多了个
开工
仅贴出关键代码,完整代码请移步GitHub
我使用的环境:
- Python3.6
- beautifulsoup4==4.7.1
- bs4==0.0.1
- lxml==4.3.3
- requests==2.21.0
- xlwt==1.3.0
- 首先使用requests获取HTML源码
import requests
……
for i in rang(1,100,1):
s=requests.session()url='http://lib.nbdp.net/paper/%d.html' % j
html=s.get(url).content
html=str(html,encoding='utf-8',errors='ignore')
实测有一份试卷中出现了特殊符号,会导致错误,所以加了一句话重新编码并忽略错误。
- 使用BeautifulSoup解析HTML
from bs4 import BeautifulSoup
……
def download_exam():
……
soup = BeautifulSoup(html,'lxml')
exams=soup.find_all(name='div',attrs={'s':'math3'})
for x in exams:
out=analyzesoup(x)
exam.append(out)
……
def analyzesoup(soupobj:bs4.element.NavigableString):
def notNone(obj):
if obj is None:
return(False)
return(True)
result=soupobj.find(name='p',attrs={'class':'pt1'})#题干
if notNone(result):
tigan=result.get_text().strip()
result=soupobj.find(name='li')#如果是选择题
if notNone(result):
xuanxiang=[]
for i in soupobj.find_all(name='li'):
xuanxiang.append(i.get_text())
result=soupobj.find(attrs={'class':'col-md-3 column xz'})
if notNone(result):
daan=result.get_text()
else:
daan='未找到答案'
out={'tg':tigan,'xx':xuanxiang,'da':daan}
return(out)
……
- 使用xlwt将题目写入xls
import xlwt
……
def download_exam():
workbook = xlwt.Workbook(encoding = 'utf-8')
for j in range(1,102,1):
title=str(j)+soup.title.get_text()
worksheet = workbook.add_sheet(title)
……
sheetwriter(exam,worksheet)
workbook.save('dump.xls')
def sheetwriter(list,sheetobj):
……
_row=1
for item in list:
……
if 'xx' in item:#选择题
sheetobj.write(_row,1, label =item['tg'])
sheetobj.write(_row,0, label =item['da'])
col=2
for i in item['xx']:
sheetobj.write(_row,col, label =i)
col+=1
_row+=1
continue
if 'dm' in item:#填空题
lines=item['tg'].splitlines(False)
_row+=1
for line in lines:
sheetobj.write(_row,1, label =line)
_row+=1
lines=item['dm'].splitlines(False)
for line in lines:
sheetobj.write(_row,1, label =line)
_row+=1
continue
……
差不多完成了,测试一下
- 大概1分钟即可下载完所有题目
- 下载的题目:
- 选择题和简答题的答案写在A列,默认宽度为0(隐藏)
- 填空题和简答题的答案会出现在原位 (
太难提取了)
- 大概1分钟即可下载完所有题目
后记
- 信息学竞赛题库的题库结构很简单,很容易解析,而且完全公开,不用处理cookies,非常适合练手。
- 头一回见把答案写在前端,然后在前端用js显示答案的,这一招太骚了。
- 这是我写的第一个爬虫程序,经验不足,在所难免。