首页 > 其他分享 >Rust项目大制作,从简单到进阶,助力大家成为Rust顶流开发工程师!

Rust项目大制作,从简单到进阶,助力大家成为Rust顶流开发工程师!

时间:2024-11-22 19:17:35浏览次数:3  
标签:顶流 use 进阶 await serde let new message Rust

在给大家介绍这个关于Rust的项目前,大家可以先看看我之前写的这两篇博客,巩固一下Rust的基础知识

博客1:为什么不来学一下Rust!!!

https://blog.csdn.net/speaking_me/article/details/143450484

博客2:Rust的应用开发场景,抓住Rust的红利开吃!!!

https://blog.csdn.net/speaking_me/article/details/143621520

同时也回答一下某些小伙伴的问题,说我为什么老是公开博客,不设置需粉丝观看或者VIP,哈哈哈,我之前是有这样的想法,但是经历了秋招面试,我慢慢的发现我的竞争者根本就不是大家而是自己,看自己能否在时代的洪流中坚持自我,找寻自我,是啊,我拿着那些虚拟财产有什么用呢,帮助大家,帮助自己进步才是我原本的出发点,我在这里看到了很多没见过的技术,找到了很多问题的解决方法,结识了各种领域的大佬,在社区畅聊,我觉得这就够了,不要在乎那些,坚持自我,做出一些贡献就足够。

这里送给自己也送给大家一句话,这也是我最喜欢的一句:你说遇事不决可问春风,春风不语既随本心。可我若本心坚定,怎会遇事不决。春风也有春风愁,不劳春风为我忧。(意思就不给大家解释了哈,懂的自然明白如何做)

那我们先从简单的项目做起

下面是一个简单的 Rust 项目示例,包括一个命令行应用程序,该应用程序可以读取用户的输入并打印出来。我们将逐步介绍如何创建和运行这个项目。

1. 安装 Rust

首先,你需要安装 Rust。最简单的方法是使用 rustup,这是一个官方的 Rust 工具链管理器。

在 Linux 和 macOS 上安装
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
在 Windows 上安装

你可以从 Rust 官方网站 下载安装程序并按照提示进行安装。

为了方便大家我把链接也搬过来了,喂大家嘴里:https://blog.csdn.net/xinyingzai/article/details/135459640

安装完成后,打开终端并运行以下命令以确保 Rust 已正确安装:

rustc --version

2. 创建一个新的 Rust 项目

使用 Cargo(Rust 的包管理器和构建系统)创建一个新的项目。

cargo new hello_world
cd hello_world

3. 编写代码

编辑 src/main.rs 文件,添加以下代码:

use std::io;

fn main() {
    println!("Hello, world!");

    // 读取用户输入
    println!("Please enter your name:");
    let mut name = String::new();
    io::stdin().read_line(&mut name).expect("Failed to read line");

    // 去除输入末尾的换行符
    name = name.trim().to_string();

    // 打印用户输入
    println!("Hello, {}!", name);
}

4. 运行项目

在终端中运行以下命令来编译和运行项目:

cargo run

你应该会看到类似以下的输出:

Hello, world!
Please enter your name:
John Doe
Hello, John Doe!

5. 项目结构

Rust 项目的基本结构如下:

hello_world/
├── Cargo.toml
└── src/
    └── main.rs
  • Cargo.toml: 项目的配置文件,包含依赖项、元数据等。
  • src/main.rs: 项目的主文件,包含 main 函数。

6. 添加依赖项

如果你需要添加外部库,可以在 Cargo.toml 文件中指定依赖项。例如,如果你想使用 serde 库进行序列化和反序列化,可以编辑 Cargo.toml 文件:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

然后在 src/main.rs 中使用这些库:

