如何为IWebElement添加事件处理程序或监听器以替代Timer监听数值变化
实现方案
Selenium本身没有为IWebElement提供原生的文本变化监听事件,但可以通过注入浏览器端的MutationObserver实现变更主动通知,完全替代Timer轮询,运行效率更高。
核心思路
利用JavaScript原生的MutationObserver接口监听对应span元素的文本内容变化,变更发生时主动记录变更信息,C#端只需读取变更记录处理即可,无需高频轮询全量元素。优先针对你最关注的价格字段实现,其余字段可按相同逻辑扩展。
具体实现代码
1. 为目标元素注入监听逻辑
遍历表格行时,为需要监听的元素绑定MutationObserver:
for (int i = 0; i < stockWatchListTableRows.Count; i++) { if (i != 0 && i != 1 && i != stockWatchListTableRows.Count - 1) { var row = stockWatchListTableRows[i]; var tds = row.FindElements(By.TagName("span")); var priceElement = tds[2]; // 优先监听价格元素 var symbol = tds[0].GetAttribute("textContent"); // 执行JS注入监听 ((IJavaScriptExecutor)driver).ExecuteScript(@" const targetEl = arguments[0]; const symbol = arguments[1]; // 清理之前的重复监听 if (targetEl._priceObserver) targetEl._priceObserver.disconnect(); const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.type === 'childList' || mutation.type === 'characterData') { const newPrice = targetEl.textContent.trim(); // 全局存储变更记录,供C#端读取 if (!window.__stockPriceChanges) window.__stockPriceChanges = []; window.__stockPriceChanges.push({ symbol: symbol, newPrice: newPrice }); } }); }); // 配置监听范围,覆盖文本变化的所有场景 observer.observe(targetEl, { childList: true, characterData: true, subtree: true }); targetEl._priceObserver = observer; ", priceElement, symbol); } }
2. 处理变更事件
无需高频轮询全量列表,只需读取变更记录处理即可,以下是无阻塞的异步处理实现:
// 持续监听价格变更,不会阻塞主线程 while (appRunning) // 替换为你自己的程序运行状态判断变量 { var change = (Dictionary<string, object>)((IJavaScriptExecutor)driver).ExecuteAsyncScript(@" const callback = arguments[0]; // 有未处理的变更直接返回 if (window.__stockPriceChanges?.length > 0) { callback(window.__stockPriceChanges.shift()); return; } // 无变更则等待新变更触发后返回 const checkTimer = setInterval(() => { if (window.__stockPriceChanges?.length > 0) { clearInterval(checkTimer); callback(window.__stockPriceChanges.shift()); } }, 100); "); // 执行业务逻辑 string symbol = change["symbol"].ToString(); string newPrice = change["newPrice"].ToString(); channelingStocksData csdata = stockDictionary[symbol]; var tblist = csdata.tbl; TextBox currentPriceTB = tblist[(int)TLPColumnNames.Current_Price]; string existingPrice = currentPriceTB.Text; bool bPriceIncreasing = Convert.ToDouble(newPrice) > Convert.ToDouble(existingPrice); ScreenStockData(symbol, newPrice, bPriceIncreasing); }
注意事项
- 若页面刷新或者目标元素被销毁重建,需要重新执行绑定监听的逻辑,可在页面加载完成的回调中触发重绑定
- 其余三个字段的监听可完全复用上述逻辑,只需替换监听的元素和全局存储的字段名即可
- 该方案仅在元素内容真实变化时才会触发处理逻辑,无无用的重复读取操作,性能远高于Timer轮询方案
内容的提问来源于stack exchange,提问作者GRF
相关产品推荐
相关产品推荐

