AtCoderの予定と結果の取得

これは[AtCoder関連サービス Advent Calendar 2018](https://adventar.org/calendars/2932)の7日目の記事です。 
[competitiveprogramming.info](https://competitiveprogramming.info/) というサイトを趣味でやっています。(経緯: [competitiveprogramming.infoについて - Competitive Programming Advent Calendar 2015](https://topcoder.g.hatena.ne.jp/firewood/20151208/1449594379))
競技プログラミング(competitive programming)の色々なトピックを集めようと思って今のドメイン名にしました。
今年からAtCoderの予定と結果を取り込むようになったのでそれについて書きます。

## 競技プログラミングカレンダー

competitiveprogramming.infoには[競技プログラミングカレンダー](https://competitiveprogramming.info/calendar)があります。もともと[Topcoder部のカレンダー](https://topcoder.g.hatena.ne.jp/)というのがあり、見やすかったので使っていましたが、これは有志が手作業で更新するという温もりのあるサービスでした。
更新されないことが増えてきたこともあり、各サービスごとのGoogle Calendarから取り込んで一つのカレンダーにまとめてみました。主に短時間系のものを、[topcoder]などのプリフィックスをつけて登録しています。特長としては、コンテストの時間が変更されたとき、同じタイトルのものを見つけて追従するようにしています。(タイトルが変わった場合は追従しないので、手作業で消したり、重複排除の条件を足したりしています)
Google Calendarを作っておいて、そのカレンダーの予定の24時間前、1時間前、10分前には[競技プログラミングSlack](https://competitiveprogramming.info/slack)のcalendarチャンネルに通知するようにしています。(Slackアプリで通知を受けることもできます。)

## AtCoderのコンテストの予定

AtCoderには[公式のGoogle Calendar](http://atcoder.jp/calendar)があって、去年まではここからカレンダー情報を取得していたのですが、たまに更新されないことがあったのと、時間の長さがゼロで登録されていたりしました。
どうやら[コンテスト一覧のページ](http://atcoder.jp/contests)がマスターデータのようなので、今年からはこちらをスクレイピングすることにしました。
まず https://atcoder.jp/contests/?lang=ja と https://atcoder.jp/contests/?lang=en を取得し、予定されたコンテストの部分をパースしてタイトル、リンク、開始時刻、長さを取得します。
次に定期コンテストのタイトルを短くします。(AtCoder Regular Contest → ARC)
もし同日にARCやABCがあるときは / で結合します。
そしてタイトルの先頭に[AtCoder]をつけます。lang=jaのほうだけにあるコンテストには、末尾に(Japanese)をつけてカレンダーに登録します。

## AtCoderのコンテストの結果

AtCoderには公式APIはないのですが、実は一部のURLの末尾に/jsonをつけるとJSON形式で返す、というのを今年知ったので、AtCoderの結果を取り込むことにしました。[3日目のNoiminさんの記事](http://noimin.hatenablog.com/entry/2018/12/03/000000)によると隠し機能とのこと。他のユーザーに影響しないよう、APIの間隔は10秒以上になるようにして使っています。
[AtCoder Contests](https://competitiveprogramming.info/atcoder/contests)というページを用意して、コンテストの種類ごとでも一覧できるようにしました。
コンテストの一覧は[コンテスト一覧のページ](http://atcoder.jp/contests)をスクレイピングして取得しておきます。また、コンテストの種類(先頭の英字)に応じてタグづけしておきます。
そしてコンテストの standings/json を取得し、データベースに保存します。ただこのJSONにはperformanceが含まれていません。~~performanceはコンテスト終了後しばらくしてrating変動が起きてから、ユーザーのページ users/USER_ID/history/json から取得することができます。
このため、コンテストの結果は、コンテストが終了してから半日後くらいに取得するようにしました。コンテストの結果はユーザー毎に保存していくわけですが、ratedのコンテストに参加したユーザーに対して、performanceの更新が必要であるというフラグをセットするようにしました。このフラグが立っているユーザーに対して、ユーザーのページをクロールしていきます。これは全参加者ぶん行う必要があるので、1分に2回だけ行うようにしています。1日に2880人分更新できるので、実用上はこれでよいかなという感じです。~~
(2019/11更新) コンテスト終了後は、順位表のタブに [レーティング変動](https://atcoder.jp/contests/abc144/results) というリンクが追加されます。このJSON APIでperformanceとratingの変動が取得できるので、そちらに変更しました。(AtCoder Problemsのソースコードを読んでいて気づきました。kenkooooさんありがとう!)
ARC/ABC/AGCについては以上の処理を自動的にやっています。そのほかのコンテストは、定期的に行われるもの(天下一プログラマーコンテストなど)をピックアップして手作業で登録したりしています。
Topcoderと同じIDでAtCoderに登録している人は、Topcoderのプロフィールページにリンクするようにしました。(competitiveprogramming.infoの)Topcoderのプロフィールページに両方のレーティンググラフが表示されます。

## その他の機能

Twitterでログインすることができ、AtCoderとCodeforcesとTopcoderのIDを登録しておくと、トップページにratingのグラフなどが表示されます。(Codeforcesのデータは保持しておらず、CodeforcesのAPIを利用しています)

![compinfo.png](https://qiita-image-store.s3.amazonaws.com/0/20902/06a544e5-25c8-3378-c4c0-1c54d691805c.png)

## 差分

competitiveprogramming.infoは3年運用していて、現況は以下のような感じです。

- お名前.comのVPS → ConoHa VPS
    - お名前.comのVPSが全く更新されず、OSアップデートしたかったので
- CentOS 6.7 → Ubuntu 18.04.1 LTS
- nginx + Unicorn → nginx 1.14 + Puma
    - HTTP/2サポートしました
- Ruby 2.1.6 → Ruby 2.5.3
    - ぼっち演算子(&.)が使えるようになりました
- Rails 4.0 → Rails 5.2

## おわりに

今後とも[Twitter](https://twitter.com/hotpepsi)や[Slack](https://competitiveprogramming.info/slack)などでフィードバックなどいただければ幸いです。
明日は [miozune さん](https://twitter.com/miozune)です。