use serde::{Deserialize, Serialize};
use std::io;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    println!("Hello, world!");

    // 读取用户输入
    println!("Please enter your name:");
    let mut name = String::new();
    io::stdin().read_line(&mut name).expect("Failed to read line");
    let name = name.trim().to_string();

    println!("Please enter your age:");
    let mut age = String::new();
    io::stdin().read_line(&mut age).expect("Failed to read line");
    let age: u8 = age.trim().parse().expect("Please type a number!");

    // 创建 Person 结构体实例
    let person = Person { name, age };

    // 序列化为 JSON
    let json = serde_json::to_string(&person).unwrap();
    println!("Serialized person: {}", json);

    // 反序列化为 Person
    let deserialized_person: Person = serde_json::from_str(&json).unwrap();
    println!("Deserialized person: {:?}", deserialized_person);
}

7. 构建和运行项目

再次运行 cargo run 命令来构建和运行项目:

cargo run

你应该会看到类似以下的输出:

Hello, world!
Please enter your name:
John Doe
Please enter your age:
30
Serialized person: {"name":"John Doe","age":30}
Deserialized person: Person { name: "John Doe", age: 30 }

总结

通过以上步骤,你已经创建了一个简单的 Rust 项目,并学会了如何读取用户输入、使用外部库以及序列化和反序列化数据。Rust 的生态系统非常丰富,你可以继续探索更多的特性和库,以满足你的开发需求。这就需要自己加油了哈。

那我们就进入进阶篇了哈

下面是一个较为复杂和深入的 Rust 项目示例,该项目将结合多个领域的知识,包括异步编程、网络通信、数据库操作、并发处理和图形界面。

我们将创建一个简单的聊天应用程序,支持客户端和服务器之间的实时通信,并使用 SQLite 数据库存储消息历史。

项目概述

  • 服务器端:使用 Tokio 进行异步网络编程,处理客户端连接和消息转发。
  • 客户端端:使用 GTK-rs 创建图形用户界面,使用 WebSocket 与服务器通信。
  • 数据库:使用 SQLite 存储消息历史。

项目结构

chat-app/
├── server/
│   ├── Cargo.toml
│   └── src/
│       └── main.rs
├── client/
│   ├── Cargo.toml
│   └── src/
│       ├── main.rs
│       └── gui.rs
├── Cargo.toml
└── README.md

服务器端

1. 初始化项目
mkdir chat-app
cd chat-app
cargo new server --bin
cd server
2. 添加依赖

编辑 Cargo.toml 文件,添加必要的依赖:

[dependencies]
tokio = { version = "1", features = ["full"] }
futures = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sqlx = { version = "0.5", features = ["runtime-tokio-native-tls", "sqlite"] }
3. 编写服务器代码

编辑 src/main.rs 文件:

use tokio::net::{TcpListener, TcpStream};
use tokio::sync::broadcast;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use futures::stream::StreamExt;
use serde::{Serialize, Deserialize};
use sqlx::sqlite::SqlitePool;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::SystemTime;

#[derive(Serialize, Deserialize, Debug)]
struct Message {
    username: String,
    content: String,
    timestamp: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    let pool = SqlitePool::connect("sqlite:chat.db").await?;
    sqlx::migrate!().run(&pool).await?;

    let (tx, _rx) = broadcast::channel::<Message>(100);
    let clients = Arc::new(tokio::sync::Mutex::new(HashMap::new()));

    loop {
        let (socket, addr) = listener.accept().await?;
        let tx = tx.clone();
        let clients = Arc::clone(&clients);
        let pool = pool.clone();

        tokio::spawn(async move {
            handle_client(socket, addr, tx, clients, pool).await;
        });
    }
}

