Rust
安装Rust工具链 安装 Rust
sh
git clone https://github.com/mcitem/lnuElytra
cd examples
# 修改 examples/src/bin/best中的教学班、账号密码
cargo run --bin best异步API(推荐使用)
安装
sh
cargo add tokio -F macros,rt-multi-thread
cargo add lnu-elytra使用
rs
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = lnu_elytra::Client::new();
client.login("账号", "密码").await?;
client.init().await?;
// 教学班示例:(2025-2026-2)-77101504-02
// 使用精确的教学班查询能能减少教务系统返回的数据量,有利于加快抢课。
let course = client.fetch_courses("教学班").await?;
// 只有当使用精确教学班查询时,才适合直接调用 try_select_o
course.try_select_0(&client).await?;
Ok(())
}最佳实践
在抢课开始前提前10分钟就登入系统,并等到抢课时间开始时在手动控制脚本继续运行(也可以通过断点调试、Cookie登录实现
示例:通过stdin控制脚本继续
rs
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = lnu_elytra::Client::new();
client.login("账号", "密码").await?;
println!("登录成功,按回车键继续...");
std::io::stdin().read_line(&mut String::new())?;
println!("正在初始化...");
client.init().await?;
let course = client.fetch_courses("教学班").await?;
course.try_select_0(&client).await?;
Ok(())
}完整示例(可直接使用)
rs
use std::sync::Arc;
use lnu_elytra::{Client, Error, SelectCourseResponse};
use tracing_subscriber::{filter::LevelFilter, fmt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
fmt().with_max_level(LevelFilter::INFO).init();
// 此示例非常适合直接用于单人抢课使用,含有基本的重试,多任务并行功能
let mut client = Client::new();
// 在 广州商学院 抢课(更换教务系统地址
// let mut client = Client::new_with_base("http://jwxt.gcc.edu.cn".try_into()?);
client.login("账号", "密码").await?;
println!("登录成功,按回车键继续...");
// 如果需要手动控制,取消注释此行
// std::io::stdin().read_line(&mut String::new())?;
println!("正在初始化...");
// 登录成功后,永远不要引发任何的panic或直接上抛Result Err,否则会导致所有直接退出,无法继续抢课
loop {
if let Ok(()) = client.init().await {
println!("初始化成功,正在准备选课...");
break;
};
println!("初始化失败,正在重试...");
}
// 教学班列表
// 并行运行多个选课任务,但可能会随机选到其中一个
let tgs = vec!["教学班1", "教学班2", "教学班3"];
let mut hds = Vec::new();
// 使用std::sync::Arc来共享Client实例,以便在多个任务中使用
let c = Arc::new(client);
for i in tgs {
hds.push(tokio::spawn(fetch(i, c.clone())));
}
for i in hds {
if let Ok(status) = i.await {
println!("选课结果: {:?}", status);
}
}
println!("进程已结束,按回车键退出...");
std::io::stdin().read_line(&mut String::new())?;
Ok(())
}
async fn fetch(i: &str, client: Arc<Client>) -> Result<SelectCourseResponse, Error> {
println!("正在选课 {}...", i);
loop {
if let Ok(course) = client.fetch_courses(i).await
&& let Ok(status) = course.try_select_0(&client).await
{
println!("选课结果 {}: {:?}", i, status);
if let Some(msg) = status.msg()
&& (msg.contains("未开放") || msg.contains("频率过高"))
{
continue;
}
if status.is_success() {
println!("选课成功 {}!", i);
}
return Ok(status);
};
}
}阻塞API
不要在tokio的异步环境中使用阻塞客户端,这会引起panic
Cannot start a runtime from within a runtime. This happens because a function (like block_on) attempted to block the current thread while the thread is being used to drive asynchronous tasks.
安装
需要启用 blocking Feature
sh
cargo add lnu-elytra -F blocking使用
rs
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = lnu_elytra::blocking::Client::new();
client.login("账号", "密码")?;
client.init()?;
let course = client.fetch_course("教学班")?;
course.try_select_0_blocking(&client)?;
Ok(())
}