NiQin (blog: 泥芹) shared the aphorism --
I returned and saw under the sun, that the race is not to the swift, nor the battle to the strong, neither yet bread to the wise, nor yet riches to men of understanding, nor yet favour to men of skill; but time and chance happeneth to them all. -- 《圣经》

[Rust] Rust 中,对网址进行异步快照,并添加水印效果的实践

💥 内容涉及著作权,均归属作者本人。若非作者注明,默认欢迎转载:请注明出处,及相关链接。

Summary: Rust 生态中,关于通过 url 网址,对站点进行拍照,生成网页快照;以及在网页快照上生成时间戳,或者添加水印的实践。

Topics: rust 网页快照 网页截图 水印效果 图片水印

最近的项目需求中,需要实现两个功能——

  • 通过 url 网址,对站点进行拍照,生成网页快照;
  • 为了避免站点版权纠纷,以及历史留痕。需要在网页快照上生成时间戳,或者添加水印。

是故,笔者经过 crate 比较,实践后,整合了一个笔者认为最合适的解决方案。特此分享,以求抛砖引玉。

新建项目,从 None 开始

为了本次分享的详细和可操作性,我们抛离其它关联项目业务。从零开始一个全新的项目:

cargo new screenshot_watermark --bin
cd screenshot_watermark

我们将在此项目中进行全新的实践。

网页快照 crate 比较和选择

笔者以前曾了解到,Rust 中关于通过 url 网址,对网页截图快照的 crate 还不少,我们仅提及较为成熟的:有通过具体浏览器的 headless 模式的,如 rust-headless-chrome;有使用 WebDriver 模式的,则可以理论支持所有浏览器。

Rust crate 中,在 Chrome 浏览器方面,网页快照库只有 rust-headless-chrome 一个较为成熟;在 WebDriver 方面,笔者测试后,成熟的库有 2 个:fantoccini、thirtyfour。

它们都是异步库。fantoccini 最为成熟,久经考验;headless-chrome 次之,仅对 chrome 浏览器提供支持,秉持“如非必要,不增实体”思维的伙伴们,优先选择;thirtyfour 则最新,还对 tokio、async-std 两个 Rust 运行时(runtime)均提供了支持。

笔者比较后,选择了 fantoccini,但此文中,我们会对它们都做以实践。

首先,让我们编辑 Cargo.toml 文件,依赖项中添加此三个 crate,以及 tokio 运行时。

笔者采用 cargo-edit 工具包进行依赖项的添加:

cargo-edit 的使用,请参阅构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(1)- 起步及 crate 选择一文中的工具类 crate 安装部分。

cargo add fantoccini headless-chrome thirtyfour tokio

thirtyfour 默认的运行时选择是 tokio,如果你喜欢使用 async-std,则需要在依赖项中指定 features

此时,Cargo.toml 文件内容如下:

[package]
name = "screenshot_watermark"
version = "0.1.0"
authors = ["我是谁?"]
edition = "2018"

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

[dependencies]
fantoccini = "0.17.3"
headless_chrome = "0.9.0"
thirtyfour = "0.24.2"
tokio = "1.6.0"

WebDriver 下载和启动

对于采用 WebDriver 模式的 fantoccini 和 thirtyfour,需要下载各自浏览器的 WebDriver:firefox 的 geckodriver、chrome 的 chromedriver、edge 的 edgedriver,以及 safari 的 safaridriver 等。目前,WebDriver 模式的网页快照 crate,对于一些小众浏览器也提供了支持,如 opera,甚至 IE 等。不过,本文中笔者就不做提及了,开发模式是完全相同的。

各自浏览器的官网,均提供了其 WebDriver 的下载。下载完成后,我们启动时需要指定端口(如果你采用默认端口,请注意代码中更改)。以 firefox 和 chrome 为例:

geckodriver --port=4444
chromedriver --port=4445

网页快照截图

以下代码中,采用 tokio 运行时,async-std 运行时编码相同。

