使用Rust获取猫咪表情包

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

使用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如下:
1
2
3
4
5
6
7
8
9
10
11
12
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请求, 获取页面数据
1
2
3
4
5
6
7
rs复制代码// 构建请求客户端
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解析响应数据
1
2
3
4
rs复制代码// 获取响应数据
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选择器找出需要的元素
1
2
3
4
5
rs复制代码let selector = Selector::parse("div.thumbnail > a > img").unwrap();

// 循环处理选择出来的img标签
for element in document.select(&selector) {
}
  1. 获取元素的srcalt属性
  • src:表情包的网络地址
  • alt:用于给表情包重命名
1
2
3
rs复制代码// 获取img标签的src属性
let src = element.value().attr("src").unwrap();
let alt = element.value().attr("alt").unwrap().to_string();
  1. 创建存储目录及构建表情包的名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
rs复制代码/**
* 根据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方法将表情包保存到本地
1
2
3
4
5
6
rs复制代码 // 请求表情包的网络地址,获取表情包文件
let response = client.get(src.parse()?).await?;
let body = hyper::body::to_bytes(response).await?;

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

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
rs复制代码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

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%