Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8833

[AtCoder]問題の入力と期待値を自動取得してみた

$
0
0

はじめに

言語の勉強としてAtCoderのABC(AtCoder Beginners Contest)の問題を解いていました。
しかし問題ページにある複数の入力サンプルと出力サンプルをコピペして目視であってるかどうかを確認するのは面倒だなと思いました。
そこでpuppeteerによるスクレイピングで入力サンプルと出力サンプルを自動で取ってきて、自動でテストするスクリプトを書いてみました。
今回はpuppeteer部分でやったことなどを残しておきます。

調査

問題ページのURLは、例えば第88回目のABCのB問題はhttps://atcoder.jp/contests/abc088/tasks/abc088_b
第160回目のABCのD問題はhttps://atcoder.jp/contests/abc160/tasks/abc160_b
となってます。
問題ページのURLは、

https://atcoder.jp/contests/<コンテスト名>/tasks/<コンテスト名>_<問題名>

で取れることがわかりました。
次に各問題ページ入力と出力例のDOM情報を調べてみます。
幸いどの問題でも例えば入力1では、

html > body > div#main-div.float-container > div#main-container.container > \
div.row > div.col-sm-12 > div#task-statement > span.lang > span.lang-ja > \
div.part > section > pre#pre-sample0

ここに配置されていることが確認できました。
pre#pre-sample<数字>の部分に関しては
入力1 -> pre#pre-sample0
出力1 -> pre#pre-sample1
入力2 -> pre#pre-sample2
出力2 -> pre#pre-sample3
入力3 -> pre#pre-sample4
出力3 -> pre#pre-sample5
...
となっていました。
これだけの情報で十分です。

コード例

第xxx回目ABC -> abc<xxx>
A問題 -> a
として例えば第160回目ABCのA問題のサンプルを全部取得したい時は、

node get_sample.js abc160 a

とコマンドライン引数を与えることを前提として以下のようにコードが書けます。

#!/usr/bin/env node
constpuppeteer=require('puppeteer');constfs=require('fs')//ex; abc161constcontest_number=process.argv[2]//ex; a,b,c..,fconstquestion=process.argv[3]constatcoder_url="https://atcoder.jp/contests/"+contest_number+"/tasks/"+contest_number+"_"+question(async()=>{constbrowser=awaitpuppeteer.launch();constpage=awaitbrowser.newPage();awaitpage.goto(atcoder_url);constcommon_selector='html > body > div#main-div.float-container > div#main-container.container > div.row > div.col-sm-12 > div#task-statement > span.lang > span.lang-ja > div.part > section > 'for(i=0;;i+=2){constin_selector=common_selector+`pre#pre-sample${i}`;constexp_selector=common_selector+`pre#pre-sample${i+1}`;//取得する前にそもそもデータが存在するかのチェックを行うconstin_data=awaitpage.$(in_selector)!=null?awaitpage.$eval(in_selector,item=>{returnitem.textContent;}):nullconstexp_data=awaitpage.$(exp_selector)!=null?awaitpage.$eval(exp_selector,item=>{returnitem.textContent;}):nullif(in_data!=null){constfilepath=`./test/in${i/2+1}`fs.writeFile(filepath,in_data,(err,data)=>{if(err)console.log(err);});}else{break;}if(exp_data!=null){constfilepath=`./test/exp${i/2+1}`fs.writeFile(filepath,exp_data,(err,data)=>{if(err)console.log(err);});}else{break;}}awaitbrowser.close();})();

これでカレントディレクトリのtestというディレクトリに入力例(in〇)と出力例(exp〇)を保存できます。
このjsにshebangを記載しパスの通ったディレクトリに置いておくことでいつでも呼び出せるようにしておきます。
自動テストスクリプトの実装は省きますが、このjsにshebangを記載することで自動テストスクリプトをshellスクリプトで書いた場合、呼び出しも簡単になります。

get_sample.js <コンテスト名> <問題名>

自動テストスクリプトではカレントディレクトリのtest/in1,in2,in3があることを確認し
あれば、プログラムのビルドし、これらを入力とし、実行。
それぞれの結果とexp1,exp2,exp3が一致するかはdiffコマンドで確認できます。

最後に

最近アルゴリズムの勉強もした方がいいのかなと思う今日この頃、、、AtCoderまずは緑色頑張ります!


Viewing all articles
Browse latest Browse all 8833

Trending Articles