async fn handle_client(
    mut socket: TcpStream,
    addr: std::net::SocketAddr,
    tx: broadcast::Sender<Message>,
    clients: Arc<tokio::sync::Mutex<HashMap<std::net::SocketAddr, broadcast::Receiver<Message>>>>,
    pool: SqlitePool,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut buf = [0; 1024];
    let mut rx = tx.subscribe();

    loop {
        let mut readable = false;
        let mut writable = false;

        {
            let clients = clients.lock().await;
            if let Some(rx) = clients.get(&addr) {
                readable = rx.recv().await.is_ok();
            }
        }

        if readable {
            let message = rx.recv().await?;
            socket.write_all(&serde_json::to_vec(&message)?).await?;
        }

        if socket.readable().await? {
            let n = socket.read(&mut buf).await?;
            if n == 0 {
                break;
            }

            let message: Message = serde_json::from_slice(&buf[..n])?;
            let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
            let message = Message {
                username: message.username,
                content: message.content,
                timestamp: now,
            };

            sqlx::query!(
                "INSERT INTO messages (username, content, timestamp) VALUES (?, ?, ?)",
                message.username,
                message.content,
                message.timestamp
            )
            .execute(&pool)
            .await?;

            tx.send(message)?;
            clients.lock().await.insert(addr, rx.resubscribe());
            writable = true;
        }

        if writable {
            socket.writable().await?;
            socket.flush().await?;
        }
    }

    Ok(())
}

客户端端

1. 初始化项目
cd ..
cargo new client --bin
cd client
2. 添加依赖

编辑 Cargo.toml 文件,添加必要的依赖:

[dependencies]
gtk = "0.11"
glib = "0.11"
gio = "0.11"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.13"
3. 编写客户端代码

编辑 src/main.rs 文件:

use gtk::prelude::*;
use gio::prelude::*;
use tokio::runtime::Runtime;
use tokio_tungstenite::tungstenite::protocol::Message as WsMessage;
use serde::{Serialize, Deserialize};
use std::sync::mpsc;

#[derive(Serialize, Deserialize, Debug)]
struct ChatMessage {
    username: String,
    content: String,
    timestamp: u64,
}

fn main() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }

    let application = gtk::Application::new(
        Some("com.example.chat-client"),
        Default::default(),
    );

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run();
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);
    window.set_title("Chat Client");
    window.set_default_size(400, 600);

    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 5);
    let scrolled_window = gtk::ScrolledWindow::new(None, None);
    let text_view = gtk::TextView::new();
    let entry = gtk::Entry::new();
    let send_button = gtk::Button::with_label("Send");

    scrolled_window.add(&text_view);
    vbox.pack_start(&scrolled_window, true, true, 0);
    vbox.pack_start(&entry, false, false, 0);
    vbox.pack_start(&send_button, false, false, 0);

    window.add(&vbox);
    window.show_all();

    let (tx, rx) = mpsc::channel();
    let text_buffer = text_view.buffer().clone();

    send_button.connect_clicked(clone!(@strong entry, @strong tx => move |_| {
        let message = entry.text().to_string();
        entry.set_text("");
        tx.send(message).unwrap();
    }));

    let runtime = Runtime::new().unwrap();
    runtime.spawn(async move {
        let ws_stream = tokio_tungstenite::connect_async("ws://127.0.0.1:8080").await.unwrap().0;
        let (mut ws_write, mut ws_read) = ws_stream.split();

        while let Ok(message) = rx.recv() {
            let message = ChatMessage {
                username: "User".to_string(),
                content: message,
                timestamp: std::time::SystemTime::now()
                    .duration_since(std::time::SystemTime::UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            };
            let json_message = serde_json::to_string(&message).unwrap();
            ws_write.send(WsMessage::Text(json_message)).await.unwrap();
        }

        while let Some(message) = ws_read.next().await {
            if let Ok(WsMessage::Text(text)) = message {
                let message: ChatMessage = serde_json::from_str(&text).unwrap();
                let message_text = format!("{}: {}\n", message.username, message.content);
                glib::idle_add_once(move || {
                    text_buffer.insert_at_cursor(&message_text);
                });
            }
        }
    });
}

数据库迁移

在服务器端目录下创建一个 migrations 文件夹,并在其中创建一个迁移文件 V1__create_messages_table.sql

CREATE TABLE IF NOT EXISTS messages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT NOT NULL,
    content TEXT NOT NULL,
    timestamp INTEGER NOT NULL
);

运行项目

  1. 启动服务器

    cd chat-app/server
    cargo run
  2. 启动客户端

    cd chat-app/client
    cargo run

项目总结

