Rust異步爬蟲實現與優化

Rust 語言在爬蟲領域的應用相對較少,盡管 Rust 的 async/await 已穩定,但其與線程安全、Pin 等概念的結合仍較復雜,而爬蟲高度依賴并發處理,進一步提高了開發成本。這就導致了使用Rust語言爬蟲用的人很少。

在這里插入圖片描述

下面是一個使用 Rust 編寫的異步爬蟲示例,支持并發請求、深度控制和去重功能。該爬蟲使用 Tokio 作為異步運行時,Reqwest 處理 HTTP 請求,Select 解析 HTML。

use std::{collections::HashSet, sync::Arc, time::Duration};use select::{document::Document,predicate::{Name, Attr},
};
use tokio::{sync::{Mutex, Semaphore},time,
};
use url::Url;// 爬蟲配置
const MAX_DEPTH: usize = 3; // 最大爬取深度
const MAX_PAGES: usize = 50; // 最大爬取頁面數
const MAX_CONCURRENT_REQUESTS: usize = 10; // 最大并發請求數
const USER_AGENT: &str = "Mozilla/5.0 (compatible; AsyncCrawler/1.0)";#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {let start_url = "https://www.rust-lang.org/";println!("Starting crawl from: {}", start_url);// 共享狀態let visited = Arc::new(Mutex::new(HashSet::new()));let page_count = Arc::new(Mutex::new(0));let semaphore = Arc::new(Semaphore::new(MAX_CONCURRENT_REQUESTS));// 初始 URLcrawl_page(start_url.to_string(),0,visited.clone(),page_count.clone(),semaphore.clone(),).await?;println!("Crawling completed!");Ok(())
}/// 爬取單個頁面
async fn crawl_page(url: String,depth: usize,visited: Arc<Mutex<HashSet<String>>>,page_count: Arc<Mutex<usize>>,semaphore: Arc<Semaphore>,
) -> Result<(), Box<dyn std::error::Error>> {// 檢查深度限制if depth > MAX_DEPTH {return Ok(());}// 檢查是否已訪問{let mut visited_set = visited.lock().await;if visited_set.contains(&url) {return Ok(());}visited_set.insert(url.clone());}// 獲取信號量許可 (控制并發)let _permit = semaphore.acquire().await?;// 創建 HTTP 客戶端let client = reqwest::Client::builder().user_agent(USER_AGENT).timeout(Duration::from_secs(5)).build()?;// 發送請求let response = match client.get(&url).send().await {Ok(res) => res,Err(e) => {eprintln!("Request failed: {} - {}", url, e);return Ok(());}};// 檢查狀態碼if !response.status().is_success() {eprintln!("HTTP error: {} - {}", url, response.status());return Ok(());}// 獲取頁面內容let html = match response.text().await {Ok(html) => html,Err(e) => {eprintln!("Failed to get text: {} - {}", url, e);return Ok(());}};// 更新頁面計數器let mut count = page_count.lock().await;*count += 1;println!("[{}/{}] Depth {}: {}", *count, MAX_PAGES, depth, url);// 檢查頁面限制if *count >= MAX_PAGES {return Ok(());}// 解析頁面并提取鏈接let base_url = Url::parse(&url)?;let document = Document::from(html.as_str());let links: Vec<String> = document.find(Name("a")).filter_map(|a| a.attr("href")).filter_map(|href| base_url.join(href).ok()).map(|url| url.to_string()).collect();// 限制請求速率time::sleep(Duration::from_millis(100)).await;// 創建新爬取任務let mut tasks = vec![];for link in links {let visited = visited.clone();let page_count = page_count.clone();let semaphore = semaphore.clone();tasks.push(tokio::spawn(async move {crawl_page(link, depth + 1, visited, page_count, semaphore).await}));}// 等待所有任務完成for task in tasks {let _ = task.await;}Ok(())
}

功能說明

1、異步并發

  • 使用 Tokio 的異步任務 (tokio::spawn)
  • 通過信號量 (Semaphore) 限制最大并發請求數

2、爬取控制

  • MAX_DEPTH:限制爬取深度
  • MAX_PAGES:限制最大頁面數
  • 請求超時設置 (5 秒)
  • 請求間延遲 (100ms)

3、智能解析

  • 使用 url 庫處理相對/絕對路徑
  • 通過 select 庫解析 HTML 并提取鏈接
  • 只處理 <a> 標簽的 href 屬性

4、狀態管理

  • 使用 Mutex 保護共享狀態
  • 使用 HashSet 記錄已訪問 URL
  • 原子計數器跟蹤已爬取頁面數

使用說明

1、添加依賴到 Cargo.toml

