OnlineJudge 离线题库采集
????過段時間要把以前的OJ換掉,我負(fù)責(zé)VirtualJudge的部分。需要用C與PHP寫一個Linux下的VJudge。
????在此之前,將以前寫給自己學(xué)弟學(xué)妹用的OJ離線題庫的采集程序改進(jìn)了一下。支持國內(nèi)一些知名高校的OJ,為之后VJudge的開發(fā)練練手,熟悉下各個OJ的結(jié)構(gòu),免去以后再在LINUX上進(jìn)行一些繁瑣的測試。
????題目的采集沒有使用任何OJ的API,直接采取從HTML頁面采集數(shù)據(jù)并處理的方式。下載HTTP文件使用的是WinINet函數(shù)集,用起來比CURL還方便。正則表達(dá)式使用的ATL庫里的regex。題目的儲存使用的文件進(jìn)行儲存。別看一個OJ就有幾千道題,文件結(jié)構(gòu)訪問的速度卻是相當(dāng)?shù)乜臁R驗(yàn)樽ト〕鰜淼念}目有大量的HTML標(biāo)簽,先要全部去掉非常地困難(一些題目有不同的格式與鏈接標(biāo)簽,甚至有一些題目是關(guān)于標(biāo)記語言的題目)。因?yàn)槲椰F(xiàn)在做的是離線的題庫,于是將這些標(biāo)簽保留寫來,利用HTML的方式顯示我采集的題目。
????目前做了六個OJ:
????1、bnu(北京師范大學(xué)OJ):這個OJ我覺得是國內(nèi)用戶體驗(yàn)做得最好的一個OJ,自己OJ的題目很豐富(含有較多不錯的中文),VOJ的功能也完美地融合在自己的OJ中。
????2、hdu(杭州電子科技大學(xué)OJ):擁有國內(nèi)最強(qiáng)判題機(jī)群,國內(nèi)各大算法競賽都選在杭電OJ舉行。
????3、neu(成都東軟學(xué)院OJ):很多人可能都不知道這OJ,也是國內(nèi)少數(shù)登錄需要驗(yàn)證碼的奇葩OJ,以至于VOJ想支持它都困難,簡單題爆多,歡迎來擼。我母校嘛,必須有,雖然我亞洲區(qū)牌都沒拿到個,學(xué)校最高也就個銅。補(bǔ)習(xí)班性質(zhì)的比賽嘛,二本學(xué)校的學(xué)生都不想把耍的時間花在覺得苦逼的事情上,我能拿著塑料堅(jiān)持那么久也是NB了。該OJ即將在今年更換新的系統(tǒng),判題內(nèi)核、數(shù)據(jù)管理、界面、以及VOJ都由我們的老成員完成。希望以后學(xué)校的騷年能取得好成績--wchrt。
????4、poj(北京大學(xué)OJ):搞ICPC的騷年都知道,國內(nèi)最為知名的OJ之一。
????5、vijos(高效信息學(xué)在線評測系OJ):里面全是中文題哦,小心有大量的小學(xué)生,分分鐘虐爆你的小學(xué)生。
????6、zoj(浙江大學(xué)OJ):國內(nèi)起步最早的OJ之一,但我基本沒怎么用過這個OJ。
????下面根據(jù)各oj分別列出了獲取題目內(nèi)容與標(biāo)題的正則表達(dá)式:
????????ojnum=0;cbox->AddString("bnu");ojurl[ojnum]="http://www.bnuoj.com/bnuoj/problem_show.php?pid=";ojgetstr[ojnum].allcontent="{<div?id=\"showproblem\">(.|\n)*?<div?id=\"one_content_base\">}";ojgetstr[ojnum].title="<div?id=\"showproblem\.*?<h1.*?>{.*?}</h1>";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("hdu");ojurl[ojnum]="http://acm.hdu.edu.cn/showproblem.php?pid=";ojgetstr[ojnum].allcontent="{<h1(.|\n)*?Note</a>}";ojgetstr[ojnum].title="<h1.*?>{.*?}</h1>";ojgetstr[ojnum].iscode=false;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("neu");ojurl[ojnum]="http://acm.nsu.edu.cn/JudgeOnline/problem.php?id=";ojgetstr[ojnum].allcontent="{<div?id=main(.|\n)*?Sample?Output(.|\n)*?BBS(.|\n)*?</a>}";ojgetstr[ojnum].title="<title.*?>{.*?}</title>";//目前不需要把內(nèi)容信息分開,就不正則詳細(xì)的題目內(nèi)容/*ojgetstr[ojnum].tim="Time?Limit:{.*?} ";ojgetstr[ojnum].mem="Memory?Limit:{.*?}<br>";ojgetstr[ojnum].des=">Description</h2>.*?<div.*?>{.*?}</div>";ojgetstr[ojnum].input=">Input</h2>.*?<div.*?>{.*?</div>.*?}</div>";ojgetstr[ojnum].output=">Output</h2>.*?<div.*?>{.*?}</div>";ojgetstr[ojnum].sinput=">Sample?Input</h2>.*?{<pre>(.|\n)*?</pre>}";ojgetstr[ojnum].soutput=">Sample?Output</h2>.*?{<pre>(.|\n)*?</pre>}";*/ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("poj");ojurl[ojnum]="http://poj.org/problem?id=";ojgetstr[ojnum].allcontent="{<div?class=\"ptt\"(.|\n)*?Discuss</a>}";ojgetstr[ojnum].title="<div?class=\"ptt\".*?>{.*?}</div>";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=49;//poj最多只允許短時間訪問49道題ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("vijos");ojurl[ojnum]="https://vijos.org/p/";ojgetstr[ojnum].allcontent="{<div?class=\"pcontent\">(.|\n)*}<h4";ojgetstr[ojnum].title="<div?class=\"content\">.*?</span>{.*?}<div";ojgetstr[ojnum].iscode=true;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;cbox->AddString("zoj");ojurl[ojnum]="http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=";ojgetstr[ojnum].allcontent="{<div?id=\"content_body\">(.|\n)*</div>}";ojgetstr[ojnum].title="<div?id=\"content_body\">.*?>.*?>{.*?}</span>";ojgetstr[ojnum].iscode=false;ojgetstr[ojnum].getnum=-1;ojgetstr[ojnum].pnostart=1000;ojnum++;因?yàn)椴煌腛J網(wǎng)站所使用的編碼格式不同,我使用的是ansi,所以要把一些使用utf-8的網(wǎng)頁轉(zhuǎn)換為ansi,下面是轉(zhuǎn)換的代碼:
????使用WinINet函數(shù)集的CInternetSession與CHttpFile下載HTTP文件,那hdu作為例子
hdu的1001題的地址是:"http://acm.hdu.edu.cn/showproblem.php?pid=1001"
這里的http://acm.hdu.edu.cn/showproblem.php是hdu的題目PHP文件,我們需要以GET的方式請求pid=1001的數(shù)據(jù)。對于hdu的其他題目,我們只需把pid的值設(shè)置成其他的值即可。
????因?yàn)槊總€OJ的題目都有幾千道,不可能每次打開軟件都去遍歷那么幾千個文件,效率太低而且容易出錯。因此我將每個題目的ID和標(biāo)題都提取出來,放到一個文件中記錄,用于題目的引索。
引索的結(jié)構(gòu)是:題目數(shù)量、id1、標(biāo)題1、id2、標(biāo)題2、id3...的格式,每個OJ一個表。
下面是儲存記錄的代碼,使用序列化儲存:
????????CFile?file;if(!file.Open("c:\\ojdata\\"+oj+"\\pinfo",CFile::modeWrite)){if(!file.Open("c:\\ojdata\\"+oj+"\\pinfo",CFile::modeCreate|CFile::modeWrite)){AfxMessageBox("寫入出錯");return?1;}}CArchive?ar(&file,CArchive::store);ar<<that->infonum;for(int?i=0;i<that->infonum;i++){ar<<(&that->problemarr[i]);}ar.Close();file.Close();//統(tǒng)計(jì)題目下載成功與失敗str.Format("SECC:%d??FAIL:%d",that->infonum,totalnum-50-that->infonum);hdu的:
全是中文題目的OJ,不錯不錯:
水水更健康:
????基本上題目的采集工作到此結(jié)束。以后做VOJ的時候再將各個部分正則出來。
因?yàn)榫W(wǎng)絡(luò)環(huán)境的因素,OJ題目的訪問速度不一定很快,這里可以用開多個線程進(jìn)行下載,以及優(yōu)化題目的下載和處理,因?yàn)槲铱梢灾苯訏煸谖业姆?wù)器上下載,所以就一條線程下載處理完了。我用的電信50M的寬帶(坑爆,說是50M,上行只有不到2M,電信太煎餅了,一個月169還不包含短信費(fèi),80端口封完喊還推薦我開3000一個月的商務(wù)寬帶)大概下載一個OJ的所有題目10多分鐘,我直接6個OJ一起下載的。不想等待的朋友可以直接在附件下載我采集好的題目包,把它解壓到到C盤即可。
????采集到了題目,怎么看呢?肯定不能直接給人看,一堆標(biāo)記語言煩死了。WINDOWS自帶了瀏覽器控件,直接使用它即可,我使用了兩種方式,一種是對話框上的HTML控件,可能是我的原因但是這個控件不穩(wěn)定, 在一些電腦上老加載出錯。
????于是我另外用了CDHtmlDialog。這直接是個HTML的對話框,每次把題目的本地地址給他后讓其Navigate即可。由于我題目是儲存的一個problemdata結(jié)構(gòu)體,含有一些其他的信息。打開題目前需要把要顯示的題目提取出來,重新生成一個HTML文件,然后再讓HTML對話框打開它。
????題目的顯示過程:
????整個離線題庫就是這樣,需要支持其他OJ只要改改正則和題號即可,對于一些沒法直接獲取到題目的OJ要做另外的處理,uestc的新OJ就需要另外的方式獲取題目內(nèi)容。
????采集程序源碼
????采集程序
????OJ題庫下載
轉(zhuǎn)載于:https://blog.51cto.com/wchrt/1606066
總結(jié)
以上是生活随笔為你收集整理的OnlineJudge 离线题库采集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国农业银行abc是什么意思
- 下一篇: 个人银行征信如何查询