init project
This commit is contained in:
commit
95d8f7de3b
|
|
@ -0,0 +1 @@
|
|||
DATABASE_URL=mysql://root:Chenweijia113!@localhost/lottery
|
||||
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "sched_tasks_rs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.38"
|
||||
clokwerk = "0.4.0"
|
||||
log = "0.4.22"
|
||||
env_logger = "0.9"
|
||||
openssl = { version = "0.10.66", features = ["vendored"] }
|
||||
regex = "1.10.5"
|
||||
reqwest = { version = "0.12.5", features = ["gzip"] }
|
||||
scraper = "0.19.1"
|
||||
sea-orm = { version = "0.12", features = [ "sqlx-mysql", "runtime-tokio-rustls", "macros" ]}
|
||||
tokio = { version = "1.39.2", features = ["full"] }
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
FROM hub.airpig.cn/library/alpine:latest
|
||||
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
|
||||
&& apk update && apk add tzdata \
|
||||
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
&& echo "Asia/Shanghai" > /etc/timezone \
|
||||
&& apk del tzdata
|
||||
|
||||
ENV RUST_LOG=info
|
||||
|
||||
ENV RUST_ENV=prod
|
||||
|
||||
COPY ./target/x86_64-unknown-linux-musl/release/sched_tasks_rs /bin/sched_tasks_rs
|
||||
|
||||
|
||||
ENTRYPOINT ["/bin/sched_tasks_rs"]
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
use std::{thread, time::Duration};
|
||||
|
||||
use chrono::format;
|
||||
use clokwerk::{Scheduler, TimeUnits, Job};
|
||||
|
||||
use log::{info, error};
|
||||
|
||||
mod tasks;
|
||||
use tasks::*;
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let mut scheduler = Scheduler::new();
|
||||
let fmt = "%Y年%m月%d日 %H:%M:%S";
|
||||
let notify_url = "https://ding.airpig.cn/QfagvFa7u323xUS5yRbFR3";
|
||||
scheduler.every(1.day()).at("00:01:00").run(move|| {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let res = get_data_from_500_com("pls").await;
|
||||
let msg;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
msg = format!("{}: 排列3数据采集完毕", chrono::Local::now().format(fmt));
|
||||
info!("{}", msg);
|
||||
},
|
||||
Err(e) => {
|
||||
msg = format!("{}: 排列3数据采集失败: {}", chrono::Local::now().format(fmt), e);
|
||||
error!("{}", msg);
|
||||
}
|
||||
}
|
||||
let notify = reqwest::get(format!("{}/{}", notify_url, msg)).await.unwrap();
|
||||
if notify.status().is_success() {
|
||||
info!("{}: 排列3数据采集通知发送成功", chrono::Local::now().format(fmt));
|
||||
} else {
|
||||
error!("{}: 排列3数据采集通知发送失败", chrono::Local::now().format(fmt));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
scheduler.every(1.day()).at("00:01:15").run(move|| {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let res = get_data_from_500_com("plw").await;
|
||||
let msg;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
msg = format!("{}: 排列5数据采集完毕", chrono::Local::now().format(fmt));
|
||||
info!("{}", msg);
|
||||
},
|
||||
Err(e) => {
|
||||
msg = format!("{}: 排列5数据采集失败: {}", chrono::Local::now().format(fmt), e);
|
||||
error!("{}", msg);
|
||||
}
|
||||
}
|
||||
let notify = reqwest::get(format!("{}/{}", notify_url, msg)).await.unwrap();
|
||||
if notify.status().is_success() {
|
||||
info!("{}: 排列5数据采集通知发送成功", chrono::Local::now().format(fmt));
|
||||
} else {
|
||||
error!("{}: 排列5数据采集通知发送失败", chrono::Local::now().format(fmt));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
scheduler.every(1.day()).at("00:01:30").run(move|| {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let res = get_data_from_500_com("sd").await;
|
||||
let msg;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
msg = format!("{}: 福彩3D数据采集完毕", chrono::Local::now().format(fmt));
|
||||
info!("{}", msg);
|
||||
},
|
||||
Err(e) => {
|
||||
msg = format!("{}: 福彩3D数据采集失败: {}", chrono::Local::now().format(fmt), e);
|
||||
error!("{}", msg);
|
||||
}
|
||||
}
|
||||
let notify = reqwest::get(format!("{}/{}", notify_url, msg)).await.unwrap();
|
||||
if notify.status().is_success() {
|
||||
info!("{}: 福彩3D数据采集通知发送成功", chrono::Local::now().format(fmt));
|
||||
} else {
|
||||
error!("{}: 福彩3D数据采集通知发送失败", chrono::Local::now().format(fmt));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
info!("{}: 开始运行定时任务", chrono::Local::now().format("%Y年%m月%d日 %H:%M:%S"));
|
||||
loop {
|
||||
scheduler.run_pending();
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
|
||||
use std::{env, time::Duration};
|
||||
|
||||
use chrono::{Local, NaiveDate};
|
||||
use regex::Regex;
|
||||
use scraper::{Html, Selector};
|
||||
use sea_orm::{ActiveModelTrait, ActiveValue::Set, ConnectOptions, Database};
|
||||
|
||||
use crate::model::{sd, pls, plw};
|
||||
|
||||
pub async fn get_data_from_500_com(issue_type: &str) -> Result<(), String> {
|
||||
|
||||
// 数据库连接操作
|
||||
let db_url;
|
||||
if env::var("RUST_ENV").unwrap_or_else(|_|"dev".to_string()) == "dev" {
|
||||
db_url = "mysql://root:Chenweijia113!@localhost/lottery";
|
||||
} else {
|
||||
db_url = "mysql://root:Chenweijia113!@mysql/lottery";
|
||||
}
|
||||
let mut opt = ConnectOptions::new(db_url);
|
||||
opt.max_connections(100)
|
||||
.min_connections(5)
|
||||
.connect_timeout(Duration::from_secs(8))
|
||||
.acquire_timeout(Duration::from_secs(8))
|
||||
.idle_timeout(Duration::from_secs(8))
|
||||
.max_lifetime(Duration::from_secs(8))
|
||||
.sqlx_logging(true)
|
||||
.sqlx_logging_level(log::LevelFilter::Info)
|
||||
.set_schema_search_path("my_schema");
|
||||
let db = Database::connect(opt).await.expect("Failed to connect to database");
|
||||
|
||||
let url = format!("https://kaijiang.500.com/{}.shtml", issue_type);
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let res = client.get(&url).send().await.expect("Failed to send request");
|
||||
println!("url: {}, status: {}", url, res.status());
|
||||
|
||||
if res.status().is_success() {
|
||||
let document = res.text_with_charset("gb2312").await.unwrap();
|
||||
let html = Html::parse_document(&document);
|
||||
|
||||
let issue_selector = Selector::parse(r#"td.td_title01 > span.span_left > a > font.cfont2 > strong"#).expect("selector error");
|
||||
let issue_iter = html.select(&issue_selector).map(|x| {x.inner_html()});
|
||||
let issue: String = issue_iter.collect();
|
||||
|
||||
let date_selector = Selector::parse(r#"td.td_title01 > span.span_right"#).expect("selector error");
|
||||
let date_str = html.select(&date_selector).map(|x| {x.inner_html()}).collect::<String>();
|
||||
let re = Regex::new(r"开奖日期:(.*) 兑奖截止日期:(.*)").unwrap();
|
||||
let Some(draw_date) = re.captures(date_str.as_str()) else { return Err(String::from("日期解析错误")) };
|
||||
let draw_date = draw_date.get(1).unwrap().as_str();
|
||||
let date = NaiveDate::parse_from_str(draw_date, "%Y年%m月%d日").expect("Failed to parse date");
|
||||
|
||||
let ball_selector = Selector::parse(r#"li.ball_orange"#).expect("selector error");
|
||||
let ball_iter = html.select(&ball_selector).map(|x| {x.inner_html()});
|
||||
let ball: String = ball_iter.collect();
|
||||
|
||||
let numbers : Vec<i32> = ball.chars().map(|c| c.to_digit(10).unwrap() as i32).collect();
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let unique_numbers: Vec<_> = numbers.clone().into_iter().filter(|&x| seen.insert(x)).collect(); // 只有当元素被成功插入时(即它是唯一的),才包含它
|
||||
// let max = numbers.iter().max().unwrap_or(&0);
|
||||
// let min = numbers.iter().min().unwrap_or(&0);
|
||||
let sum = numbers.iter().sum::<i32>();
|
||||
let code_small = numbers.iter().filter(|&&x| x < 5).count() as i32;
|
||||
let code_big = numbers.iter().filter(|&&x| x >= 5).count() as i32;
|
||||
let code_single = numbers.iter().filter(|&&x| x % 2 == 1).count() as i32;
|
||||
let code_double = numbers.iter().filter(|&&x| x % 2 == 0).count() as i32;
|
||||
|
||||
if issue_type == "sd" {
|
||||
let group_type = if unique_numbers.len() == 3 { 6 } else if unique_numbers.len() == 2{ 3 } else {1};
|
||||
let new_model = sd::ActiveModel {
|
||||
draw_issue: Set(Some(issue)),
|
||||
draw_code: Set(Some(ball)),
|
||||
draw_date: Set(Some(date)),
|
||||
created_at: Set(Some(Local::now().naive_local())),
|
||||
sum_num: Set(Some(sum)),
|
||||
code_small: Set(Some(code_small)),
|
||||
code_big: Set(Some(code_big)),
|
||||
code_single: Set(Some(code_single)),
|
||||
code_double: Set(Some(code_double)),
|
||||
hundred: Set(Some(numbers[0])),
|
||||
ten: Set(Some(numbers[1])),
|
||||
one: Set(Some(numbers[2])),
|
||||
sum_hundred_one: Set(Some(numbers[0] + numbers[2])),
|
||||
sum_hundred_ten: Set(Some(numbers[0] + numbers[1])),
|
||||
sum_ten_one: Set(Some(numbers[1] + numbers[2])),
|
||||
group_type: Set(Some(group_type)),
|
||||
..Default::default()
|
||||
};
|
||||
new_model.insert(&db).await.expect("insert error");
|
||||
} else if issue_type == "pls" {
|
||||
let group_type = if unique_numbers.len() == 3 { 6 } else if unique_numbers.len() == 2{ 3 } else {1};
|
||||
let new_model = pls::ActiveModel {
|
||||
draw_issue: Set(Some(issue)),
|
||||
draw_code: Set(Some(ball)),
|
||||
draw_date: Set(Some(date)),
|
||||
created_at: Set(Some(Local::now().naive_local())),
|
||||
sum_num: Set(Some(sum)),
|
||||
code_small: Set(Some(code_small)),
|
||||
code_big: Set(Some(code_big)),
|
||||
code_single: Set(Some(code_single)),
|
||||
code_double: Set(Some(code_double)),
|
||||
hundred: Set(Some(numbers[0])),
|
||||
ten: Set(Some(numbers[1])),
|
||||
one: Set(Some(numbers[2])),
|
||||
sum_hundred_one: Set(Some(numbers[0] + numbers[2])),
|
||||
sum_hundred_ten: Set(Some(numbers[0] + numbers[1])),
|
||||
sum_ten_one: Set(Some(numbers[1] + numbers[2])),
|
||||
group_type: Set(Some(group_type)),
|
||||
..Default::default()
|
||||
};
|
||||
new_model.insert(&db).await.expect("insert error");
|
||||
} else if issue_type == "plw" {
|
||||
let new_model = plw::ActiveModel {
|
||||
draw_issue: Set(Some(issue)),
|
||||
draw_code: Set(Some(ball)),
|
||||
draw_date: Set(Some(date)),
|
||||
created_at: Set(Some(Local::now().naive_local())),
|
||||
sum_num: Set(Some(sum)),
|
||||
code_small: Set(Some(code_small)),
|
||||
code_big: Set(Some(code_big)),
|
||||
code_single: Set(Some(code_single)),
|
||||
code_double: Set(Some(code_double)),
|
||||
ten_thousand: Set(Some(numbers[0])),
|
||||
thousand: Set(Some(numbers[1])),
|
||||
hundred: Set(Some(numbers[2])),
|
||||
ten: Set(Some(numbers[3])),
|
||||
one: Set(Some(numbers[4])),
|
||||
sum_hundred_one: Set(Some(numbers[2] + numbers[4])),
|
||||
sum_hundred_ten: Set(Some(numbers[2] + numbers[3])),
|
||||
sum_ten_one: Set(Some(numbers[3] + numbers[4])),
|
||||
sum_first_3: Set(Some(numbers[0] + numbers[1] + numbers[2])),
|
||||
sum_next_3: Set(Some(numbers[2] + numbers[3] + numbers[4])),
|
||||
..Default::default()
|
||||
};
|
||||
new_model.insert(&db).await.expect("insert error");
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(String::from("获取数据失败"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
pub mod get_data;
|
||||
pub mod model;
|
||||
|
||||
pub use get_data::get_data_from_500_com;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15
|
||||
|
||||
pub mod prelude;
|
||||
|
||||
pub mod sd;
|
||||
pub mod pls;
|
||||
pub mod plw;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "pls")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub draw_issue: Option<String>,
|
||||
pub draw_date: Option<Date>,
|
||||
pub draw_code: Option<String>,
|
||||
pub hundred: Option<i32>,
|
||||
pub ten: Option<i32>,
|
||||
pub one: Option<i32>,
|
||||
pub group_type: Option<i32>,
|
||||
pub group_3_span: Option<i32>,
|
||||
pub code_big: Option<i32>,
|
||||
pub code_small: Option<i32>,
|
||||
pub code_single: Option<i32>,
|
||||
pub code_double: Option<i32>,
|
||||
pub sum_num: Option<i32>,
|
||||
pub sum_num_span: Option<i32>,
|
||||
pub sum_ten_one: Option<i32>,
|
||||
pub sum_hundred_ten: Option<i32>,
|
||||
pub sum_hundred_one: Option<i32>,
|
||||
pub sum_single_double: Option<i32>,
|
||||
pub sum_big_small: Option<i32>,
|
||||
pub created_at: Option<DateTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "plw")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub draw_issue: Option<String>,
|
||||
pub draw_date: Option<Date>,
|
||||
pub draw_code: Option<String>,
|
||||
pub ten_thousand: Option<i32>,
|
||||
pub thousand: Option<i32>,
|
||||
pub hundred: Option<i32>,
|
||||
pub ten: Option<i32>,
|
||||
pub one: Option<i32>,
|
||||
pub code_big: Option<i32>,
|
||||
pub code_small: Option<i32>,
|
||||
pub code_single: Option<i32>,
|
||||
pub code_double: Option<i32>,
|
||||
pub sum_num: Option<i32>,
|
||||
pub sum_ten_one: Option<i32>,
|
||||
pub sum_hundred_ten: Option<i32>,
|
||||
pub sum_hundred_one: Option<i32>,
|
||||
pub sum_first_3: Option<i32>,
|
||||
pub sum_next_3: Option<i32>,
|
||||
pub created_at: Option<DateTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15
|
||||
#[allow(unused_imports)]
|
||||
|
||||
pub use super::sd::Entity as Sd;
|
||||
pub use super::pls::Entity as Pls;
|
||||
pub use super::plw::Entity as Plw;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "sd")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub draw_issue: Option<String>,
|
||||
pub draw_date: Option<Date>,
|
||||
pub draw_code: Option<String>,
|
||||
pub hundred: Option<i32>,
|
||||
pub ten: Option<i32>,
|
||||
pub one: Option<i32>,
|
||||
pub group_type: Option<i32>,
|
||||
pub group_3_span: Option<i32>,
|
||||
pub code_big: Option<i32>,
|
||||
pub code_small: Option<i32>,
|
||||
pub code_single: Option<i32>,
|
||||
pub code_double: Option<i32>,
|
||||
pub sum_num: Option<i32>,
|
||||
pub sum_num_span: Option<i32>,
|
||||
pub sum_ten_one: Option<i32>,
|
||||
pub sum_hundred_ten: Option<i32>,
|
||||
pub sum_hundred_one: Option<i32>,
|
||||
pub sum_single_double: Option<i32>,
|
||||
pub sum_big_small: Option<i32>,
|
||||
pub created_at: Option<DateTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
Loading…
Reference in New Issue