use std::fs;
use fantoccini::ClientBuilder;
use headless_chrome::{
    protocol::page::ScreenshotFormat, Browser, LaunchOptionsBuilder,
};
use thirtyfour::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 使用 fantoccini 进行网页快照截图 - 开始
    // 连接到 webdriver 实例,监听端口 4444
    // 4444 端口对应的是 geckodriver
    // 在 fantoccini 中如果要使用 chromedriver,请将 chromedriver 的启动端口改为 4444
    let mut client =
        ClientBuilder::native().connect("http://localhost:4444").await?;
    // 访问快照目标网址
    client.goto("https://blog.budshome.com").await?;
    // 设定快照截图尺寸
    client.set_window_size(1280, 1024).await?;

    // 网页快照
    let screenshot = client.screenshot().await?;
    fs::write("screenshot_f.jpg", &screenshot)?;

    // 关闭客户端浏览器窗口
    client.close().await?;
    // 使用 fantoccini 进行网页快照截图 - 结束

    // 使用 headless-chrome 进行网页快照截图 - 开始
    // 打开客户端浏览器
    let options =
        LaunchOptionsBuilder::default().build().expect("没有找到 Chrome 应用");
    let browser = Browser::new(options)?;
    // tab 初始化
    let tab = browser.wait_for_initial_tab()?;
    // 访问快照目标网址
    // 网页快照截图
    // JPEG 格式使用 75% 图象质量
    let jpg_data = tab
        .navigate_to("https://blog.budshome.com")?
        .wait_until_navigated()?
        .capture_screenshot(ScreenshotFormat::JPEG(Some(75)), None, true)?;
    fs::write("screenshot_h.jpg", &jpg_data)?;
    // 使用 headless-chrome 进行网页快照截图 - 结束

    // 使用 thirtyfour 进行网页快照截图 - 开始
    // firefox 浏览器
    let caps = DesiredCapabilities::firefox();
    let driver = WebDriver::new("http://localhost:4444", &caps).await?;
    // 访问快照目标网址
    driver.get("https://blog.budshome.com").await?;
    // 网页快照
    let png_data = driver.screenshot_as_png().await?;
    fs::write("screenshot_t_f.jpg", &png_data)?;

    // chrome 浏览器
    let caps = DesiredCapabilities::chrome();
    let driver = WebDriver::new("http://localhost:4445", &caps).await?;
    // 访问快照目标网址
    driver.get("https://blog.budshome.com").await?;
    // 网页快照
    let png_data = driver.screenshot_as_png().await?;
    fs::write("screenshot_t_c.jpg", &png_data)?;
    // 使用 thirtyfour 进行网页快照截图 - 结束

    Ok(())
}

运行程序,生成的截图如下所示(为了网页展示,上传服务器时缩小了尺寸):

blog 快照

笔者体验:fantoccini 最合适,headless-chrome 最为方便。

图片水印效果

Rust 的图像处理 crate 非常丰富,有 image、imagef、imager、andrew、png、jpg、gif、rgb,以及 image 库的子库 imageproc 和 image-png/gif/jpg 等等,琳琅满目。最为成熟、完善的还要数 image,我们如下示例即采用。

笔者实践测试了 andrew、imager、imagef 等,也大抵可用。

在上述代码的 Ok(())之前,添加如下代码,实现网页快照截图增加水印效果。

    // 打开网页快照截图
    // 此为底图,即要打上水印的图像
    let screenshot = image::open("screenshot.jpg").unwrap();
    // 转换为 rgb8 图像
    let mut screenshot_rgb = screenshot.to_rgb8();

    // 水印,采用图片,方便美术加工后
    // 当然也可以是文字等
    let watermark = image::open("rust-shijian.png").unwrap().to_rgb8();

    // 向底图添加水印效果
    image::imageops::overlay(&mut screenshot_rgb, &watermark, 900, 800);

    //  保存底图
    screenshot_rgb.save("screenshot.jpg").unwrap();

笔者的水印图片是微信公众号二维码,在图像右下角。

为了网页展示,上传服务器时缩小了尺寸

blog 快照 水印

结语

Okay,代码全部完成。可以发现,Rust 的图像处理生态不只很完善,使用也非常方便,不逊于 Python、Java 的生态。

以下为技术广告——

谢谢您的阅读!


