use clap::{Parser, Subcommand, ValueEnum};
use rust_scrapling::fetchers::client::Fetcher;
use rust_scrapling::fetchers::config::FetcherConfig;
#[derive(Clone, Copy, PartialEq, Eq, ValueEnum)]
enum OutputFormat {
Text,
Html,
Json,
}
#[derive(Parser)]
#[command(name = "rust-scrapling")]
#[command(about = "RUSTScrapling - A Rust web scraping framework", version)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Fetch {
url: String,
#[arg(short, long)]
selector: Option<String>,
#[arg(short, long, value_enum, default_value_t = OutputFormat::Text)]
format: OutputFormat,
#[arg(long)]
no_stealth: bool,
},
Extract {
url: String,
#[arg(short, long)]
selector: Option<String>,
},
}
#[tokio::main]
async fn main() {
env_logger::init();
let cli = Cli::parse();
match cli.command {
Commands::Fetch {
url,
selector,
format,
no_stealth,
} => {
let config = FetcherConfig::builder().stealth(!no_stealth).build();
let fetcher = match Fetcher::new(config) {
Ok(f) => f,
Err(e) => {
eprintln!("Failed to build HTTP client: {}", e);
std::process::exit(1);
}
};
match fetcher.get(&url).await {
Ok(response) => {
if let Some(css) = selector {
let sel = response.selector();
let results = sel.css(&css);
for item in &results {
match format {
OutputFormat::Html => println!("{}", item.outer_html()),
OutputFormat::Json => {
let obj = serde_json::json!({
"tag": item.tag(),
"text": item.text().as_str(),
"html": item.html_content().as_str(),
});
println!("{}", serde_json::to_string_pretty(&obj).unwrap());
}
OutputFormat::Text => println!("{}", item.text()),
}
}
eprintln!("Found {} elements", results.len());
} else {
match format {
OutputFormat::Html => println!("{}", response.text()),
OutputFormat::Text | OutputFormat::Json => {
let sel = response.selector();
println!(
"{}",
sel.get_all_text("\n", true, &["script", "style"], None)
);
}
}
}
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Commands::Extract { url, selector } => {
let fetcher = match Fetcher::new(FetcherConfig::default()) {
Ok(f) => f,
Err(e) => {
eprintln!("Failed to build HTTP client: {}", e);
std::process::exit(1);
}
};
match fetcher.get(&url).await {
Ok(response) => {
let sel = response.selector();
if let Some(css) = selector {
let results = sel.css(&css);
for item in &results {
println!("{}", item.text());
}
} else {
println!(
"{}",
sel.get_all_text("\n", true, &["script", "style"], None)
);
}
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
}
}