python棋盘放米oj题和答案_python抓取信息学奥赛一本通OJ题库

〇、前言

一直想自己搭建一个OJ平台,以后或许可以给学校用,正在依次学习需要的知识。OJ平台需要题库,打算先从已有的OJ平台上抓下来,方便实验。

当然,能拿到的只有题目,测试点数据目前看来还是需要自己造咯。

学习python和爬虫有一段时间了,于是乎打算用python写个小爬虫抓题库。

OJ平台选择了大学课程上老师指定的信息学奥赛一本通(C++)版在线测评网站(其实还有一个原因是他的网站设计相对简单,数据好拿一点)。

一、踩点

网站非常简洁(lou),不登录也可以看到题目。

url里传递数据“pid=”后面的数字就是题目的编号,从1000开始。

我们需要的数据是一道题目的“编号”、“题目名称”、“题目描述”、“输入”、“输出”、“输入样例”、“输出样例”、“提示”(部分题目中有这一项)。这个OJ中“来源”写的都是“NO”,对我们意义不大,就不抓他了。

这里想到需要注意的部分:

1.可能会有图片。

2.部分题目有“提示”这一块内容。

F12查看我们需要的数据的部分,写的不是很整齐,包含关系有点混乱。

二、抓取数据

这里用requests.get抓取网站。

复制题目的url,先随便写个合理的pid,到时候外层套个循环就能抓所有题目了。按照规范构造个headers模拟浏览器。

urls = 'http://ybt.ssoier.cn:8088/problem_show.php?pid=%d'

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

req = requests.get(url=urls % '1000', headers=headers).text.encode('ISO-8859-1', 'ignore').decode('utf-8', 'ignore')

三、数据整理

我用的是lxml库处理抓下来的网页数据。

from lxml import etree

reqhtml = etree.HTML(req)

用xpath找我们想要的部分

例如找题目名称

res = reqhtml.xpath('//center/table/td/center/h3')

tmmc = res[0].text

但是后面的数据有点难下手,小标题包含在

标签中,内容文字在

标签里,且他俩并列而非包含,但是像pid=1000的例子中看到的那样,后面输入样例的数据、输出样例的标题和数据跑到下一层包含中去了。

那么我们只能暂且不从逻辑关系上分析,把他们可能存在的标签位置全部抓取下来,再根据小标题文字内容进行整理。

比如,“题目描述”之后的内容都为题目描述的文字部分,直到出现“输入”。

代码如下

res = reqhtml.xpath('//p|//h3|//font/div/pre|//font/p|//p/img/@src')

for i in res:

if not hasattr(i, 'text'):

with open('./%s' % str(i), 'wb') as f:

f.write(requests.get('http://ybt.ssoier.cn:8088/%s' % str(i)).content)

if tyb == 1:

tmms += str(i)

elif tyb == 2:

sr += str(i)

elif tyb == 3:

sc += str(i)

elif tyb == 4:

sryl += str(i)

elif tyb == 5:

scyl += str(i)

elif tyb == 6:

ts += str(i)

continue

if(i.text):

if i.text == '【题目描述】':

tyb = 1

elif i.text == '【输入】':

tyb = 2

elif i.text == '【输出】':

tyb = 3

elif i.text == '【输入样例】':

tyb = 4

elif i.text == '【输出样例】':

tyb = 5

elif i.text == '【提示】':

tyb = 6

elif i.text == '【来源】':

break

elif tyb == 1:

tmms += i.text

elif tyb == 2:

sr += i.text

elif tyb == 3:

sc += i.text

elif tyb == 4:

sryl += i.text

elif tyb == 5:

scyl += i.text

elif tyb == 6:

ts += i.text

用一个tyb作为标记,指示现在读取的是哪一块内容。

如果读到图片——也就是说内容不存在“text”属性,把图片保存起来,在文本位置加一段“图片+图片序号”作为标记,方便后期处理,把图片再加上去。

