AtCoder用スクリプト作成ツールを自作してみた


最近競技プログラミングにハマっており、AtCoderのコンテストに参加したり過去問を解いたりしてアルゴリズムの勉強をしています。問題ごとにスクリプトを準備するのが結構めんどくさかったので、自動化してみました。atcoder-toolsを使えばファイル作成だけでなくテストや提出の自動化もできるのですが、私の環境では色々と不都合があったため、モジュールの勉強も兼ねて簡易的なツールを自作しました。現在はAtCoderBeginnerContest向けの実装なので他のコンテストの場合は修正が必要かもしれません。

概要

このツールでは以下の機能を実装しています。

  • 指定した問題のPythonスクリプトを作成
  • BeautifulSoupによるタイトルの自動取得
  • ブラウザで問題ページを開く

まずコンテスト名と問題名(A~F)を聞かれるので、入力します。

Contest(ex. abc123): abc180
Problems: all

allまたはa-fを入力すればすべての問題、カンマで区切れば任意の複数問題が指定できます。
するとコンテスト名のディレクトリが作成され、その配下に問題ごとのスクリプトが作成されます。
スクレイピングツールであるBeautifulSoupによって、問題ページのHTMLからタイトル部分を抽出し、スクリプトにタイトルをつけてくれます。

Files Created.   File: ABC180/A_box.py
Files Created.   File: ABC180/B_Variousdistances.py
Files Created.   File: ABC180/C_Creampuff.py
Files Created.   File: ABC180/D_TakahashiUnevolved.py
Files Created.   File: ABC180/E_TravelingSalesmanamongAerialCities.py
Files Created.   File: ABC180/F_Unbranched.py

スクリプトにはコメントでURLが追記され、webbrowserモジュールによって自動で問題ページが開きます。
URLが書いてあると後で問題を見直したいときに便利です。

# https://atcoder.jp/contests/abc180/tasks/abc180_a

ソースコード

import os
from typing import List
import requests
import webbrowser as wb
from bs4 import BeautifulSoup


def make_problem_files(_contest: str, _problems: List[str]):
    """
    :param _contest: コンテスト名(大小文字区別なし)
    :param _problems: 問題名(大小文字区別なし)のリスト
    :return: なし
    """
    for p in _problems:
        # URLを指定
        url = 'https://atcoder.jp/contests/{0}/tasks/{0}_{1}'.format(contest.lower(), p.lower())
        # ディレクトリ名を指定
        directory = _contest.upper()
        # HTMLからタイトルを取得
        r = requests.get(url)
        soup = BeautifulSoup(r.text, 'html.parser')
        title = soup.find('title').text.replace(' ', '').replace('-', '_')
        # スクリプト名を指定
        script = '{0}/{1}.py'.format(directory, title)

        if not os.path.exists(directory):
            # ディレクトリが存在しない場合新規作成
            os.makedirs(directory)
        if not os.path.exists(script):
            # ファイルが存在しない場合新規作成
            try:
                with open(script, 'w', encoding='utf-8') as f:
                    # 先頭にURLを追記
                    f.write('# ' + url + '\n')
                print('Files Created.   File: {0}'.format(script))
            except:
                print('ERROR: Files Not Created.   File: {0}'.format(script))
        # ブラウザで問題ページを開く(new=2:新しいタブ)
        wb.open(url, new=2, autoraise=True)


if __name__ == '__main__':
    # コンテスト名の入力
    contest = input('Contest(ex. abc123): ')
    # 問題を指定
    problems = input('Problems: ')
    prob_list = []
    if problems.lower() == 'a-f' or problems.lower() == 'all':
        prob_list = ['a', 'b', 'c', 'd', 'e', 'f']
    else:
        prob_list = problems.split(',')
    # ファイルの作成
    make_problem_files(contest, prob_list)