做网页自动化时,F12开发者工具几乎是必开的——查XPath、看网络请求、调试JavaScript。但大部分人只用到了它的1%功能。
其实,开发者工具本身也可以被自动化利用——通过它来执行调试脚本、拦截请求、分析页面性能、甚至绕过某些前端限制。今天讲浏览器控制台和开发者工具在RPA流程中的高阶用法,以及如何把它的能力集成到影刀流程中。
先说核心:开发者工具能为RPA提供什么
| 能力 | 说明 | RPA中的价值 |
|---|---|---|
| Console执行JS | 在控制台直接运行JavaScript | 实时调试、动态修改页面 |
| Network抓包 | 捕获页面所有网络请求 | 提取API接口、获取隐藏数据 |
| Elements实时编辑 | 修改DOM结构和样式 | 绕过前端限制、临时修复页面 |
| Performance分析 | 页面加载性能分析 | 优化等待策略 |
| Application存储 | 查看Cookie/LocalStorage | 调试登录态 |
第一部分:Console控制台的高阶操作
1.1 在控制台中执行多行脚本
// 在浏览器控制台中执行(F12 → Console)
// 1. 获取页面上所有商品链接

let links = document.querySelectorAll('.product-item a');
let urls = Array.from(links).map(a => a.href);
console.log(urls);
// 2. 模拟滚动到底部(触发懒加载)

window.scrollTo(0, document.body.scrollHeight);
// 3. 批量点击所有“加载更多”按钮
document.querySelectorAll('.load-more-btn').forEach(btn => btn.click());

