PPC と見せかけて Web の話です.
はじめに
25B の みどりむし🦠 です.
受験期に競プロを離れて以来, ついぞコンテストに参加しないまま半年が経ってしまいました.
そろそろ再開のために環境を復元しようとしていたところ, 最近実装された CLOUDFLARE 認証に手元の半自動提出環境が破壊されていたので, その対処法を記録します.
必要なログイン情報
詳細は省きますが, AtCoder へログインするには (初回を除き) 少なくとも HTTP Cookie (のうち, REVEL_SESSION
の値) があればよいです.
逆にこれさえ取得できれば, それをリクエストヘッダの Cookie
プロパティに渡してやることで, コンテスト中にも問題ページにアクセスして問題文やサンプルをスクレイピングしたりできるようになります. (開催中のコンテストに限り自動提出も可能です. )
HTTP Cookie
document.cookie
を参照しても取得できないので, 別な方法で持ってきます.
適当なリクエストのレスポンスヘッダから拝借する方法
atcoder.jp にログイン済みのブラウザで開発者ツールを開き, 一旦リロードしておきます.
開発者ツールの Network タブを開き, 表示されているリクエストのうち一番上のものの Response Headers から Set-Cookie
プロパティの値をそのまま控えておけばよいです.
開発者ツールから直接取得する方法
atcoder.jp にログイン済みのブラウザで開発者ツールを開き, Application > Cookies > https://atcoder.jp
> REVEL_SESSION
の値を控えておきます.
使用する際は以下の形で用います:
REVEL_SESSION={{控えた値}}
atcoder-cli を使用している場合
筆者はまともに使ったことがないのですが, 利用人口がそれなりにありそうですので atcoder-cli に適用する方法を述べておきます.
atcoder-cli の Cookie の保存場所は ~/.config/atcoder-cli-nodejs/session.json
らしいので, これを以下のように書き換えればよいです:
{
"cookies": [
"REVEL_SESSION={{ここに前項で得た Cookie の REVEL_SESSION をペーストする}}"
]
}
おそらく現在 atcoder-cli を利用できている人もセッションの期限が切れ次第突然弾かれるようになると思いますので, その際はこの手順で手動復帰してあげてください.
online-judge-tools (oj) を使用している場合
oj は selenium.webdriver を用いてお使いのブラウザからアクセスを試みるようです.
つまり基本的には何もしなくてもよいということです.
実装例 (Node.js)
執筆前の想定よりもあっさり済んでしまったので, 尺調整としてソースを自動提出するプログラムの実装例を紹介してみます.
const Axios = require("axios");
const axios = Axios.create({
headers: {
"X-Requested-With": "XMLHttpRequest",
"Accept-Encoding": "gzip",
Cookie: "{{Cookie}}",
},
timeout: 15 * 1000,
});
const data = new URLSearchParams();
data.append("data.TaskScreenName", "{{Problem ID}}");
data.append("data.LanguageId", "{{Language ID}}");
data.append("sourceCode", "{{Source Code}}");
data.append("csrf_token", "{{CSRF Token}}");
axios.post("https://atcoder.jp/contests/{{Problem ID}}/submit", data);
CSRF Token
コンテスト中に自動提出をするためには CSRF Token を body に含める必要があるようです. この値は前項で取得した Cookie にも含まれてはいますが, 少々抽出が面倒なので他の方法を述べておきます.
atcoder.jp にログイン済みのブラウザで開発者ツールを開き, Console タブに下記の JavaScript コードを投げることで簡単に取得できます:
document.getElementsByName("csrf_token")[0].value
Language ID
適当な問題の提出ページに遷移し, JavaScript Console に以下のコードを投げることで一覧が得られます:
document.getElementsByName("data.LanguageId")[0]
おわりに
昔はユーザー名とパスワード (と CSRF Token) からログインを完全自動で行えたのですが, 現在ではおそらく不可能です. 甚だ残念ですが, しょうがないですね.
ただ幸いなことに, AtCoder のセッション期限はそこそこ長い (半年ほどある) ようですので, 今回述べた方法でも十分実用に足るのではと思います.
あるいは, oj のように手元のブラウザを利用してスクレイピングするという手もある気がします.
(しょうもない内容なので別媒体にて投稿するつもりだったのですが, せっかくならということで traP のブログに投げることになりました. ここまでお付き合いいただきありがとうございます. 今後ともよろしくどうぞ. )