杭州电子科技大学的OJ

杭州电子科技大学的OJ(http://acm.hdu.edu.cn/)(以后简称杭电)很有特色,目前也很火,其中一个关键原因就是它提供了一些新功能,比如diy,webdiy,virtual contest等。这里我们简单讨论一下杭电的webdiy。

      webdiy是什么?是在DIY的基础上增加了从其他OJ选题的功能,那么DIY是什么?就是自己在本地选题,然后组成一场比赛。实现这个功能关键是能在其他OJ上提交,并能获得评判结果,直接往数据库里面写肯定是不可能的,那就只剩下一个方法:网络爬虫,模拟用户提交。

      最近一直在研究python的网络编程模块,用python来实现这个功能还是比较简单的,先看两张demo截图

 

左边是poj,右边是zoj,除了给出评判结果外,还有必要的提示信息

下面是代码实现:

POJ

复制代码

# -*- coding: utf-8 -*- 

import re
import sys
import logging
from time import sleep
import urllib,urllib2,cookielib
from BeautifulSoup import BeautifulSoup

class POJ:
    URL_HOME = 'http://poj.org/'
    URL_LOGIN = URL_HOME + 'login?'
    URL_SUBMIT = URL_HOME + 'submit?'
    URL_STATUS = URL_HOME + 'status?'
    #结果信息
    INFO =['RunID','User','Problem','Result','Memory','Time','Language','Code Length','Submit Time']
    #语言
    LANGUAGE = {
            'G++':'0',
            'GCC':'1',
            'JAVA':'2',
            'PASCAL':'3',
            'C++':'4',
            'C':'5',
            'FORTRAN':'6',
            }

    def __init__(self, user_id, password):
        self.user_id = user_id
        self.password = password
        cj = cookielib.LWPCookieJar()
        self.opener =urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
        urllib2.install_opener(self.opener)

    def login(self):
        data = dict(
                user_id1 = self.user_id,
                password1 = self.password,
                B1 = 'login',
                url = '.')
        postdata = urllib.urlencode(data)
        try:
            req = urllib2.Request(POJ.URL_LOGIN,postdata)
            res = self.opener.open(POJ.URL_LOGIN,postdata).read()
            if res.find('loginlog')>0: 
                logging.info("login successful!")
                return True
            else:
                logging.error('login failed')
                return False
        except:
            logging.error('login failed')
            return False

    def submit(self,pid,language,src):
        submit_data = dict(
                problem_id = pid,
                language = POJ.LANGUAGE[language.upper()],
                source = src,
                submit = 'Submit',)
        postdata2 = urllib.urlencode(submit_data)
        try:
            req2 = urllib2.Request(POJ.URL_SUBMIT,data = postdata2)
            res = self.opener.open(POJ.URL_SUBMIT,postdata2).read()
            logging.info('submit successful')
            return True
        except:
            logging.error('submit error')
            return False

    def result(self,user_id):
        url = POJ.URL_STATUS + urllib.urlencode({'user_id':user_id})
        page = urllib2.urlopen(url)
        soup = BeautifulSoup(page)
        table = soup.findAll('table',{'class':'a'}) #提取表格
        pattern = re.compile(r'>[-+: \w]*<')  #正则表达式匹配需要的信息
        result = pattern.findall(str(table))
        #正在评判,编译或等待
        wait = ['Running & Judging','Compiling','Waiting']
        for i in range(3):
            if result[32][1:-1]==wait[i] or result[32][1:-1] == '':
                logging.info(result[32])
#                sleep(1)
                return False
        #最终结果在result序列中的位置
        num = [21,24,28,32,35,37,40,43,45]
        for i in range(9):
            print POJ.INFO[i],':',result[num[i]][1:-1]
        return True


if __name__=='__main__':
    #基础logging模块配置
    FORMAT = '----%(message)s----'
    logging.basicConfig(level=logging.INFO,format = FORMAT)
    if len(sys.argv) > 1: #从外部传入参数
        user_id, pwd, pid, lang, src, = sys.argv[1:]
        src = open(src,'r').read()
    else:  #测试
        user_id = 'username'
        pwd = 'password'
        pid = 1000
        lang = 'gcc'
        src = '''
        #include<stdio.h>
        int main()
        {
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%d",a+b);
            return 0;
        }
        
'''
    logging.info('connecting to server')
    poj = POJ(user_id,pwd)
    if poj.login():
        logging.info("submiting")
        if poj.submit(pid,lang,src):
            logging.info('getting result')
            status = poj.result(user_id)
            while status!=True:  #直到检测到结果
                status = poj.result(user_id)
复制代码

ZOJ

复制代码
# -*- coding: utf-8 -*-
import re
import sys
import logging
from time import sleep
import urllib,urllib2,cookielib
from BeautifulSoup import BeautifulSoup

class ZOJ:
    URL_HOME = 'http://acm.zju.edu.cn/onlinejudge/'
    URL_LOGIN = URL_HOME + 'login.do?'
    URL_SUBMIT = URL_HOME + 'submit.do?'
    URL_STATUS = URL_HOME + 'showRuns.do?contestId=1&'
    
    #结果信息
    INFO =['RunID','Submit Time','Judge Status','Problem ID',
        'Language','Run Time(ms)','Run Memory(KB)','User Name']
    #语言:为了防止出错,gcc定义为C语言,g++定义为c++,zoj没有gcc和g++选项
    LANGUAGE = {
            'C':'1',
            'C++':'2',
            'FPC':'3',
            'JAVA':'4',
            'PYTHON':'5',
            'PERL':'6',
            'SCHEME':'7',
            'PHP':'8',
            'GCC':'1',
            'G++':'2',
            }

    def __init__(self, user_id, password):
        self.user_id = user_id
        self.password = password
        cj = cookielib.LWPCookieJar()
        self.opener =urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
        urllib2.install_opener(self.opener)

    def login(self):
        data = dict(
                handle = self.user_id,
                password = self.password,
                )
        postdata = urllib.urlencode(data)
        try:
            req = urllib2.Request(ZOJ.URL_LOGIN,postdata)
            res = self.opener.open(ZOJ.URL_LOGIN,postdata).read()
            if res.find(self.user_id)>0:
                logging.info("login successful!")
                return True
            else:
                logging.error('login failed')
                return False
        except:
            logging.error('login failed')
            return False

    def submit(self,pid,language,src):
        submit_data = dict(
                problemId = str(int(pid) - 1000),
                languageId = ZOJ.LANGUAGE[language.upper()],
                source = src,)
        postdata2 = urllib.urlencode(submit_data)
        try:
            req2 = urllib2.Request(ZOJ.URL_SUBMIT,data = postdata2)
            res = self.opener.open(ZOJ.URL_SUBMIT,postdata2).read()
            logging.info('submit successful')
            return True
        except:
            logging.error('submit error')
            return False

    def result(self,user_id):
        url = ZOJ.URL_STATUS + urllib.urlencode({'handle':user_id})
        page = urllib2.urlopen(url)
        soup = BeautifulSoup(page)
        table = soup.findAll('table',{'class':'list'})
        table = ''.join(str(table).split())
        pattern = re.compile(r'>[-+:\w]*<')
        result = pattern.findall(str(table))
        wait = ['Running','Compiling','Waiting']
        num = [18,20,23,27,31,34,36,40]
        for i in range(3):
            if result[23][1:-1]==wait[i]:
                logging.info(result[23])
                sleep(1)
                return False
        if result[23][1:-1] == '':
            num = [18,20,24,29,33,36,38,42]
        for i in range(8):
            print ZOJ.INFO[i],':',result[num[i]][1:-1]
        return True


if __name__=='__main__':
    FORMAT = '----%(message)s----'
    logging.basicConfig(level=logging.INFO,format = FORMAT)
    if len(sys.argv) > 1:
        user_id, pwd, pid, lang, src, = sys.argv[1:]
        src = open(src,'r').read()
    else:
        user_id = 'username'
        pwd = 'password'
        pid = 1001
        lang = 'c++'
        src = '''
        #include<stdio.h>
        int main()
        {
            int a,b;
            while(scanf("%d%d",&a,&b)!=EOF)
            printf("%d\\n",a+b);
            return 0;
        }
        
'''
    logging.info('connecting to server')
    zoj = ZOJ(user_id,pwd)
    if zoj.login():
        logging.info('submiting')
        if zoj.submit(pid,lang,src):
            logging.info('getting result')
            status = zoj.result(user_id)
            while status!=True:

                status = zoj.result(user_id) 

复制代码

      先简单解释一下代码:程序用urllib模块编码数据,用urllib2模块提交,用cookielib模块保存登录信息,提交成功后用beautifulsoup模块解析网页得到表格,然后用re模块正则表达式匹配最终结果,sys模块用来从外部程序外部传入参数,整个过程用logging日志模块记录事件日志。

      应该说,上面提到的模块都是经常用到的,都是应该熟练掌握的。上面只是一些简单用法,以后好要深入学习。

      再说说程序的用法(以poj为例):将上面的代码保存到"poj.py",然后在终端执行这个命令:”python poj.py username password problem_id language source_code_path“ 。将上面的用户名和密码替换成你自己的用户名和密码,problem_id是你要提交的题号,如1001,语言可以选gcc,g++,java,pascal等,最后是源文件所在的目录,如果源文件在当前目录下,可以省略路径,直接写文件名。

      这个程序仅仅实现了功能,用户可以根据需要自己扩展,让这个程序更易用,更实用,更符合你的要求,比如在程序中集成用户名和密码,自动识别题目号和语言,给poj.py增加执行权限然后把它所在的目录添加到环境变量或者直接把程序放到/usr/local/bin/目录下,这样的话,或许你以后用vim写完代码,然后一个命令“poj.py 1001.c”就自动交过去了,把这个程序集成到vim里面做成一键提交或许更爽!哈哈,这一切不是不可能!

      说来也有趣,poj和zoj很容易就实现了,但是在弄杭电时,却一直没成功,貌似杭电有防止网络爬虫的机制,杭电自己在其他oj上刷题,却不让别人在自己oj上刷。或许是我学艺不精,还要好好研究。网上说需要增加header,也就是模拟浏览器才能登录,但是登录以后提交却一直没提交成功,也不知道为什么,哪位大神知道帮忙解决一下?小弟感激不尽!

      上面只是一个demo,真正用到webdiy里面的话还要进行扩充,比如增加数据库的支持,还要抓取题目和编译错误信息。当提交量大的时候如何进行调度,网络不给力怎么办,出现错误如何处理等,这都是需要考虑的问题。上面的程序只是一个后台程序,如果做一个webdiy的话还要有前台的展示页面和后台的管理页面,正在学习django模块,希望能用这个框架做。


博主ma6174对本博客文章(除转载的)享有版权,未经许可不得用于商业用途。转载请注明出处http://www.cnblogs.com/ma6174/

对文章有啥看法或建议,可以评论或发电子邮件到ma6174@163.com


 
分类: ACMpython网络

python

poj和zoj自动登录,提交并获取评判结果
摘要: 杭州电子科技大学的OJ(http://acm.hdu.edu.cn/)(以后简称杭电)很有特色,目前也很火,其中一个关键原因就是它提供了一些新功能,比如diy,webdiy,virtual contest等。这里我们简单讨论一下杭电的webdiy。 webdiy是什么?是在DIY的基础上增加了从其他OJ选题的功能,那么DIY是什么?就是自己在本地选题,然后组成一场比赛。实现这个功能关键是能在其他OJ上提交,并能获得评判结果,直接往数据库里面写肯定是不可能的,那就只剩下一个方法:网络爬虫,模拟用户提交。 最近一直在研究python的网络编程模块,用python来实现这个功能还是比较...阅读全文

posted @ 2012-07-26 12:07 ma6174 阅读(503) | 评论 (0) 编辑

python urllib模块学习笔记
摘要: 这个模块是最基本最常用的,以前看过,总结一下#coding:utf-8importurlliburl='http://cnblogs.com'#代理服务器proxies={'http':'http://127.0.0.1:8087'}#使用代理服务器打开r=urllib.urlopen(url,proxies=proxies)printr.info()printr.getcode()printr.geturl()#打开本地文件f=urllib.urlopen(url='file:/home/ma6174/a.sh')printf.阅读全文

posted @ 2012-07-24 10:08 ma6174 阅读(57) | 评论 (2) 编辑

ssh批量登录并执行命令(python实现)
摘要: 人生苦短,我用python! 局域网内有一百多台电脑,全部都是linux操作系统,所有电脑配置相同,系统完全相同(包括用户名和密码),ip地址是自动分配的。现在有个任务是在这些电脑上执行某些命令,者说进行某些操作,比如安装某些软件,拷贝某些文件,批量关机等。如果一台一台得手工去操作,费时又费力,如果要进行多个操作就更麻烦啦。 或许你会想到网络同传, 网络同传是什么?就是在一台电脑上把电脑装好,配置好,然后利用某些软件,如“联想网络同传”把系统原样拷贝过去,在装系统时很有用,只要在一台电脑上装好,同传以后所有的电脑都装好操作系统了,很方便。同传要求所有电脑硬件完全相同,在联想的电脑...阅读全文

posted @ 2012-05-25 20:51 ma6174 阅读(1712) | 评论 (1) 编辑

python利用elaphe制作二维条形码
摘要: 条形码的应用将会越来越广泛,看到了一篇文章(http://www.systron.com.cn/txm-7.htm),写的挺好的!用手机拍二维码,查二维码确实很爽!这将成为一种潮流!手机上的二维码识别程序已经做的很好了,“我查查”用起来很不错的我搜集了几个二维条码生成网站:http://www.morovia.com/free-online-barcode-generator/qrcode-maker.phphttp://qrencode.sinaapp.com/http://www.mayacode.com/作为一个程序猿,我们也要懂得如何制作二维条形码python的elaphe模块帮我们解阅读全文

posted @ 2012-05-18 21:28 ma6174 阅读(203) | 评论 (1) 编辑

删除目录下相同文件 -> 逐级优化(python实现)
摘要: 不要整天往脑袋里塞算法,要适时把算法拿出来,应用到实际开发中! 这两天闲来无事在百度上淘了点图片,不多,也就几万张吧,其中有不少美女图片奥!哈哈!这里暂且不说图片是怎么获得的,咱聊聊得到图片以后发生的事。 遇到的第一个问题就是有些图片没有后缀名。在windows下,没有后缀名的文件是不能正确被识别的,没有预览,打开时还要选择打开方式,费劲!这个问题比较容易解决,给每个图片加上后缀名就是了。没有后缀名的图片也不多,不到1000张吧,一张一张地改很麻烦,还好我是学计算机的,上午写了个程序批量修改http://www.cnblogs.com/ma6174/archive/2012...阅读全文

posted @ 2012-05-05 01:54 ma6174 阅读(1162) | 评论 (14) 编辑

批量重命名文件——python实现
摘要: 任务很简单,某个目录下面有几千个文件,某些文件没有后缀名,现在的任务就是将所有的没有后缀名的文件加上后缀名,python有现成的函数可以实现,但是在实现过程中遇到几个问题,分享一下解决方法下面是最终代码 (windows下实现的)#-*-coding:cp936-*-importospath='D:\\图片\\'forfileinos.listdir(path):ifos.path.isfile(os.path.join(path,file))==True:iffile.find('.')<0:newname=file+'rsfdjndk.jpg&阅读全文

posted @ 2012-05-04 11:07 ma6174 阅读(428) | 评论 (0) 编辑

配置python的eclipse开发环境
摘要: eclipse狠强大!在eclipse下开发python很方便!代码提示功能比较完善!在eclipse下配置python开发环境不算难,简单记录一下.1.help -> Install New Software,点击"add",在name里面输入"PyDev",location里面输入"http://pydev.org/updates"2.在出来的列表里面选择"PyDev",然后狂点下一步就是了,网络好的话很快就能安完3.配置编译器:我window -> perferences,依次找到PyDev -&阅读全文

posted @ 2012-04-29 20:38 ma6174 阅读(95) | 评论 (0) 编辑

多机调度问题——python实现
摘要: 问题描述:有N个独立作业,每个作业处理时间为time[i],有M个相同的机器加工处理,约定每个作业可以在任何一台机器上加工处理,未完工前不允许中断处理,作业不能拆分成更小的子作业。要求在最短时间内完成,求最短时 解决方案最理想的方法是平均分配,每台机器处理的时间相同,最后同时处理完任务。实际情况中不一定能完全分配,我们应尽量缩小各个机器处理时间的差距,用贪 心算法可以比较好的解决:先将作业处理时间降序排列,依次选择时间往机器上安排,每次安排在当前工作量总时间最小的机器上,最后求得时间差距最小 代码实现#!/usr/bin/envpython#-*-coding:utf...阅读全文

posted @ 2012-04-24 15:16 ma6174 阅读(72) | 评论 (0) 编辑

OJ问题检测程序---python开发
摘要: 懒人总是想方设法使自己更懒,特别是学计算机的孩纸。 问题来源很简单,OJ评测程序有点问题,有时候不知到怎么回事就waiting了,一但waiting后面所有提交的代码就都waiting了, OJ就不能正常评测了,这时候就需要去服务器端解决问题。怎么解决评测问题不是本次讨论的重点,这里我们更关心的是如何及时发现问题。我们怎么发现问题呢?一般情况下,我们要打开OJ,找到状态页面,然后看看评判结果有没有waiting的,这样做的话,你就要过一段时间就打开页面一次,查看有没有出问题,麻烦!想过没有,一但OJ开始waiting了,你就收到一个短信,告诉你OJ出问题了,你就可以马上解决,这样多好啊。...阅读全文

posted @ 2012-03-23 20:07 ma6174 阅读(1001) | 评论 (2) 编辑

编译原理----词法分析程序----python语言版
摘要: 对python的应用还是不熟练,很多实用的方法没掌握,下面的程序本来是用C写的,为了练习一下python,又用python改写的,很粗糙,有bug,不过能运行出结果,嘿嘿,以后学好了python再来优化吧#-*-coding:cp936-*-Keyword=("begin","end","if","while","var","procedure","else","for","do","int",&阅读全文

posted @ 2012-03-20 09:38 ma6174 阅读(156) | 评论 (2) 编辑

原文地址:https://www.cnblogs.com/Leo_wl/p/2610309.html