// 4. 提取表格数据
let tableData = [];
document.querySelectorAll('#data-table tbody tr').forEach(row => {
let cells = row.querySelectorAll('td');
tableData.push(Array.from(cells).map(c => c.innerText));
});
console.table(tableData);
1.2 在影刀中通过ExecuteScript执行控制台命令
# ============================================
# 影刀中执行JavaScript(同控制台效果)
# ============================================
# 获取页面上所有商品价格
执行JavaScript("""
let prices = document.querySelectorAll('.price');
let priceArray = Array.from(prices).map(el => el.innerText);
return priceArray;
""", 存入变量=价格列表)
输出日志("采集到 " + 获取列表长度(价格列表) + " 个价格")
# 模拟控制台中的批量操作
执行JavaScript("""
// 模拟人类滚动

window.scrollTo(0, document.body.scrollHeight / 2);
setTimeout(() => {
window.scrollTo(0, document.body.scrollHeight);
}, 500);
return 'scroll completed';
""")
1.3 使用控制台调试XPath(比XPath Helper更灵活)
// 在控制台中测试XPath
function getElementByXPath(xpath) {
return document.evaluate(
xpath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
}
// 测试XPath是否能定位到元素
let el = getElementByXPath('//div[@class="product"]//span[@class="price"]');
console.log(el ? '✅ 找到元素' : '❌ 未找到');

if (el) console.log(el.innerText);
// 测试contains匹配
let el2 = getElementByXPath('//*[contains(text(),"下一页")]');
console.log(el2 ? '✅ 找到下一页按钮' : '❌ 未找到');
1.4 批量测试多个XPath
// 测试一组XPath,返回第一个有效的
const xpaths = [
'//*[@id="price"]',
'//span[contains(@class,"price")]',
'//*[contains(text(),"¥")]'
];
for (let xp of xpaths) {
let el = getElementByXPath(xp);
if (el) {
console.log('✅ 有效XPath:', xp);
console.log(' 内容:', el.innerText);
break;
} else {
console.log('❌ 无效XPath:', xp);
}
}
第二部分:Network抓包——获取API接口数据
很多网站的数据是通过API接口加载的,直接在Network面板里可以找到这些接口,比从页面上抓取更高效。
2.1 手动抓包流程
- 打开开发者工具(F12)→ Network标签
- 刷新页面或执行操作
- 在请求列表中找到数据接口(通常是XHR/Fetch类型)
- 查看请求URL、Headers、Response
2.2 在影刀中直接调用API接口
# ============================================
# 从Network抓包获取的API直接调用
# ============================================
# 示例:淘宝商品详情API(从Network中捕获)
# URL: https://detail.tmall.com/item.htm?id=123456
# 实际数据接口: https://mdskip.taobao.com/api/...
# 在影刀中直接请求API,绕过页面渲染
HTTP请求(
方法="GET",
URL="https://mdskip.taobao.com/api/xxx?itemId=123456",
请求头={
"User-Agent": "Mozilla/5.0...",
"Referer": "https://detail.tmall.com/"
}
)
# 解析JSON响应(比从HTML提取快10倍)
响应JSON = JSON解析(HTTP响应内容)
商品价格 = 响应JSON["data"]["price"]
商品标题 = 响应JSON["data"]["title"]
2.3 用JavaScript拦截并获取页面网络请求
# ============================================
# 通过JavaScript拦截网络请求
# ============================================
执行JavaScript("""
// 拦截所有fetch请求
const originalFetch = window.fetch;
window.fetch = function(...args) {
console.log('Fetch请求:', args[0]);
// 如果请求的是数据接口,记录响应
if (args[0].includes('/api/')) {
return originalFetch.apply(this, args).then(response => {
response.clone().json().then(data => {
window.__captured_api_data = data;
});
return response;
});
}
return originalFetch.apply(this, args);
};
// 拦截所有XHR请求
const originalXHROpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
this._url = url;
return originalXHROpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(body) {
this.addEventListener('load', function() {
if (this._url && this._url.includes('/api/')) {
try {
window.__captured_xhr_data = JSON.parse(this.responseText);
} catch(e) {}
}
});
return originalXHRSend.apply(this, arguments);
};
return '拦截已启动';
""")
第三部分:Elements实时编辑——临时修复页面
3.1 在控制台中修改页面元素
有时候页面元素因为某些原因被隐藏或禁用,无法通过正常方式操作。可以在控制台中临时修改DOM。
# ============================================
# 通过JavaScript修改页面元素
# ============================================
# 场景1:移除禁用属性,让按钮可点击
执行JavaScript("""
document.querySelector('#submit-btn').disabled = false;
document.querySelector('#submit-btn').removeAttribute('disabled');
return '按钮已启用';
""")
# 场景2:显示隐藏元素
执行JavaScript("""
document.querySelector('.hidden-modal').style.display = 'block';
document.querySelector('.hidden-modal').style.visibility = 'visible';
return '元素已显示';
""")
# 场景3:修改元素文本(用于绕过文本验证)
执行JavaScript("""
document.querySelector('.error-message').innerText = '';
document.querySelector('.warning').style.display = 'none';
return '页面已修复';
""")
3.2 注入自定义CSS
# ============================================
# 注入CSS样式,让隐藏元素可见
# ============================================
执行JavaScript("""
const style = document.createElement('style');
style.textContent = `
/* 让所有隐藏元素可见(调试用) */
[style*="display:none"],
[style*="display: none"],
[hidden] {
display: block !important;
border: 3px solid red !important;
}
/* 高亮所有可点击元素 */
button, a, [role="button"] {
outline: 2px solid blue !important;
}
`;
document.head.appendChild(style);
return 'CSS已注入';
""")
3.3 通过控制台直接调用页面函数
很多网站的前端代码包含全局函数,可以在控制台中直接调用。
// 在控制台中尝试调用页面函数
// 例如:电商网站的加入购物车函数
if (typeof window.addToCart === 'function') {
window.addToCart('product_123', 2);
console.log('已调用加入购物车函数');
}
// 查找页面中的可用全局函数
let globalFuncs = Object.keys(window).filter(key => typeof window[key] === 'function');
console.log('可用函数:', globalFuncs);
第四部分:Performance分析——优化等待策略
4.1 分析页面加载关键指标
# ============================================
# 获取页面性能数据
# ============================================
执行JavaScript("""
const perfData = window.performance.timing;
const loadTime = perfData.loadEventEnd - perfData.navigationStart;
const domReady = perfData.domContentLoadedEventEnd - perfData.navigationStart;
const firstPaint = perfData.responseStart - perfData.navigationStart;
return {
totalLoad: loadTime,
domReady: domReady,
firstPaint: firstPaint,
isLoaded: loadTime > 0
};
""", 存入变量=性能数据)
输出日志("页面加载总耗时:" + 性能数据["totalLoad"] + "ms")
输出日志("DOM就绪耗时:" + 性能数据["domReady"] + "ms")
# 根据性能数据动态调整等待时间
如果 性能数据["totalLoad"] > 5000:
输出日志("页面加载较慢,增加等待时间")
设置变量(动态超时 = 15)
否则:
设置变量(动态超时 = 5)
结束If
4.2 检测页面是否有未完成的请求
# ============================================
# 检测页面是否还有未完成的网络请求
# ============================================
执行JavaScript("""
// 检查是否还有未完成的fetch/XHR请求
if (window.__pendingRequests) {
return {pending: window.__pendingRequests > 0};
}
// 通过performance API检测
const entries = performance.getEntriesByType('resource');
const incomplete = entries.filter(e =>
e.responseEnd === 0 || e.duration === 0
);
return {
pending: incomplete.length > 0,
count: incomplete.length
};
""", 存入变量=请求状态)
如果 请求状态["pending"] == True:
输出日志("还有 " + 请求状态["count"] + " 个请求未完成")
等待(2)
否则:
输出日志("所有请求已完成")
结束If
第五部分:Application存储——调试登录态
5.1 查看和管理Cookie
# ============================================
# 通过JavaScript获取所有Cookie
# ============================================
执行JavaScript("""
// 获取所有Cookie
const cookies = document.cookie.split(';').map(c => c.trim());
const cookieObj = {};
cookies.forEach(c => {
const [key, value] = c.split('=');
if (key) cookieObj[key] = decodeURIComponent(value || '');
});
return cookieObj;
""", 存入变量=Cookie对象)
输出日志("当前Cookie数量:" + 获取字典键数量(Cookie对象))
# 检查关键登录Cookie是否存在
如果 字典包含键(Cookie对象, "session_id") == True:
输出日志("会话Cookie存在,登录态有效")
否则:
输出日志("会话Cookie不存在,可能未登录")
结束If
5.2 查看LocalStorage数据
# ============================================
# 获取LocalStorage中的调试数据
# ============================================
执行JavaScript("""
// 获取所有LocalStorage数据
const keys = Object.keys(localStorage);
const data = {};
keys.forEach(key => {
try {
data[key] = JSON.parse(localStorage.getItem(key));
} catch(e) {
data[key] = localStorage.getItem(key);
}
});
return data;
""", 存入变量=本地存储数据)
# 查找特定配置项
如果 字典包含键(本地存储数据, "user_config") == True:
配置 = 本地存储数据["user_config"]
输出日志("用户配置:" + JSON序列化(配置))
结束If
第六部分:实战——自动捕获API并替代页面采集
# ============================================
# 完整实战:通过Network抓包获取商品数据
# ============================================
# 场景:采集商品价格,但不想从DOM中解析
# ----- 1. 打开商品页面 -----
打开网页("https://detail.xxx.com/item/123456", 打开方式="新建标签页")
等待(3秒)
# ----- 2. 在页面中注入请求拦截脚本 -----
执行JavaScript("""
// 拦截商品详情API
window.__productData = null;
const originalFetch = window.fetch;
window.fetch = function(...args) {
const url = args[0];
if (typeof url === 'string' && url.includes('/api/product/detail')) {
return originalFetch.apply(this, args).then(response => {
response.clone().json().then(data => {
window.__productData = data;
console.log('✅ 已捕获商品数据:', data);
});
return response;
});
}
return originalFetch.apply(this, args);
};
// 触发页面加载(如果页面还没加载完)
// 如果已经加载完,手动刷新触发请求
if (document.readyState === 'complete') {
location.reload();
}
return '拦截已启动,等待数据...';
""")
# ----- 3. 等待数据被捕获 -----
设置变量(等待次数 = 0)
条件循环(等待次数 < 30):
执行JavaScript("return window.__productData !== null;", 存入变量=数据已捕获)
如果 数据已捕获 == True:
输出日志("数据已捕获")
跳出循环
否则:
等待(1)
等待次数 = 等待次数 + 1
结束If
结束条件循环
# ----- 4. 读取捕获的数据 -----
执行JavaScript("return window.__productData;", 存入变量=商品数据)
# ----- 5. 提取关键字段 -----
解析JSON(商品数据, 存入变量=数据对象)
价格 = 数据对象["data"]["price"]
标题 = 数据对象["data"]["title"]
库存 = 数据对象["data"]["stock"]
输出日志("商品:标题=" + 标题 + ",价格=" + 价格 + ",库存=" + 库存)
第七部分:开发者工具常用快捷键
| 快捷键 | 功能 | RPA中的用途 |
|---|---|---|
F12 / Ctrl+Shift+I | 打开/关闭开发者工具 | 调试时快速打开 |
Ctrl+Shift+C | 元素选择模式 | 快速定位元素XPath |
Ctrl+F | 在元素/网络/源码中搜索 | 搜索特定XPath或接口 |
Ctrl+Shift+F | 在所有源码中搜索 | 查找页面中的JS函数 |
Ctrl+Shift+J | 打开Console面板 | 执行测试脚本 |
Ctrl+Shift+E | 打开Network面板 | 查看网络请求 |
常见问题速查
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 控制台命令在影刀中不执行 | 页面未加载完成 | 先等待页面加载 |
| 拦截不到网络请求 | 拦截代码执行太晚 | 在页面加载前注入 |
| JSON解析失败 | 响应不是JSON格式 | 检查响应类型 |
| 跨域请求被拦截 | CORS限制 | 使用浏览器环境,不单独调用 |
| 控制台命令返回值太大 | 数据量超限 | 在JavaScript中处理后再返回 |
推荐资源
- Chrome开发者工具官方文档
- 浏览器Console API文档
- 本系列第28篇《API与HTTP请求的鉴权与分页处理》
- 本系列第59篇《API数据采集与鉴权实战(淘宝/拼多多/飞书)》
#影刀RPA #RPA自动化 #开发者工具 #ChromeDevTools #JavaScript #Network
作者:林焱
本文为《影刀RPA学习手册》系列文章之一,内容源于实操经验的整理与分享。