[dependencies]
tokio = { version = "1.0", features = ["full"] }
reqwest = "0.11"
select = "0.6"
url = "2.4"

2、可配置參數:

// 在代碼頂部修改這些常量:
const MAX_DEPTH: usize = 3;      // 最大爬取深度
const MAX_PAGES: usize = 50;     // 最大爬取頁面數
const MAX_CONCURRENT_REQUESTS: usize = 10; // 并發請求數
const USER_AGENT: &str = "..."; // 自定義 User-Agent

3、運行:

cargo run

這個爬蟲框架提供了基礎功能,我們可以根據具體需求擴展其功能。建議在實際使用時添加適當的日志記錄、錯誤處理和遵守目標網站的爬取政策。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/89731.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/89731.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/89731.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Electron 安全最佳實踐:構建安全的桌面應用

Electron 是一個流行的框架&#xff0c;允許開發者使用 Web 技術&#xff08;HTML、CSS、JavaScript&#xff09;構建跨平臺桌面應用。許多知名應用&#xff0c;如 VS Code、Slack 和 Discord&#xff0c;都基于 Electron 開發。然而&#xff0c;由于其結合了 Node.js&#xff…

MySQL 事務詳解:從基礎操作到隔離級別與 MVCC 原理

前言 首先從概念上進行理解什么是事務&#xff0c;以及事務的4大屬性&#xff0c;知道是什么還要知道為什么&#xff1f; 事務是如何進行操作的&#xff0c;最后在談事務的隔離性、隔離級別&#xff08;最重要但是也很難理解&#xff09;&#xff0c;理解隔離級別體現在哪里 …

【Unity 編輯器工具開發:GUILayout 與 EditorGUILayout 對比分析】

Unity 編輯器工具開發&#xff1a;GUILayout 與 EditorGUILayout 對比分析 一、核心區別對比 方面GUILayoutEditorGUILayout區別命名空間UnityEngineUnityEditorEditorGUILayout 僅限編輯器環境適用范圍游戲運行時 編輯器工具僅限編輯器工具運行時禁用 EditorGUILayout渲染管…

[附源碼+數據庫+畢業論文]基于Spring+MyBatis+MySQL+Maven+jsp實現的個人財務管理系統,推薦!

摘 要 隨著軟件信息技術的興起&#xff0c;許多手工作業也升級為軟件管理數據&#xff0c;本次針對個人財務數據的管理&#xff0c;開發一款個人財務管理系統&#xff0c;該系統可以解決許多信息管理上面的難題&#xff0c;比如處理數據時間很長&#xff0c;數據存在錯誤不能及…

Compose入門3 - 高仿小紅書 界面

使用compose 實現一個小紅書UI 界面&#xff0c;主要是為了鍛煉 使用compose布局的能力 demo地址&#xff1a;https://github.com/PangHaHa12138/ComposeDemo 先上demo 截圖 下面是完整的compose代碼 package com.example.test001import android.annotation.SuppressLint imp…

mybatis-plus json字段使用typeHandler自動轉換為List

mybatis-plus json字段使用typeHandler自動轉換為List mybatis-plus json字段使用typeHandler自動轉換為List 一、實現思路 1.配置mybatis配置&#xff0c;注入handlermybatis-plus:typeHandlersPackage: com.power.common.core.handler 2.字段頂部增加注解TableField(typeHand…

(C++)學生管理系統(測試2版)(map數組的應用)(string應用)(引用)(C++教學)(C++項目)

1. 頭文件與命名空間 #include <iostream> // 輸入輸出流庫&#xff0c;提供cin/cout等基本I/O功能 #include <map> // 映射容器庫&#xff0c;提供map數據結構&#xff08;鍵值對集合&#xff09; #include <string> // 字符串庫&#xff0c;…

使用assembly解決jar包超大,實現依賴包、前端資源外置部署

成果物需要部署到用戶內網的童鞋應該都遇到過該問題&#xff1a;引入的maven依賴越來越多&#xff0c;jar包越來越大&#xff0c;我之間甚至見過一兩個G的依賴&#xff0c;想改個代碼換到現場測試&#xff0c;包傳到現場要一二十分鐘&#xff0c;真正實現了改代碼兩分鐘分鐘&am…

基于PHP+MySQL實現(Web)英語學習與測試平臺

數據庫課設&#xff1a;英語學習與測試平臺 運行環境要求 PHP7.1 基于 thinkPHP6.0、Layui、Xadmin 開發 主要功能 公共模塊 登錄注冊個人信息修改密碼修改 教師模塊 文章查看發布班級管理測試查看發布批改歷史成績查看 學生模塊 文章查看參與測試查看成績 管理員模塊…

WinForm中Settings.settings和app.config修改后信息不同步到exe.config問題

