robotask内新建一个简单采集任务 但以封装思路可复用逻辑来设计 笔记 2026-07-04 18h50s54
先用36kr 快讯 测试取值
document.querySelectorAll(".flow-item")
看看有多少个
document.querySelectorAll(".flow-item")[0]
看看第一个
document.querySelectorAll(".flow-item")[0].innerText
取第一个的标题、链接、日期
let item = document.querySelectorAll(".flow-item")[0];
console.log(item.querySelector(".item-title").innerText);
console.log(item.querySelector(".item-title").href);
console.log(item.querySelector(".time").innerText);
完整测试
let item = document.querySelectorAll(".flow-item")[0];
let news = {
title: item.querySelector(".item-title").innerText,
url: item.querySelector(".item-title").href,
time: item.querySelector(".time").innerText
};
news;
但出现了错误 Path is empty 这时候需要梳理逻辑
了解 robotask 的Execute JavaScript 逻辑
以下是从官方pdf faq找寻的全部帮助 我们看看是哪里需要调整
执行 JavaScript”操作会在浏览器中运行自定义 JavaScript代码。这个强大的操作让你可以以其他操作可能无法涵盖的方式与页面互动。
从复杂的 JavaScript 渲染页面中提取数据 绕过标准操作的限制(隐藏元素、Shadow DOM) 对页面内容进行计算或数据转换 在截屏前修改页面外观(隐藏横幅、弹窗) 处理特殊情况,如无限滚动或懒加载 访问页面变量或 JavaScript 函数 注意:此操作需要 JavaScript 编程知识。没有编程技能的用户可以使用其他操作完成大多数任务
选择要运行脚本的浏览器
内联脚本类型或直接将 JavaScript 粘贴到文本区域 适合短脚本或快速操作 支持多行代码和完整的 JavaScript 语法
如何返回值 要把结果保存到一个变量,你的脚本必须使用 return 语句
将结果保存到变量 可选:输入一个变量名来存储脚本的返回值 你的脚本必须使用 return 语句来返回值 如果脚本没有返回值,请留空
// Get page title
return document.title;
// Count elements
return document.querySelectorAll('.item').length;
// Get multiple values as JSON
return {
title: document.title,
url: window.location.href,
timestamp: new Date().toISOString()
};
Examples of usage.
Extract data from a table:
const rows = document.querySelectorAll('table tr');
const data = [];
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length >= 2) {
data.push({
name: cells[0].textContent,
value: cells[1].textContent
});
}
});
return JSON.stringify(data);
Scroll to bottom of page:
window.scrollTo(0, document.body.scrollHeight);
// No return needed for actions without results
导致 Path is empty 错误的原因严谨追查
为了搞清楚这个问题 首先我确认本地环境是否异常,所以我在新电脑直接安装官方最新版和对应的ChromiumSetup64(11)插件,直接在里面测试,结果没有意外依然是Path is empty ,
你说的浏览器绑定我最先测试 微软的浏览器和默认的 built-in 均一样返回错误
所以我将目光再次调整,是否是我的用法错了,于是我将直接跑以下官方的示例
我注意到执行js对话框 浏览器下拉默认是Browser1,我改为built-in后无法测试只有默认Browser1才行
点击测试会打开一个浏览器 且可以进行F12调试 应该不存在没有对象可以访问
于是我跑了官方的两个案例和你给的两个 都一样返回错误
const item = document.querySelector(".flow-item");
return JSON.stringify({
title:item.querySelector(".item-title").innerText,
url:item.querySelector(".item-title").href,
time:item.querySelector(".time").innerText
});
我现在甚至已经用了最新版 11.0.7.347 不至于bug这么明显吧 如果开发者连基础测试都没通过想必在上个版本就已经否决发布了
没错 这个web自动化插件 的确是 CEF(Chromium Embedded Framework)模式
以下是我调取这两个插件的属性信息:
Description: Embedded Chromium Browser
Location: D:\Work\RoboTask\Plugins\Chromium\Chromium.rtp
--------
Number of Actions: 7
* Action "Browser Fill Web Form"
* Action "Browser Web Page Information"
* Action "Browser Click Link"
* Action "Browser Wait for Done"
* Action "Browser Page Snapshot"
* Action "Browser Window Size"
* Action "Browser Run Javascript"
--------
Number of Triggers: 0
Description: Web Automation
Location: D:\Work\RoboTask\Plugins\WebAutomation\WebAutomation.rtp
--------
Number of Actions: 11
* Action "Start Browser"
* Action "Close Browser"
* Action "Navigate"
* Action "Mouse Click / Hover / Focus"
* Action "Click Download Link"
* Action "Send Keys"
* Action "Get Element Property"
* Action "Get Page Details"
* Action "Set Form Field Value"
* Action "Take Screenshot"
* Action "Execute Javascript"
--------
Number of Triggers: 0
再次测试
为了验证你这个问题首先我说明一下,ChromiumSetup64独立包安装后就会安装在C:\RoboTask\CEF\ 体积440M,同时会生成插件
D:\Work\RoboTask\Plugins\Chromium\Chromium.rtp
而D:\Work\RoboTask\Plugins\WebAutomation\WebAutomation.rtp 插件我认为是直接操作了这个浏览器基底,
现在开始验证你的假设,
1.看一下纯Chromium插件内的 Action "Browser Run Javascript" 是否能操作WebAutomation的 Action "Start Browser"
结论是:W: 2026/7/4 16:46:20: CEF未加载 跳过步骤.
2.直接让Chromium.rtp的Action "Browser Fill Web Form" 打开网页再让WebAutomation的 Action "Execute Javascript"执行js,但无法读取浏览器对象所以我输入了CEF,
运行后得到错误E: 2026/7/4 16:52:18: Browser variable "CEF" is empty or not found
所以这两个假设测试失败,目前来看 WebAutomation有独立的体系可以访问内置浏览器,因为我测试了WebAutomation的"Start Browser"打开网页再"Get Page Details"获取标题 成功了
Chromium.rtp 和 WebAutomation.rtp 是两套完全不同的 Browser 对象。
进行temp文件夹监控 测试
首先我测试执行脚本 当打开浏览器后弹出错误 我看到监控根据出现了200多个日志数 首先我看到
C:\RoboTask\Neocore\neocore.exe 启动了一些东西 并创建了一些诸如 临时文件C:\Users\c\AppData\Local\Temp\12d7a267-9352-4edf-9831-985d105e43fc.tmp
当然后面的是由 explorer读取了一些 C:\Users\c\AppData\Local\Temp\playwright_chromiumdev_profile-FHRHc6
但这都不是关键信息,为了看下执行js有没有动静我直接把刚才打开的界面再次点击测试 观察监控 结果无任何反应
既如此我直接把他作为外部js执行试试返回说明错误 随便下载一个js执行
C:\Users\c\Downloads\a.js
这次返回:value result not found
既然做到这一步了 我觉得直接可以测试正确的代码,我直接改为
真正解决问题在这一步 但是每次新建一个任务 使用内部js都会问题依旧,所以这里我们直接就用外部初始化一下一个空文件再执行真正的内部脚本
const item = document.querySelector(".flow-item");
return JSON.stringify({
title:item.querySelector(".item-title").innerText,
url:item.querySelector(".item-title").href,
time:item.querySelector(".time").innerText
});
测试后得到弹窗为标题、链接和时间,那说明外部跑通,但内部js难道不是一个逻辑吗?内部不行 同样的代码只有外部行
于是我直接把代码再次粘贴到内部文本框 点击测试,结果返回与上面执行的一样!
这真是无语了,于是我保存关闭又再次试了一次,以及再执行了一次外部模式 都正确返回。
你说说
排查日志
Inline 和 Script File 最终走的是同一套执行器。
这次得出的逻辑结论可能是:
第一次运行 ExecuteJavascript
↓
检查 Script Engine
↓
Path=""
↓
报错
↓
切换 Script File
↓
初始化成功
↓
Script Engine Loaded
↓
以后 Inline 也正常
缓存路径目录(C:\Users\c\AppData\Local\Temp\cef\cache)不是根缓存路径目录(C:\Users\c\AppData\Local\Temp\cef\User Data)的子目录
[0704/165213.319:ERROR:cef\libcef\browser\context.cc:181] 缓存路径无效,将默认使用内存存储
C:\Users\c\AppData\Local\Temp\cef\User Data 看来是任务执行的必要工作目录
很有可能内部反而不是直接的一部,外部才没有绕路,ExecuteJavascript Action 第一次初始化没有完成。你的结论是对的 那么原因是什么,我可不想自动固定时间执行时再次重现如故。
否则只能直接走外部js flie
其实我有封装"简单采集"控件,的想法,我知道在当前工具下有几个实现路径,1.直接用脚本能力 执行node或python 插件,直接把 "简单采集"控件,作为一个任务用任务调用这个任务,这是在
工具中内置支持的,不过这样不干脆出错率大,虽然有全局变量和数据库操作插件却仍显复杂
再次分析 如何封装 取列表类
C:\Users\c\AppData\Local\Temp\cef\User Data
这个目录是在什么时候建立的?
这句话让我思考到 可能浏览器没有第一次初始化某些模块,虽然目录是安装软件时建立的 但有些文件和目录却是20分钟前建立的
所以如果下次踩坑了 可以写个判断如果返回不了数据就直接给他 js file 再取值
封装方案最优:xecute JS↓JSON↓Robotask
这里封装为控件有几个变量那就是选择目标的几个字段需要用户级输入或配置例如通过file\xml、ini、sql、窗口会话
{
"list": ".flow-item",
"fields": {
"title": ".item-title",
"url": ".item-title@href",
"time": ".time",
"content": ".item-desc span"
}
}
但在执行时 xecute JS面临在 js代码中传递参数的问题 目前我还没有实践过也不知道实现过程不知道能否取出来值以便得到正确的选择器路径 也就是这份模板的封装和传参
const result=[];
document.querySelectorAll(".flow-item").forEach(item=>{
result.push({
title:item.querySelector(".item-title")?.innerText,
url:item.querySelector(".item-title")?.href,
time:item.querySelector(".time")?.innerText,
content:item.querySelector(".item-desc span")?.innerText
});
});
return JSON.stringify(result);
封装简单采集的落地逻辑
直接把 Robotask 的变量替换到 JS 模板中。
例如 Robotask 有变量:
const result = [];
document.querySelectorAll("%LIST%").forEach(item => {
result.push({
title: item.querySelector("%TITLE%")?.innerText,
url: item.querySelector("%URL%")?.href,
time: item.querySelector("%TIME%")?.innerText
});
});
return JSON.stringify(result);
只要 Execute JavaScript 支持 RoboTask 变量替换即可
如果 Robotask 不支持变量替换怎么办?这就是第二种方案
const config = JSON.parse('%CONFIG%');
const result = [];
document.querySelectorAll(config.list).forEach(item => {
const row = {};
for(const key in config.fields){
const selector = config.fields[key];
if(selector.endsWith("@href")){
row[key] = item.querySelector(selector.replace("@href",""))?.href;
}else{
row[key] = item.querySelector(selector)?.innerText;
}
}
result.push(row);
});
return JSON.stringify(result);
只需要支持传
{
"list": ".flow-item",
"fields": {
"title": ".item-title",
"url": ".item-title@href",
"time": ".time"
}
}
遇到不同网站取得值的方法也是不同的
、{
"list": ".flow-item",
"fields":[
{
"name":"title",
"selector":".item-title",
"type":"text"
},
{
"name":"url",
"selector":".item-title",
"type":"href"
},
{
"name":"time",
"selector":".time",
"type":"text"
},
{
"name":"content",
"selector":".item-desc span",
"type":"text"
}
]
}
可以增加字段和指定类型
再增加容错逻辑 以后再迭代
const el = item.querySelector(field.selector);
if(!el){
row[field.name] = "";
continue;
}
某一条新闻没有时间或别的必要字段。整个采集全部停止
Edited on
Jul 04, 2026
By
sytbbt .