通过以上步骤,你已经创建了一个完整的聊天应用程序,其中包括:

  • 服务器端:使用 Tokio 进行异步网络编程,处理客户端连接和消息转发。
  • 客户端端:使用 GTK-rs 创建图形用户界面,使用 WebSocket 与服务器通信。
  • 数据库:使用 SQLite 存储消息历史。

这个项目结合了异步编程、网络通信、图形界面和数据库操作等多个领域的知识,展示了 Rust 在构建复杂应用程序方面的强大能力。

对进阶篇详细讲解(对前面这个不是很理解的,可以看这个,这个代码有注释)当然,我重新写了一遍,方便大家看

让我们一步一步地详细解释这个复杂的 Rust 项目,确保每一个部分都清晰易懂。

项目概述

我们将会创建一个简单的聊天应用程序,分为服务器端和客户端两部分。服务器端负责处理客户端的连接和消息转发,客户端则提供图形用户界面,允许用户发送和接收消息。此外,我们还会使用 SQLite 数据库来存储消息历史。

项目结构

chat-app/
├── server/
│   ├── Cargo.toml
│   └── src/
│       └── main.rs
├── client/
│   ├── Cargo.toml
│   └── src/
│       ├── main.rs
│       └── gui.rs
├── Cargo.toml
└── README.md

服务器端

1. 初始化项目

首先,我们需要初始化服务器端项目:

mkdir chat-app
cd chat-app
cargo new server --bin
cd server
2. 添加依赖

编辑 Cargo.toml 文件,添加必要的依赖:

[dependencies]
tokio = { version = "1", features = ["full"] }
futures = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sqlx = { version = "0.5", features = ["runtime-tokio-native-tls", "sqlite"] }
3. 编写服务器代码

编辑 src/main.rs 文件,编写服务器逻辑:

use tokio::net::{TcpListener, TcpStream};
use tokio::sync::broadcast;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use futures::stream::StreamExt;
use serde::{Serialize, Deserialize};
use sqlx::sqlite::SqlitePool;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::SystemTime;

#[derive(Serialize, Deserialize, Debug)]
struct Message {
    username: String,
    content: String,
    timestamp: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 绑定服务器到 IP 地址和端口
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    
    // 连接到 SQLite 数据库
    let pool = SqlitePool::connect("sqlite:chat.db").await?;
    
    // 运行数据库迁移脚本
    sqlx::migrate!().run(&pool).await?;

    // 创建广播通道,用于消息传递
    let (tx, _rx) = broadcast::channel::<Message>(100);
    
    // 创建客户端列表,用于管理连接的客户端
    let clients = Arc::new(tokio::sync::Mutex::new(HashMap::new()));

    // 监听客户端连接
    loop {
        let (socket, addr) = listener.accept().await?;
        
        // 复制广播发送者和客户端列表
        let tx = tx.clone();
        let clients = Arc::clone(&clients);
        let pool = pool.clone();

        // 为每个客户端创建一个新的任务
        tokio::spawn(async move {
            handle_client(socket, addr, tx, clients, pool).await;
        });
    }
}

async fn handle_client(
    mut socket: TcpStream,
    addr: std::net::SocketAddr,
    tx: broadcast::Sender<Message>,
    clients: Arc<tokio::sync::Mutex<HashMap<std::net::SocketAddr, broadcast::Receiver<Message>>>>,
    pool: SqlitePool,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut buf = [0; 1024];
    let mut rx = tx.subscribe();

    loop {
        let mut readable = false;
        let mut writable = false;

        // 检查是否有新的消息需要发送给客户端
        {
            let clients = clients.lock().await;
            if let Some(rx) = clients.get(&addr) {
                readable = rx.recv().await.is_ok();
            }
        }

        if readable {
            let message = rx.recv().await?;
            socket.write_all(&serde_json::to_vec(&message)?).await?;
        }

        // 检查是否有来自客户端的消息
        if socket.readable().await? {
            let n = socket.read(&mut buf).await?;
            if n == 0 {
                break;
            }

            let message: Message = serde_json::from_slice(&buf[..n])?;
            let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
            let message = Message {
                username: message.username,
                content: message.content,
                timestamp: now,
            };

            // 将消息存入数据库
            sqlx::query!(
                "INSERT INTO messages (username, content, timestamp) VALUES (?, ?, ?)",
                message.username,
                message.content,
                message.timestamp
            )
            .execute(&pool)
            .await?;

            // 广播消息给所有客户端
            tx.send(message)?;
            clients.lock().await.insert(addr, rx.resubscribe());
            writable = true;
        }

        // 发送消息到客户端
        if writable {
            socket.writable().await?;
            socket.flush().await?;
        }
    }

    Ok(())
}

