Node-RED提取网页HighCharts红绿系列数据:选择器与函数实现
解决Node-RED提取指定HighCharts数据的问题
嘿,我来帮你搞定这个家庭自动化的数据提取需求!咱们一步步来,先解决HTML节点的选择器问题,再搞定Function节点的代码逻辑。
一、HTML节点的正确选择器配置
首先要明确:目标页面的HighCharts数据是嵌在页面的JavaScript脚本里的,不是直接在可见的DOM元素中。所以HTML节点的核心是定位到包含"Preliminära resultat 2018"图表数据的脚本块。
你可以在HTML节点里用这个选择器:script:contains("Preliminära resultat 2018")
配置细节:
- 选择器类型选CSS selector
- 输出格式选HTML(这样能拿到完整的脚本内容,方便后续解析)
这个选择器会匹配页面中包含目标图表标题文本的脚本标签,精准定位到存数据的地方。
二、Function节点的代码实现
拿到脚本内容后,我们需要从中提取绿色、红色系列的数据,转换成包含值和日期的结构化数组。以下是直接可用的代码,我会在代码里加注释说明逻辑:
// 1. 获取HTML节点传来的脚本内容 const scriptText = msg.payload; // 2. 用正则匹配出HighCharts的配置对象(重点抓series数据) const chartRegex = /Highcharts\.chart\([^,]+,\s*({[^}]+series[^}]+})/; const matchResult = scriptText.match(chartRegex); // 如果没匹配到数据,直接返回错误提示 if (!matchResult || !matchResult[1]) { msg.payload = "未找到目标图表的series数据"; return msg; } // 3. 把匹配到的JS对象字符串转成合法JSON let chartConfig; try { // 处理页面脚本里的单引号和未加引号的属性名,确保JSON能解析 const fixedJson = matchResult[1] .replace(/'/g, '"') .replace(/([a-zA-Z0-9_]+):/g, '"$1":'); chartConfig = JSON.parse(fixedJson); } catch (err) { msg.payload = `解析图表数据失败:${err.message}`; return msg; } // 4. 筛选出绿色和红色的系列(可根据实际名称调整判断条件) const targetSeries = chartConfig.series.filter(series => { // 这里用颜色码判断,也可以改成按名称筛选,比如series.name === "Flöde" return series.color === "#009900" || series.color === "#ff0000"; }); // 5. 把HighCharts的[时间戳, 值]格式转换成{value, date}的数组 const formattedData = targetSeries.map(series => ({ seriesName: series.name, color: series.color, data: series.data.map(point => ({ value: point[1], date: new Date(point[0]).toLocaleString() // 转成易读的日期格式,也可以用toISOString() })) })); // 6. 把处理好的数据传递给下一个节点 msg.payload = formattedData; return msg;
代码关键说明:
- 正则匹配:因为页面没有提供公开API,所以直接从脚本里提取HighCharts的配置对象是最靠谱的方式。
- JSON转换:页面里的脚本可能用单引号定义字符串,属性名也可能没加引号,所以要做格式修正才能被
JSON.parse识别。 - 系列筛选:这里用颜色码锁定绿色和红色系列,你也可以根据实际的系列名称(比如“Flöde”代表水流,“Temperatur”代表温度)来调整判断条件,更稳定。
- 数据格式化:把HighCharts默认的[时间戳, 数值]数组转成包含值和日期的对象,方便后续家庭自动化节点做警报、趋势分析。
三、后续优化提示
- 可以在Debug节点里查看输出,确认数据结构是否符合预期,如果解析出错,看Function节点返回的错误信息调整正则或转换逻辑。
- 针对家庭自动化需求,你可以在Function节点后面加Switch节点,判断值是否超过阈值(比如温度超过30℃触发警报),或者用Trend节点做趋势监控。
内容的提问来源于stack exchange,提问作者Tobbe




