欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python分析 oj 网的题目难度和通过率的关系

程序员文章站 2022-07-05 15:16:56
本着做题的心态,上了东莞理工学院的 oj 网;看了一下题目不想动手,在选择难度的时候发现有些通过率和难度可能存在着某些关系,于是决定爬下这些数据简单查看一下是否存在关系。 一、新建项目 我是用 Scrapy 框架爬取的(因为刚学没多久,顺便练练手)。首先,先新建 project (下载 Scarpy ......

  本着做题的心态,上了东莞理工学院的 oj 网;看了一下题目不想动手,在选择难度的时候发现有些通过率和难度可能存在着某些关系,于是决定爬下这些数据简单查看一下是否存在关系。

 

一、新建项目

  我是用 scrapy 框架爬取的(因为刚学没多久,顺便练练手)。首先,先新建 project (下载 scarpy 部分已省略),在控制台输入 scrapy startproject onlinejudge(其中, onlinejudge为项目名称),敲击回车键新建项目完成。

二、明确目的

  在动手写代码之前,先分析一下网页结构。网站是通过动态加载的,数据通过 json 文件加载。

Python分析 oj 网的题目难度和通过率的关系

 

  1、明确要爬取的目标: http://oj.dgut.edu.cn/problems 网站里的题目,难度,提交量,通过率。在查找 json 的时候发现只有通过数,那么通过率就要自己计算。

  2、打开 onlinejudge 目录下的 items.py 写下如下代码:

class onlinejudgeitem(scrapy.item):

    id = scrapy.field()                     # 题目编号
    title = scrapy.field()                  # 标题
    difficulty = scrapy.field()             # 难度
    submissionno = scrapy.field()         # 提交量
    acceptedno = scrapy.field()           # 正确数
    passingrate = scrapy.field()           # 正确率

三、制作爬虫

  1、在当前目录下输入命令:scrapy genspider oj "oj.dgut.edu.cn" (其中 oj 是爬虫的名字,"oj.dgut.edu.cn"算是一个约束,规定一个域名)

  2、打开 onlinejudge/spiders 下的 ojspider.py ,增加或修改代码为:

import scrapy
import json
from onlinejudge.items import onlinejudgeitem

class ojspider(scrapy.spider):
    name = 'oj'        # 爬虫的名字
    allowed_domains = ['oj.dgut.edu.cn']     # 域名范围
    offset = 0
    url = 'http://oj.dgut.edu.cn/api/xproblem/?limit=20&offset='
    start_urls = [url + str(offset)]       # 爬取的url元祖/列表

    def parse(self, response):
        data = json.loads(response.text)['data']['results']
        if len(data):
            for i in range(len(data)):
                submissionno = data[i]['submission_number']
                acceptedno = data[i]['accepted_number']
                try:
                    passingrate = round((int(acceptedno)/int(submissionno)) * 100, 2)
                except zerodivisionerror as e:
                    passingrate = 0
    
                strpr = str(passingrate) + "%"
    
                item = onlinejudgeitem()
    
                item['id'] = data[i]['_id']
                item['title'] = data[i]['title']
                item['difficulty'] = data[i]['difficulty']
                item['submissionno'] = submissionno
                item['acceptedno'] = acceptedno
                item['passingrate'] = strpr
    
                yield item

                print(i)
            self.offset += 20
            yield scrapy.request(self.url + str(self.offset), callback=self.parse)
 

四、存储数据

    1、打算将数据存储为 excel 文档,要先安装 openpyxl 模块,通过 pip install openpyxl 下载。

    2、下载完成后,在 pipelines.py 中写入如下代码

from openpyxl import workbook

class onlinejudgepipeline(object):

    def __init__(self):
        self.wb = workbook()
        self.ws = self.wb.active                # 激活工作簿
        self.ws.append(['编号', '标题', '难度', '提交量', '正确数', '正确率'])    # 设置表头

    def process_item(self, item, spider):
        line = [item['id'], item['title'], item['difficulty'],
                item['submissionno'], item['acceptedno'], item['passingrate']]
        self.ws.append(line)
        self.wb.save('oj.xlsx')
        return item

五、设置 settings.py 

    修改并增加代码:

log_file = "oj.log"

robotstxt_obey = true

item_pipelines = {
    'onlinejudge.pipelines.onlinejudgepipeline': 300,
}

六、运行爬虫

  在当前目录下新建一个 main.py 并写下如下代码

from scrapy import cmdline

cmdline.execute("scrapy crawl oj".split())

  然后运行 main.py 文件。

 

  于是,想要的数据就被爬下来了

Python分析 oj 网的题目难度和通过率的关系

 

七、分析数据

  分析数据之前,先安装好 numpy,pandas,matplotlib,xlrd。

import pandas as pd
import xlrd

data = pd.read_excel("../onlinejudge/onlinejudge/oj.xlsx")
data.describe()

Python分析 oj 网的题目难度和通过率的关系

data = data.set_index('编号')
data.head()

Python分析 oj 网的题目难度和通过率的关系

from matplotlib import pyplot as plt
import matplotlib.style as psl
%matplotlib inline

psl.use('seaborn-colorblind')    # 设置图表风格
plt.rcparams['font.sans-serif']=['simhei'] #用来正常显示中文标签

  查看题目各难度的数目:

level_values = data['难度'].values

difficulties = {
    '简单': 0,
    '中等': 0,
    '困难': 0
}

for value in level_values:
    if value == '简单':
        difficulties['简单'] += 1
    elif value == '中等':
        difficulties['中等'] += 1
    else:
        difficulties['困难'] += 1

level = pd.series(difficulties)
print(level)

level.plot(kind = 'bar', figsize=(6, 7))
plt.grid(axis='y')

Python分析 oj 网的题目难度和通过率的关系

  验证正确率与难度直接是否存在关系:

import numpy as np

relation = data[['难度', '正确率']]
rate_values = relation['正确率'].values

fig, axes = plt.subplots(figsize=(15, 6))
axes.scatter(rate_values, level_values)
plt.grid(axis='x')
plt.xticks(np.arange(0, 1, 0.05))
plt.xlabel('正确率')
plt.ylabel('难度')

Python分析 oj 网的题目难度和通过率的关系

根据表格显示,题目难度跟正确率是存在一定关系的(我想的没有错哈哈哈)。