跳到主要内容

BrowseCrawler

概述

BrowseCrawler 用 BFS 队列遍历整棵 AddressSpace 子树, 双重保护 (max_depth + max_nodes)。基于 tokio。

API

成员类别读写说明
BrowseCrawler::new(ua, max_depth, max_nodes, filter)构造构造
crawl(root, progress, cancel)async 方法返回 Result<CrawlResult>
CrawlResult.all_nodes字段Vec<CrawlNode>
CrawlResult.children_by_parent字段HashMap<String, Vec<String>>
CrawlResult.elapsed字段Duration

代码示例

use opcua::{DarraOpcUa, BrowseCrawler, NodeClass, WellKnownNodes};
use tokio_util::sync::CancellationToken;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let ua = DarraOpcUa::new("opc.tcp://localhost:4840")?;
ua.connect()?;

// 1) 爬整棵 ObjectsFolder
let crawler = BrowseCrawler::new(&ua, 8, 50_000, NodeClass::Unspecified);

let result = crawler.crawl(
WellKnownNodes::OBJECTS_FOLDER,
|count, nid| print!("\r已抓 {} 个, 当前 {}", count, nid),
CancellationToken::new(),
).await?;

println!("\n共 {} 节点, 耗时 {:.1}s",
result.all_nodes.len(), result.elapsed.as_secs_f64());

// 2) 仅 Variable 节点
let c2 = BrowseCrawler::new(&ua, 10, 100_000, NodeClass::Variable);
let r2 = c2.crawl("ns=2;s=Boilers", |_, _| {}, CancellationToken::new()).await?;
for n in &r2.all_nodes {
println!(" {} ({})", n.browse_name, n.node_id);
}

// 3) 取消支持
let cancel = CancellationToken::new();
let cancel_clone = cancel.clone();
tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
cancel_clone.cancel();
});
let r3 = crawler.crawl("i=85", |_, _| {}, cancel).await?;
println!("取消时已抓 {} 个", r3.all_nodes.len());

Ok(())
}

性能

节点规模耗时
1,000~0.5s
10,000~5s
50,000~25s

最佳实践

  • 限定 root, 不要从 i=84 (Root) 开始
  • 用 nodeClassFilter 节省内存
  • 启动时一次性爬
  • 给用户"取消"按钮 (CancellationToken)

跨语言对照

C#PythonJavaC++RustC
BrowseCrawlerBrowseCrawlerBrowseCrawlerBrowseCrawlerBrowseCrawlerDarraUa_BrowseCrawler_*

下一步