はじめに
RustでAtCoderにログイン認証を通すコードを作成したので備忘録として残しておきます。
処理の流れ
- https://atcoder.jp/login にアクセスしてCookieとcsrf_tokenを取得
- csrf_token、ユーザ名、パスワードをクエリパラメータに設定してログイン
コード
reqwestのfeaturesに"blocking"
、"cookies"
を追加する必要があります。
use scraper::Selector;
use reqwest::{blocking::Client, cookie::Jar};
use std::{io, sync::Arc};
fn get_user_id() -> String {
let mut input = String::new();
print!("ユーザ名を入力してください: ");
io::stdout().flush().unwrap();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
input.trim().to_string()
}
fn login() -> Result<(), reqwest::Error> {
let user = get_user_id();
let pass = rpassword::prompt_password("パスワードを入力してください: ")
.expect("Failed to read password");
// Cookieストアを作成
let cookie_store = Arc::new(Jar::default());
// Cookieストアを持つClientを作成
let client = Client::builder()
.cookie_store(true) // クライアントでCookieストアを有効にする
.cookie_provider(Arc::clone(&cookie_store)) // カスタムCookieストアを設定
.build()?;
// csrf_tokenを取得
let selector = Selector::parse("input[name=\"csrf_token\"]").unwrap();
let body = client.get("https://atcoder.jp/login").send()?.text()?;
let document = scraper::Html::parse_document(&body);
let csrf_token = document
.select(&selector)
.next()
.unwrap()
.value()
.attr("value")
.unwrap()
.to_string();
let params = [
("username", &user),
("password", &pass),
("csrf_token", &csrf_token),
];
let response = client
.post("https://atcoder.jp/login")
.query(¶ms)
.send()?;
response.error_for_status()?;
println!("ログイン成功");
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
login()?;
Ok(())
}
まとめ
cookieの保存のあたりで苦戦しましたがRustフォーラムの記事に助けられました。