Related Articles

  1. [Rust] RustHub.org:基于 Rust-Web 技术栈,及 image-rs、fluent-rs、rhai-script ……
  2. [WebAssembly] yew SSR 服务器端渲染
  3. [Rust] async-std 创建者对于最近“项目是否已死?”,移除对其支持等的答复
  4. [Rust] Rust 1.56.0 版本和 Rust 2021 版次发布,新特性一览,及项目的迁移、升级
  5. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 WebAssembly 博客应用的体验报告
  6. [Rust] Rust 官方周报 399 期(2021-07-14)
  7. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 web 前端(5)- 构建 HTTP 请求、与外部服务器通信的两种方法
  8. [Rust] Rust 官方周报 398 期(2021-07-07)
  9. [Rust] Rust 官方周报 397 期(2021-06-30)
  10. [Rust] Rust 官方周报 396 期(2021-06-23)
  11. [Rust] Rust 官方周报 395 期(2021-06-16)
  12. [Rust] Rust 1.53.0 明日发布,关键新特性一瞥
  13. [Rust] 使用 tide、handlebars、rhai、graphql 开发 Rust web 前端(3)- rhai 脚本、静态/资源文件、环境变量等
  14. [Rust] 使用 tide、handlebars、rhai、graphql 开发 Rust web 前端(2)- 获取并解析 GraphQL 数据
  15. [Rust] 使用 tide、handlebars、rhai、graphql 开发 Rust web 前端(1)- crate 选择及环境搭建
  16. [Rust] Rust 官方周报 394 期(2021-06-09)
  17. [Rust] Rust web 前端库/框架评测,以及和 js 前端库/框架的比较
  18. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 web 前端(4)- 获取 GraphQL 数据并解析
  19. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 web 前端(3)- 资源文件及小重构
  20. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 WebAssembly 标准的 web 前端(2)- 组件和路由
  21. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 WebAssembly 标准的 web 前端(1)- 起步及 crate 选择
  22. [Rust] Rust 官方周报 393 期(2021-06-02)
  23. [Rust] Rust 官方周报 392 期(2021-05-26)
  24. [Rust] Rust 中,对网址进行异步快照,并添加水印效果的实践
  25. [Rust] Rust 官方周报 391 期(2021-05-19)
  26. [Rust] Rust,风雨六载,砥砺奋进
  27. [Rust] 为什么我们应当将 Rust 用于嵌入式开发?
  28. [Rust] Rust 官方周报 390 期(2021-05-12)
  29. [Rust] Rust + Android 的集成开发设计
  30. [Rust] Rust 1.52.1 已正式发布,及其新特性详述
  31. [Rust] 让我们用 Rust 重写那些伟大的软件吧
  32. [Rust] Rust 1.52.0 已正式发布,及其新特性详述
  33. [Rust] Rust 官方周报 389 期(2021-05-05)
  34. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务(4) - 变更服务,以及小重构
  35. [Rust] Rust 1.52.0 稳定版预发布测试中,关键新特性一瞥
  36. [Rust] Rust 生态中,最不知名的贡献者和轶事
  37. [Rust] Rust 基金会迎来新的白金会员:Facebook
  38. [Rust] Rustup 1.24.1 已官宣发布,及其新特性详述
  39. [Rust] Rust 官方周报 388 期(2021-04-28)
  40. [Rust] Rust 官方周报 387 期(2021-04-21)
  41. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(4)- 变更服务,以及第二次重构
  42. [Rust] Rustup 1.24.0 已官宣发布,及其新特性详述
  43. [Rust] basedrop:Rust 生态中,适用于实时音频的垃圾收集器
  44. [Rust] Rust 编译器团队对成员 Aaron Hill 的祝贺
  45. [Rust] Jacob Hoffman-Andrews 加入 Rustdoc 团队
  46. [机器人] 为什么应将 Rust 引入机器人平台?以及机器人平台的 Rust 资源推荐
  47. [Rust] rust-lang.org、crates.io,以及 docs.rs 的管理,已由 Mozilla 转移到 Rust 基金会
  48. [Rust] Rust 官方周报 386 期(2021-04-14)
  49. [Rust] Rust 编译器(Compiler)团队 4 月份计划 - Rust Compiler April Steering Cycle
  50. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务(3) - 重构
  51. [Rust] 头脑风暴进行中:Async Rust 的未来熠熠生辉
  52. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务(2) - 查询服务
  53. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务 - 起步及 crate 选择
  54. [Rust] Rust 2021 版本特性预览,以及工作计划
  55. [Rust] Rust 用在生产环境的 42 家公司
  56. [Rust] 构建最精简的 Rust Docker 镜像
  57. [Rust] Rust 官方周报 385 期(2021-04-07)
  58. [Rust] 使用 Rust 做异步数据采集的实践
  59. [Rust] Android 支持 Rust 编程语言,以避免内存缺陷
  60. [Rust] Android 平台基础支持转向 Rust
  61. [Rust] Android 团队宣布 Android 开源项目(AOSP),已支持 Rust 语言来开发 Android 系统本身
  62. [Rust] RustyHermit——基于 Rust 实现的下一代容器 Unikernel
  63. [Rust] Rustic:完善的纯粹 Rust 技术栈实现的国际象棋引擎,多平台支持(甚至包括嵌入式设备树莓派 Raspberry Pi、Buster)
  64. [Rust] Rust 迭代器(Iterator trait )的要诀和技巧
  65. [Rust] 使用 Rust 极致提升 Python 性能:图表和绘图提升 24 倍,数据计算提升 10 倍
  66. [Rust] 【2021-04-03】Rust 核心团队人员变动
  67. [Rust] Rust web 框架现状【2021 年 1 季度】
  68. [Rust] Rust 官方周报 384 期(2021-03-31)
  69. [Rust] Rust 中的解析器组合因子(parser combinators)
  70. [生活] 毕马威(KPMG)调查报告:人工智能的实际采用,在新冠疫情(COVID-19)期间大幅提升
  71. [Python] HPy - 为 Python 扩展提供更优秀的 C API
  72. [Rust] 2021 年,学习 Rust 的网络资源推荐(2)
  73. [Rust] 2021 年,学习 Rust 的网络资源推荐
  74. [生活] 况属高风晚,山山黄叶飞——彭州葛仙山露营随笔
  75. [Rust] Rust 1.51.0 已正式发布,及其新特性详述
  76. [Rust] 为 Async Rust 构建共享的愿景文档—— Rust 社区的讲“故事”,可获奖
  77. [Rust] Rust 纪元第 382 周最佳 crate:ibig 的实践,以及和 num crate 的比较
  78. [Rust] Rust 1.51.0 稳定版本改进介绍
  79. [Rust] Rust 中将 markdown 渲染为 html
  80. [生活] 国民应用 App 的用户隐私数据窥探
  81. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(3)- 重构
  82. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(2)- 查询服务
  83. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(1)- 起步及 crate 选择
  84. [Rust] Rust 操控大疆可编程 tello 无人机

