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模拟浏览器。

三、数据整理

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

用xpath找我们想要的部分

例如找题目名称

但是后面的数据有点难下手,小标题包含在<h3>标签中,内容文字在<p>标签里,且他俩并列而非包含,但是像pid=1000的例子中看到的那样,后面输入样例的数据、输出样例的标题和数据跑到下一层包含中去了。

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

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

代码如下

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

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

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

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

四、效果

保存的题目
保存的图片

五、保存数据

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

五、完整代码

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')

代做工资流水公司绵阳对公银行流水泰州对公流水代办廊坊打企业对公流水入职银行流水公司许昌消费贷流水烟台银行流水多少钱廊坊查询工资流水app截图成都代开房贷流水成都打印薪资流水长沙查询签证银行流水湛江做工资流水兰州购房银行流水打印九江开背调银行流水新乡薪资流水报价惠州车贷流水查询中山企业流水打印图片温州薪资银行流水费用天津银行流水PS价格太原车贷流水多少钱许昌流水账单代办镇江企业银行流水图片荆州工资证明制作海口代做个人工资流水佛山工资流水单代办湖州流水单查询包头办理日常消费流水九江做薪资流水台州背调工资流水多少钱淮安银行流水电子版代办厦门查银行流水单香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

代做工资流水公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化