客户端端

1. 初始化项目

初始化客户端项目:

cd ..
cargo new client --bin
cd client
2. 添加依赖

编辑 Cargo.toml 文件,添加必要的依赖:

[dependencies]
gtk = "0.11"
glib = "0.11"
gio = "0.11"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.13"
3. 编写客户端代码

编辑 src/main.rs 文件,编写客户端逻辑:

use gtk::prelude::*;
use gio::prelude::*;
use tokio::runtime::Runtime;
use tokio_tungstenite::tungstenite::protocol::Message as WsMessage;
use serde::{Serialize, Deserialize};
use std::sync::mpsc;

#[derive(Serialize, Deserialize, Debug)]
struct ChatMessage {
    username: String,
    content: String,
    timestamp: u64,
}

fn main() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }

    let application = gtk::Application::new(
        Some("com.example.chat-client"),
        Default::default(),
    );

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run();
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);
    window.set_title("Chat Client");
    window.set_default_size(400, 600);

    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 5);
    let scrolled_window = gtk::ScrolledWindow::new(None, None);
    let text_view = gtk::TextView::new();
    let entry = gtk::Entry::new();
    let send_button = gtk::Button::with_label("Send");

    scrolled_window.add(&text_view);
    vbox.pack_start(&scrolled_window, true, true, 0);
    vbox.pack_start(&entry, false, false, 0);
    vbox.pack_start(&send_button, false, false, 0);

    window.add(&vbox);
    window.show_all();

    let (tx, rx) = mpsc::channel();
    let text_buffer = text_view.buffer().clone();

    send_button.connect_clicked(clone!(@strong entry, @strong tx => move |_| {
        let message = entry.text().to_string();
        entry.set_text("");
        tx.send(message).unwrap();
    }));

    let runtime = Runtime::new().unwrap();
    runtime.spawn(async move {
        let ws_stream = tokio_tungstenite::connect_async("ws://127.0.0.1:8080").await.unwrap().0;
        let (mut ws_write, mut ws_read) = ws_stream.split();

        while let Ok(message) = rx.recv() {
            let message = ChatMessage {
                username: "User".to_string(),
                content: message,
                timestamp: std::time::SystemTime::now()
                    .duration_since(std::time::SystemTime::UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            };
            let json_message = serde_json::to_string(&message).unwrap();
            ws_write.send(WsMessage::Text(json_message)).await.unwrap();
        }

        while let Some(message) = ws_read.next().await {
            if let Ok(WsMessage::Text(text)) = message {
                let message: ChatMessage = serde_json::from_str(&text).unwrap();
                let message_text = format!("{}: {}\n", message.username, message.content);
                glib::idle_add_once(move || {
                    text_buffer.insert_at_cursor(&message_text);
                });
            }
        }
    });
}

数据库迁移

在服务器端目录下创建一个 migrations 文件夹,并在其中创建一个迁移文件 V1__create_messages_table.sql

CREATE TABLE IF NOT EXISTS messages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT NOT NULL,
    content TEXT NOT NULL,
    timestamp INTEGER NOT NULL
);

运行项目

  1. 启动服务器

    cd chat-app/server
    cargo run
  2. 启动客户端

    cd chat-app/client
    cargo run

项目总结