在 WinForms 項目中&#xff0c;Settings.settings 和 app.config/exe.config 的關系確實容易讓人困惑。以下是問題的根本原因和解決方案&#xff1a; 問題本質 設計時文件&#xff1a;app.config&#xff08;源碼中的配置文件&#xff09;運行時文件&#xff1a;bin/Debug/Yo…

【公司環境下發布個人NPM包完整教程】

&#x1f3e2; 公司環境下發布個人NPM包完整教程 創建時間: 2025年7月2日 適用場景: 公司電腦&#xff0c;需要臨時切換個人賬戶發布npm包 &#x1f3af; 教程概述 場景說明 環境: 公司電腦&#xff0c;已配置公司npm賬戶目標: 臨時使用個人賬戶發布npm包&#xff0c;發布后恢復…

滲透測試中 phpinfo() 的信息利用分析

在滲透測試中&#xff0c;phpinfo() 是一個非常常見卻極具價值的信息泄露點。這個函數的本意是向開發者展示當前 PHP 環境的詳細配置情況&#xff0c;包括編譯選項、擴展模塊、環境變量、系統信息、目錄路徑等。然而一旦該頁面被暴露到互聯網上&#xff0c;攻擊者便可以借此收集…

《如何在 Spring 中實現 MQ 消息的自動重連:監聽與發送雙通道策略》

大家好&#xff0c;我是G探險者&#xff01;&#x1f4cc; 背景場景在高可用分布式系統中&#xff0c;我們經常面臨&#xff1a;MQ 集群重啟 → 消息監聽中斷MQ 網絡短暫抖動 → 發送端連接失敗一端恢復正常&#xff0c;另一端仍處于掛死狀態如果你只配置了“連接工廠層”的重連…

OpenCV 安裝使用教程

一、OpenCV 簡介 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一個開源計算機視覺和機器學習軟件庫&#xff0c;提供了超過 2500 個優化的算法&#xff0c;用于實時圖像處理、視頻分析、對象識別、人臉檢測、機器學習等任務。 Python 提供了對 Open…

【SNN脈沖神經網絡3】HH神經元軟件仿真

本篇文章主要核心目的在于研究明白HH神經元的數學模型&#xff0c;并且驗證其正確性。因此&#xff0c;在本篇文章中只會使用numpy函數庫用于構建神經元&#xff0c;以及matplotlib用于繪圖。1.導入對應的庫import numpy as np import matplotlib.pyplot as plt import re impo…

「日拱一碼」014 Python常用庫——Pandas

目錄 數據結構 pandas.Series &#xff1a;一維數組&#xff0c;類似于數組&#xff0c;但索引可以是任意類型&#xff0c;而不僅僅是整數 pandas.DataFrame &#xff1a;二維表格型數據結構&#xff0c;類似于 Excel 表格&#xff0c;每列可以是不同的數據類型 數據讀取與寫…

狂命爆肝21天,共51K字的JAVA學習筆記奉上,JAVA從入門到精通一文搞定,一文在手JAVA無憂

背景知識 Java 相關概念 JavaSE (Java Standard Edition): 基礎版&#xff0c;用于開發桌面應用程序。JavaEE (Java Enterprise Edition): 企業版&#xff0c;用于開發企業級應用程序。JavaME (Java Micro Edition): 微型版&#xff0c;用于開發嵌入式系統和移動設備應用程序…

Dijkstra 算法#圖論

Dijkstra 算法 算法前提&#xff1a;在沒有負邊的情況下使用。算法思路&#xff1a;將結點分成已確定最短路長度的點集 S 和未確定最短路長度的點集 T&#xff0c;每次從 T 集合中選取最短路長度最小的結點移到 S 集合中&#xff0c;并對其出邊執行更新操作 從T集合中&#x…

開源與閉源大模型的生態與技術對比:以百度文心4.5開源為視角

技術對比&#xff1a;開源與閉源大模型的優劣勢 性能對比&#xff1a;算力效率與場景適配的博弈 在模型性能的競技場上&#xff0c;開源與閉源大模型呈現出明顯的差異化特征。以百度文心4.5開源系列為例&#xff0c;其47B參數的混合專家&#xff08;MoE&#xff09;模型在飛槳…

企業電商解決方案哪家好?ZKmall模塊商城全渠道支持 + 定制化服務更省心

在數字化浪潮席卷各行各業的當下&#xff0c;企業要想拓展市場、提升競爭力&#xff0c;搭建專屬電商平臺已經成了繞不開的選擇。但市場上的電商解決方案五花八門&#xff0c;怎么才能挑到真正適合自己的&#xff1f;其實道理很簡單&#xff1a;能同時搞定全渠道支持和定制化服…