如果是文字的话,就把他加入到相应的字符串之中。

读到“来源”,说明前面的内容都已经处理完了,而我们又不需要记录来源,直接结束掉。

四、效果保存的题目保存的图片

五、保存数据

上一步已经成功按照内容类别,把需要的数据记录到各自的字符串中,保存数据就非常方便了,打印输出、保存到数据库都不是难事,我这里先保存在了excel中。

import xlwt

save_file = xlwt.Workbook()

save_sheet = save_file.add_sheet(u'sheet1')

save_sheet.write(pid - 999, 0, pid)

save_sheet.write(pid-999, 1, tmmc)

save_sheet.write(pid - 999, 2, tmms)

save_sheet.write(pid - 999, 3, sr)

save_sheet.write(pid - 999, 4, sc)

save_sheet.write(pid - 999, 5, sryl)

save_sheet.write(pid - 999, 6, scyl)

save_sheet.write(pid - 999, 7, ts)

save_sheet.write(pid - 999, 7, ts)

save_file.save('./信息学奥赛题库.xls')

五、完整代码

import requests

from lxml import etree

import xlwt

def bashuoj(save_file):

save_sheet = save_file.add_sheet(u'sheet1')

urls = 'http://ybt.ssoier.cn:8088/problem_show.php?pid=%d'

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

for pid in range(1000, 1418):

req = requests.get(url=urls % pid, headers=headers).text.encode('ISO-8859-1', 'ignore').decode('utf-8', 'ignore')

print('开始抓取%d题' % pid)

reqhtml = etree.HTML(req)

res = reqhtml.xpath('//center/table/td/center/h3')

tmmc = res[0].text

tmms = ''

sr = ''

sc = ''

sryl = ''

scyl = ''

ts = ''

tyb = 0

res = reqhtml.xpath('//p|//h3|//font/div/pre|//font/p|//p/img/@src')

for i in res:

if not hasattr(i, 'text'):

with open('./%s' % str(i), 'wb') as f:

f.write(requests.get('http://ybt.ssoier.cn:8088/%s' % str(i)).content)

if tyb == 1:

tmms += str(i)

elif tyb == 2:

sr += str(i)

elif tyb == 3:

sc += str(i)

elif tyb == 4:

sryl += str(i)

elif tyb == 5:

scyl += str(i)

elif tyb == 6:

ts += str(i)

continue

if(i.text):

if i.text == '【题目描述】':

tyb = 1

elif i.text == '【输入】':

tyb = 2

elif i.text == '【输出】':

tyb = 3

elif i.text == '【输入样例】':

tyb = 4

elif i.text == '【输出样例】':

tyb = 5

elif i.text == '【提示】':

tyb = 6

elif i.text == '【来源】':

break

elif tyb == 1:

tmms += i.text

elif tyb == 2:

sr += i.text

elif tyb == 3:

sc += i.text

elif tyb == 4:

sryl += i.text

elif tyb == 5:

scyl += i.text

elif tyb == 6:

ts += i.text

save_sheet.write(pid - 999, 0, pid)

# print('【题目名称】')

# print(tmmc)

save_sheet.write(pid-999, 1, tmmc)

# print('【题目描述】')

# print(tmms)

save_sheet.write(pid - 999, 2, tmms)

# print('【输入】')

# print(sr)

save_sheet.write(pid - 999, 3, sr)

# print('【输出】')

# print(sc)

save_sheet.write(pid - 999, 4, sc)

# print('【输入样例】')

# print(sryl)

save_sheet.write(pid - 999, 5, sryl)

# print('【输出样例】')

# print(scyl)

save_sheet.write(pid - 999, 6, scyl)

# print('【提示】')

# print(ts)

save_sheet.write(pid - 999, 7, ts)

print(pid, '完毕')

if __name__ == '__main__':

save_file = xlwt.Workbook()

bashuoj(save_file)

save_file.save('./信息学奥赛题库.xls')

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值