Topics

rust(84)

graphql(17)

rust-官方周报(17)

webassembly(16)

wasm(10)

tide(9)

async-graphql(9)

yew(9)

rust-web(8)

rust-官方博客(8)

this-week-in-rust(6)

mysql(5)

actix-web(5)

rbatis(5)

android(4)

mongodb(3)

json-web-token(3)

jwt(3)

cargo(3)

技术延伸(3)

rust-wasm(3)

trunk(3)

handlebars(3)

rhai(3)

async-std(3)

用户隐私(2)

学习资料(2)

python(2)

ai(2)

人工智能(2)

postgresql(2)

rust-compiler(2)

rust-基金会(2)

rust-foundation(2)

rustup(2)

rust-toolchain(2)

rust-工具链(2)

rust-游戏开发(2)

rust-区块链(2)

rust-2021(2)

graphql-client(2)

surf(2)

rust-game(2)

rusthub(2)

tello(1)

drone(1)

无人机(1)

隐私数据(1)

markdown(1)

html(1)

crate(1)

async(1)

异步(1)

旅游(1)

不忘生活(1)

葛仙山(1)

hpy(1)

python-扩展(1)

正则表达式(1)

解析器组合因子(1)

组合器(1)

regular-expression(1)

parser-combinator(1)

regex(1)

官方更新(1)

rust-工作招聘(1)

rust-技术资料(1)

rust-周最佳-crate(1)

rust-web-框架(1)

rust-web-framework(1)

rust-核心团队(1)

rust-core-team(1)

rust-language-team(1)

pyo3(1)

rust-python-集成(1)

python-性能改进(1)

迭代器(1)

iterator-trait(1)

国际象棋(1)

chess(1)

游戏引擎(1)

game-engine(1)

虚拟化(1)

unikernel(1)

rustyhermit(1)

linux(1)

virtualization(1)

sandboxing(1)

沙箱技术(1)

数据采集(1)

异步数据采集(1)

docker(1)

镜像(1)

生产环境(1)

rust-评价(1)

rust-2021-edition(1)

rust-2021-版本(1)

graphql-查询(1)

vision-doc(1)

愿景文档(1)

代码重构(1)

steering-cycle(1)

方向周期(1)

隐私声明(1)

机器人(1)

robotics(1)

rustdoc(1)

rust-编译器(1)

实时音频(1)

real-time-audio(1)

变更服务(1)

mutation(1)

查询服务(1)

query(1)

rust-贡献者(1)

rust-轶事(1)

rust-稳定版(1)

rust-预发布(1)

rust-测试(1)

安全编程(1)

可信计算(1)

安全代码(1)

secure-code(1)

rust-android-integrate(1)

rust-embedded(1)

rust-嵌入式(1)

rust-生产环境(1)

rust-production(1)

网页快照(1)

网页截图(1)

水印效果(1)

图片水印(1)

yew-router(1)

css(1)

web-前端(1)

wasm-bindgen(1)

区块链(1)

blockchain(1)

dotenv(1)

标识符(1)

rust-1.53.0(1)

rust-1.56.0(1)

rust-项目升级(1)

异步运行时(1)

ssr(1)

tokio(1)

warp(1)

reqwest(1)

graphql-rust(1)


Elsewhere

- Open Source
  1. github/zzy
  2. github/sansx
- Learning & Studying
  1. Rust 学习资料 - iRust.net