使用Rust获取猫咪表情包

3,838 阅读3分钟

一起用代码吸猫!本文正在参与【喵星人征文活动】

使用Rust获取可爱的猫咪表情包。

所需依赖

本文使用到的依赖有hyperhyper-tlsscrapertokio

  • hyper: HTTP底层实现库
  • hyper-tls: HTTPS实现库
  • scraper: 解析html
  • tokio: Rust编程语言的异步运行时,提供异步事件驱动平台,构建快速,可靠和轻量级网络应用

如果目标网站不是HTTPS类型的话,可以不用hyper-tls依赖。创建client的时候使用Client::new()即可

步骤

  1. 创建项目 在命令窗口中运行cargo new 项目名命令创建一个rust项目

  2. 加入依赖 在Cargo.toml文件中加入上面所说的依赖。Cargo.toml如下:

[package]
edition = "2021"
name = "cat"
version = "0.1.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
hyper = {version = "0.14", features = ["full"]}
hyper-tls = "0.5.0"
scraper = "0.12.0"
tokio = {version = "1", features = ["full"]}

  1. 分析目标网站 打开表情包网站搜索猫咪,按F12分析页面结构。使用定位按钮随便定位一张表情包元素,左键在出现的选项中负责该元素的选择器 image.png

将复制的选择器粘贴在文本中,如下: #post_container > li:nth-child(2) > div.thumbnail > a > img 结合页面元素分析可知,使用选择器div.thumbnail > a > img可以获得所有的表情包元素

  1. 构造并发起http/https请求, 获取页面数据
// 构建请求客户端
let https = HttpsConnector::new();
let client = Client::builder().build::<_, hyper::Body>(https);

let url = "http://www.*********.com/?s=%E7%8C%AB%E5%92%AA";
// 发起请求获取网页数据,
let response = client.get(url.parse()?).await?;
  1. 使用scraper解析响应数据
// 获取响应数据
let bytes = body::to_bytes(response.into_body()).await?;
// 解析HTML
let document = Html::parse_document(String::from_utf8(bytes.to_vec()).unwrap().as_ref());
  1. 使用CSS选择器找出需要的元素
let selector = Selector::parse("div.thumbnail > a > img").unwrap();

// 循环处理选择出来的img标签
for element in document.select(&selector) {
}
  1. 获取元素的srcalt属性
  • src:表情包的网络地址
  • alt:用于给表情包重命名
// 获取img标签的src属性
let src = element.value().attr("src").unwrap();
let alt = element.value().attr("alt").unwrap().to_string();
  1. 创建存储目录及构建表情包的名称
/**
 * 根据img标签的alt属性,拼接文件保存的路径
 *
 */
fn get_file_name(alt: &String) -> String {
    let mut tmp_dir = "E:\\img\\".to_string();

    // 如果该目标不存在则创建
    fs::create_dir_all(&tmp_dir).unwrap();

    let names: Vec<_> = alt.split("[").collect();
    let name = names.first().unwrap();
    let name = name.trim();
    let name = name.replace("?", "");
    tmp_dir += &name;
    tmp_dir += &".gif";

    return tmp_dir;
}
  1. 获取表情包并保存到本地 请求上面src属性获取的地址,并使用fs::write方法将表情包保存到本地
 // 请求表情包的网络地址,获取表情包文件
let response = client.get(src.parse()?).await?;
let body = hyper::body::to_bytes(response).await?;

// 将文件写入本地磁盘
fs::write(&tmp_dir, body.iter())?;

完整代码

use hyper::body;
use hyper::Client;
use hyper_tls::HttpsConnector;
use scraper::Html;
use scraper::Selector;
use std::fs;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 构建请求客户端
    let https = HttpsConnector::new();
    let client = Client::builder().build::<_, hyper::Body>(https);

    let url = "http://www.*********.com/?s=%E7%8C%AB%E5%92%AA";
    // 发起请求获取网页数据,
    let response = client.get(url.parse()?).await?;

    if res.status() != 200 {
        panic!("请求失败");
    }

    // 获取响应数据
    let bytes = body::to_bytes(res.into_body()).await?;
    // 解析HTML
    let document = Html::parse_document(String::from_utf8(bytes.to_vec()).unwrap().as_ref());
    let selector = Selector::parse("div.thumbnail > a > img").unwrap();

    // 循环处理选择出来的img标签
    for element in document.select(&selector) {
        println!("{:?}", element.value());

        // 获取img标签的src属性
        let src = element.value().attr("src").unwrap();
        let alt = element.value().attr("alt").unwrap().to_string();

        // 根据img标签的alt属性,拼接文件保存的路径
        let tmp_dir = get_file_name(&alt);
        println!("path: {}", tmp_dir);

        // 请求表情包的网络地址,获取表情包文件
        let response = client.get(src.parse()?).await?;
        let body = hyper::body::to_bytes(response).await?;

        // 将文件写入本地磁盘
        fs::write(&tmp_dir, body.iter())?;
    }

    Ok(())
}

/**
 * 根据img标签的alt属性,拼接文件保存的路径
 *
 */
fn get_file_name(alt: &String) -> String {
    let mut tmp_dir = "E:\\img\\".to_string();
    // 如果该目标不存在则创建
    fs::create_dir_all(&tmp_dir).unwrap();

    let names: Vec<_> = alt.split("[").collect();
    let name = names.first().unwrap();
    let name = name.trim();
    let name = name.replace("?", "");
    tmp_dir += &name;
    tmp_dir += &".gif";

    return tmp_dir;
}

运行效果

image.png