通过以上步骤,我们创建了一个完整的聊天应用程序,包括以下几个部分:

  1. 服务器端

    • 使用 Tokio 进行异步网络编程,处理客户端连接和消息转发。
    • 使用 SQLite 数据库存储消息历史。
    • 使用广播通道(broadcast::channel)管理消息的发送和接收。
  2. 客户端端

    • 使用 GTK-rs 创建图形用户界面,允许用户输入和显示消息。
    • 使用 WebSocket 与服务器通信,发送和接收消息。

这个项目结合了异步编程、网络通信、图形界面和数据库操作等多个领域的知识,展示了 Rust 在构建复杂应用程序方面的强大能力。

标签:顶流,use,进阶,await,serde,let,new,message,Rust
From: https://blog.csdn.net/speaking_me/article/details/143980505

相关文章

  • 【C++】深入理解 C++ 中的继承进阶:多继承、菱形继承及其解决方案
    个人主页:起名字真南的CSDN博客个人专栏:【数据结构初阶】......
  • SQL进阶技巧:如何进行数字范围统计?| 货场剩余货位的统计查询方法
    目录0场景描述1 剩余空位区间和剩余空位编号统计分析 2 查找已用货位区间3小结0场景描述这是在做一个大型货场租赁系统时遇到的问题,在计算货场剩余存储空间时,不仅仅需要知道哪些货位是空闲的,还要能够判断出哪些货位之间是连续的。因为在新货物入场时,可以判断这些......
  • Java教程:SE进阶【十万字详解】(中)
    ✨博客主页:https://blog.csdn.net/m0_63815035?type=blog......
  • ybtoj 高效进阶题解索引
    密码:sunxuhetai2009--------------------云落的分割线--------------------基础算法第1章-递推算法第2章-贪心算法--------------------云落的分割线--------------------图论第1章-并查集第4章-强连通分量--------------------云落的分割线--------------------......
  • python-day07-面向对象进阶
    isinstance和issubclassisinstance(obj,cls)检查是否obj是否是类cls的对象123456class Foo(object):     pass   obj = Foo()   isinstance(obj,Foo)issubclass(sub,super)检查sub类是否是super类的派生类 1234......
  • rust学习十一.1、泛型(通用类型)
    这是和大部分的语言差不多的一个概念,只不过实现上有一些区别而已。所以,如果学过java,c#,c++,那么这应该很好理解。虽然如此,还是有不少内容需要记录,只不过内容有一点小多。注意:这是入门级别内容,只能涉及到一些基本的方面。一、定义英文Generic/generics,中文翻译为通用类型/......
  • 小白如何进阶 Java 高级工程师
    一、小白进阶之路开启在当今数字化时代,Java作为一种广泛应用的编程语言,掌握它对于个人职业发展至关重要。从小白进阶为Java高级工程师不仅意味着薪资的提升,更是个人技术实力和职业价值的体现。然而,这条进阶之路充满挑战。首先,Java语言本身具有一定的复杂性。它涵盖了众......
  • Chrome DevTools Protocol 进阶:Console域
    前言在日常开发和调试过程中,浏览器控制台(Console)是开发者最常使用的工具之一。通过它,我们可以输出调试信息、错误提示、以及监控JavaScript代码的执行。ChromeDevToolsProtocol(CDP)通过Console域,允许我们以编程的方式来捕获和处理控制台中的日志输出,使我们能够进行更加自......
  • Python语法进阶与虚拟机安装详解
    Python作为一种高级编程语言,以其简洁的语法和强大的功能,在数据科学、人工智能、Web开发等多个领域得到了广泛应用。为了深入理解Python的进阶语法,并在一个隔离的环境中进行实践,虚拟机安装成为了一个不错的选择。本文将详细介绍Python的进阶语法以及如何在虚拟机中安装Python......
  • python进阶-02-一篇文章搞明白BeautifulSoup
    python进阶-02-一篇文章搞明白BeautifulSoup一.说明开始今天的日拱一卒,上一篇文章我们介绍了Xpath,今天我们开始介绍BeautifulSoup,这个也是用来解析HTML文档的技术,但是跟Xpath还是有区别的,XPath是使用路径表达式来定位元素,而BeautifulSoup就是一个字简单。二.安装要使......