谷歌填表类 通过 Chrome DevTools Protocol(CDP) 控制本机 Chrome(或兼容的 Chromium / Edge),对当前附着的页面做:
- 导航、等待加载
- CSS 选择器填表 / 点击 / 取文本 / 取值
执行(JS):在页面里跑任意 JavaScript,结果转成文本返回(采集、复杂操作的主入口)
类型名必须写 谷歌填表类(扩展类库)。
目录
- 它能做什么 / 不能做什么
- 最小闭环
- 启动、连接、打开、断开
- 启动前配置
- 状态与错误
- CSS 选择器基础
- DOM 封装方法详解
- 执行(JS) 详解
- DOM 常见写法大全
- JS 常见写法大全
- 动态列表 / 直播间类页面
- 表单与登录场景
- iframe、Shadow DOM、多标签
- 与定时器配合轮询
- 方法 / 属性总表
- 常见错误与排查
- 限制与注意
1. 它能做什么 / 不能做什么
能做
| 场景 | 怎么做 |
|---|---|
| 打开网址、跳转 | 打开(url) |
| 填输入框、点按钮 | 填入 / 点击 |
| 读标签、标签文字 | 取值 / 取文本 |
| 等元素出现 | 等待出现 / 是否存在 |
| 任意页面逻辑 | 执行("…JS…") |
| 抓列表、弹幕区、用户信息(只要在页面 DOM/JS 里) | 执行 + 自己的选择器/脚本 |
读 window 上的全局状态 |
执行("JSON.stringify(window.xxx)") |
| 本机自动起带调试口的 Chrome | 连接()(或先 启动()) |
不能 / 不负责
| 点 | 说明 |
|---|---|
| 不是 HTTP 客户端 | 不会替你发「纯接口 POST」;页面表单点提交可以 |
| 没有内置「抖音弹幕类」 | 能力在 CDP + 你的 JS/选择器;平台 DOM 变了要改选择器 |
| 不管风控/封号 | 技术上能写;合规与账号风险自负 |
| 默认只附着一个页面目标 | 多标签用 打开新标签 / 连接调试地址(高级) |
填入/点击/取* 只用 querySelector(第一个匹配) |
要第 N 个、要批量,用 执行 |
2. 最小闭环
谷歌填表类 g
g.置超时(15000)
g.置端口(9333)
如果 (g.连接() == 假) {
信息框(g.错误信息)
返回()
}
如果 (g.打开("https://www.baidu.com") == 假) {
信息框(g.错误信息)
返回()
}
g.等待出现("#kw", 10000)
g.填入("#kw", "Y++")
g.点击("#su")
g.等待出现("#content_left", 12000)
输出(g.取标题())
g.断开()
推荐顺序:
- (可选)
置端口/置超时/置用户目录… 连接()— 附着调试页;本机没有调试口会自动启动 Chrome打开(网址)— 导航- DOM 操作或
执行 断开()— 只断 CDP,不强制关浏览器窗口
3. 启动、连接、打开、断开
3.1 启动() / 启动浏览器()
- 只确保本机调试口起来(必要时拉起 Chrome)
- 不附着页面、不导航
- 二者完全等价
如果 (g.启动() == 假) {
输出(g.错误信息)
}
' 之后仍须 连接() 才能填表 / 执行
3.2 连接([端口], [主机])
- 附着某个调试页的 WebSocket(CDP)
- 端口/主机省略时用
置端口/置主机 - 本机且调试口未开时:自动启动浏览器再连
- 远程主机:不会自动启动,对方必须已开
--remote-debugging-port
g.连接() ' 用默认/已置端口
g.连接(9333) ' 指定端口
g.连接(9333, "127.0.0.1")
成功后再 打开;连上时页面可能是 about:blank。
3.3 连接调试地址(调试URL)
高级:直接连 /json/list 里的 webSocketDebuggerUrl。
' url 形如 ws://127.0.0.1:9333/devtools/page/XXXX
如果 (g.连接调试地址(url) == 假) { … }
3.4 打开新标签([url], [端口], [主机])
新建标签并附着到该页;本机可自动起浏览器。
g.打开新标签("https://example.com")
g.打开新标签() ' about:blank
3.5 打开(url)
已连接后导航,并等待页面达到可交互(interactive / complete,受超时限制)。
g.打开("https://example.com/login")
g.打开("file:///D:/page.html") ' 本地文件也可(注意权限)
3.6 等待加载([毫秒])
再次等待 document.readyState;毫秒 ≤0 用会话超时。
g.打开(url)
g.等待加载(8000)
3.7 断开() / 重置()
| 方法 | 行为 |
|---|---|
断开() |
断开 CDP;浏览器窗口可继续留着 |
重置() |
断开 + 清错误;保留超时/端口等配置 |
关窗前建议先 断开(),避免残留连接。
4. 启动前配置
均须在 启动 / 连接 触发启动之前 设置才对自动拉起的进程生效。
| 方法 | 说明 |
|---|---|
置超时(毫秒) |
CDP/等待超时;≤0 回退 30000 |
置端口(端口) |
默认调试口,常用 9222 / 9333;占用时库会尝试换空闲口 |
置主机(主机) |
默认 127.0.0.1;仅本机自动启动 |
置框架(选择器) |
后续 DOM 操作限定该 iframe;空=清除(见 13.1) |
置用户目录(路径) |
--user-data-dir;空则用临时目录(按端口复用,二次启动更快) |
置缓存目录(路径) |
--disk-cache-dir |
置浏览器路径(路径) |
chrome.exe / msedge.exe 全路径;空则自动找 |
g.置超时(20000)
g.置端口(9333)
g.置用户目录("D:\\ypl_chrome_profile")
g.置缓存目录("D:\\ypl_chrome_cache")
g.置浏览器路径("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe")
g.连接()
独立用户目录的好处:不跟日常 Chrome 抢配置,调试参数不会被已开着的普通 Chrome「吞掉」。
5. 状态与错误
方法
| 方法 | 返回 | 说明 |
|---|---|---|
是否已连接() |
逻辑 | 是否仍附着 |
取错误() |
文本 | 最近一次失败原因 |
取页面URL() |
文本 | location.href(取标题前会刷新元数据) |
取标题() |
文本 | document.title |
取超时() |
整数 | 当前超时毫秒 |
属性(无括号)
| 属性 | 等价 |
|---|---|
g.是否已连接 |
是否已连接() |
g.错误信息 |
取错误() |
g.超时 |
取超时() |
g.页面URL |
取页面URL() |
g.页面标题 |
取标题() |
如果 (g.连接() == 假) {
输出(g.错误信息)
}
如果 (g.是否已连接) {
输出(g.页面标题)
}
约定:返回逻辑假 / 空文本时,先看 错误信息。
6. CSS 选择器基础
填入 / 点击 / 取文本 / 取值 / 是否存在 / 等待出现 的选择器都是 CSS,内部等价于:
document.querySelector(选择器) // 只取第一个匹配
6.1 常用写法
| 选择器 | 含义 |
|---|---|
#id |
id |
.class |
class |
input |
标签名 |
input[name=user] |
属性 |
input[type=password] |
类型 |
button[type=submit] |
提交按钮 |
form#login input.user |
后代 |
div > span |
子代 |
a[href*="login"] |
属性包含 |
[data-id="1"] |
data-* |
#list li:first-child |
伪类(视浏览器支持) |
#list li:nth-child(2) |
第 2 个子节点 |
6.2 在浏览器里怎么找选择器
- F12 → Elements
- 右键节点 → Copy → Copy selector
- 或自己写短选择器,在 Console 试:
document.querySelector('你的选择器')
6.3 选择器里的引号(Y++ 字符串)
g.填入("#user", "admin")
g.填入("input[name=password]", "123456")
g.点击("button[type=submit]")
' 选择器本身若含双引号,用单引号包属性或换写法:
g.点击("a[title='下一页']")
6.4 只要第 N 个、要全部 — 用 执行
封装方法不能写 #list li 的第 3 个;请用 JS:
文本 t = g.执行(@"(function(){
var el=document.querySelectorAll('#list li')[2];
return el?el.textContent:'';
})()")
7. DOM 封装方法详解
7.1 填入(选择器, 值) → 逻辑
对第一个匹配元素:
focus()- 设
value - 派发
input、change(bubbles)
适合:<input>、<textarea>,以及带 value 的控件。
不一定适用于高度定制的富文本 / contenteditable(改用 执行)。
如果 (g.填入("#user", "admin") == 假) {
输出(g.错误信息) ' 常见:未找到元素
}
g.填入("input[name=wd]", "关键词")
g.填入("#kw", "") ' 清空
7.2 点击(选择器) → 逻辑
对第一个匹配调用 element.click()。
g.点击("#su")
g.点击("button[type=submit]")
g.点击("a.login")
页面用 React 等且普通 click 无效时,用 执行 派发更完整的鼠标事件(见第 10 节)。
7.3 取文本(选择器) → 文本
取 textContent(含后代文字,不含输入框的 value)。
文本 tip = g.取文本("#msg")
文本 nick = g.取文本(".user-name")
7.4 取值(选择器) → 文本
取 value(输入框当前内容)。
g.填入("#kw", "QT")
文本 v = g.取值("#kw") ' "QT"
7.5 是否存在(选择器) → 逻辑
如果 (g.是否存在("#kw")) {
g.填入("#kw", "x")
}
7.6 等待出现(选择器, [毫秒]) → 逻辑
轮询直到存在或超时;毫秒 ≤0 用会话超时。等待期间会泵 UI 消息,降低假死感。
如果 (g.等待出现("#content_left", 15000) == 假) {
输出(g.错误信息)
}
典型组合:
g.打开(url)
如果 (g.等待出现("#user", 10000) == 假) { 返回() }
g.填入("#user", "a")
g.填入("#password", "b")
g.点击("#login")
g.等待出现("#welcome", 10000)
输出(g.取文本("#welcome"))
8. 执行(JS) 详解
8.1 语义
文本 结果 = g.执行(表达式)
- 在当前页面执行 JavaScript
- 返回值会转成文本(对象/数组建议自己
JSON.stringify) - 表达式为空或未连接 → 空文本,并设错误信息
底层大致是 CDP Runtime.evaluate(returnByValue),并把结果字符串化。
8.2 短表达式 vs 长脚本
短:
文本 title = g.执行("document.title")
文本 href = g.执行("location.href")
文本 n = g.执行("document.querySelectorAll('.item').length")
长脚本:用原始字符串 @"",避免转义地狱:
文本 json = g.执行(@"(function(){
var nodes = document.querySelectorAll('.chat-item');
var arr = [];
for (var i = 0; i < nodes.length; i++) {
arr.push({
text: nodes[i].innerText,
html: nodes[i].innerHTML
});
}
return JSON.stringify(arr);
})()")
8.3 必须「有返回值」
执行 要的是表达式结果。纯语句建议包成 IIFE:
' 推荐
g.执行(@"(function(){ document.body.style.zoom='1.2'; return 'ok'; })()")
' 不推荐:无返回值的语句,结果常为空或不稳定
g.执行("document.body.style.zoom='1.2'")
8.4 返回类型约定
| JS 侧 | 建议 |
|---|---|
| 字符串/数字/布尔 | 直接 return x,Y++ 收到文本 |
| 对象/数组 | return JSON.stringify(x),再用 JSON类解析 |
| DOM 元素 | 不要直接 return 节点;return 其 textContent / 属性 |
undefined |
往往变成空文本 |
8.5 与封装方法的分工
| 需求 | 优先 |
|---|---|
| 简单填一个 input | 填入 |
| 简单点一下 | 点击 |
| 第 N 个、批量、复杂条件 | 执行 |
| checkbox / select / contenteditable | 执行 |
| 读全局状态、算数据 | 执行 |
| 等元素 | 等待出现(或 JS 里轮询,一般更慢) |
9. DOM 常见写法大全
下列均可直接改选择器后使用。
9.1 读属性 / dataset / HTML
文本 href = g.执行("document.querySelector('a.more').getAttribute('href')")
文本 src = g.执行("document.querySelector('img.avatar').src")
文本 html = g.执行("document.querySelector('#panel').innerHTML")
文本 cls = g.执行("document.querySelector('#btn').className")
9.2 设置属性 / 样式
g.执行(@"(function(){
var e=document.querySelector('#kw');
if(!e) return 'no';
e.setAttribute('placeholder','请输入');
e.style.border='2px solid red';
return 'ok';
})()")
9.3 checkbox / radio
g.执行(@"(function(){
var e=document.querySelector('#agree');
if(!e) return 'no';
e.checked = true;
e.dispatchEvent(new Event('change',{bubbles:true}));
return String(e.checked);
})()")
9.4 <select> 下拉框
' 按 value
g.执行(@"(function(){
var s=document.querySelector('#city');
if(!s) return 'no';
s.value='330100';
s.dispatchEvent(new Event('change',{bubbles:true}));
return s.value;
})()")
' 按可见文本
g.执行(@"(function(){
var s=document.querySelector('#city');
if(!s) return 'no';
for (var i=0;i<s.options.length;i++){
if(s.options[i].text.indexOf('杭州')>=0){
s.selectedIndex=i;
s.dispatchEvent(new Event('change',{bubbles:true}));
return s.value;
}
}
return 'miss';
})()")
9.5 contenteditable / 富文本近似
g.执行(@"(function(){
var e=document.querySelector('[contenteditable=true]');
if(!e) return 'no';
e.focus();
e.innerText='要填的内容';
e.dispatchEvent(new InputEvent('input',{bubbles:true}));
return e.innerText;
})()")
9.6 滚动
g.执行("window.scrollTo(0, document.body.scrollHeight)")
g.执行("document.querySelector('#list').scrollTop = 99999")
g.执行(@"(function(){
var e=document.querySelector('#target');
if(e) e.scrollIntoView({behavior:'instant',block:'center'});
return e?'ok':'no';
})()")
9.7 键盘事件(回车提交等)
g.执行(@"(function(){
var e=document.querySelector('#kw');
if(!e) return 'no';
e.focus();
var ev=new KeyboardEvent('keydown',{key:'Enter',code:'Enter',keyCode:13,which:13,bubbles:true});
e.dispatchEvent(ev);
return 'ok';
})()")
9.8 更「真」的点击(React 等)
g.执行(@"(function(){
var e=document.querySelector('#su');
if(!e) return 'no';
var opts={bubbles:true,cancelable:true,view:window};
e.dispatchEvent(new MouseEvent('mousedown',opts));
e.dispatchEvent(new MouseEvent('mouseup',opts));
e.dispatchEvent(new MouseEvent('click',opts));
return 'ok';
})()")
9.9 文件选择 <input type=file>
CDP 页面脚本通常无法可靠地给 file 输入框赋本地路径(浏览器安全限制)。
若业务必须上传:优先看站点是否提供「粘贴/拖拽」或其它入口;或改用本机自动化其它方案。本类不保证 file 输入。
9.10 隐藏元素
querySelector 能选到 display:none 的节点,但 click() 可能无效。可先改样式再点,或直接调站点暴露的函数。
g.执行(@"(function(){
var e=document.querySelector('#hidden-btn');
if(!e) return 'no';
e.style.display='block';
e.click();
return 'ok';
})()")
10. JS 常见写法大全
10.1 页面信息
g.执行("document.title")
g.执行("location.href")
g.执行("location.pathname")
g.执行("document.readyState")
g.执行("document.cookie")
g.执行("navigator.userAgent")
10.2 统计数量
g.执行("document.querySelectorAll('.chat-item').length")
g.执行("document.images.length")
10.3 批量导出文本列表(JSON)
文本 批 = g.执行(@"(function(){
var list=document.querySelectorAll('.item .title');
var out=[];
for(var i=0;i<list.length;i++) out.push(list[i].innerText.trim());
return JSON.stringify(out);
})()")
10.4 带结构的对象数组
文本 批 = g.执行(@"(function(){
var rows=document.querySelectorAll('tr.data-row');
var out=[];
for(var i=0;i<rows.length;i++){
var tds=rows[i].querySelectorAll('td');
out.push({
name: tds[0]?tds[0].innerText:'',
score: tds[1]?tds[1].innerText:''
});
}
return JSON.stringify(out);
})()")
' 随后可用 JSON类 解析 批
10.5 读 / 写全局变量
文本 st = g.执行("JSON.stringify(window.__INITIAL_STATE__ || {})")
g.执行(@"(function(){ window.__MY_FLAG__=1; return String(window.__MY_FLAG__); })()")
10.6 localStorage / sessionStorage
g.执行("localStorage.getItem('token')")
g.执行(@"(function(){ localStorage.setItem('k','v'); return localStorage.getItem('k'); })()")
g.执行("JSON.stringify(sessionStorage)")
10.7 调用页面已有函数
g.执行(@"(function(){
if(typeof window.sendChat==='function'){
window.sendChat('hello');
return 'ok';
}
return 'no-fn';
})()")
10.8 fetch(页面上下文,带 Cookie)
在页面里发请求(同源 / CORS 规则跟浏览器一致):
文本 body = g.执行(@"(async function(){
var r = await fetch('/api/list',{credentials:'include'});
var t = await r.text();
return t;
})()")
注意:若运行时把 执行 当同步表达式,顶层 async 可能拿不到 Promise 结果。更稳妥:
- 站点若把数据放在 DOM/全局,优先读 DOM/全局;或
- 用同步 XHR(不推荐但有时可用):
文本 body = g.执行(@"(function(){
var xhr=new XMLHttpRequest();
xhr.open('GET','/api/list',false);
xhr.withCredentials=true;
xhr.send(null);
return xhr.responseText;
})()")
10.9 等待条件(在 JS 里短等)
长时间等待优先用 Y++ 的 等待出现 或定时器轮询 执行。JS 内短等示例:
文本 ok = g.执行(@"(function(){
var t0=Date.now();
while(Date.now()-t0<3000){
if(document.querySelector('#ready')) return '1';
}
return '0';
})()")
(会占满页面主线程几秒,慎用。)
10.10 去掉脚本 / 规范化文本
g.执行(@"(function(){
var e=document.querySelector('.msg');
return e?(e.innerText||'').replace(/\s+/g,' ').trim():'';
})()")
11. 动态列表 / 直播间类页面
没有单独的「弹幕/礼物/用户」API,但只要数据在页面上,就可以写。
11.1 流程
连接()打开(直播间或列表页 URL)(或手动打开后再连接)等待出现(列表容器选择器)- 循环或定时器里
执行抓取
11.2 抓当前全部弹幕/消息文本
函数 抓消息列表() 文本 {
返回(g.执行(@"(function(){
var nodes=document.querySelectorAll('.chat-item'); /* 改成实页选择器 */
var out=[];
for(var i=0;i<nodes.length;i++){
out.push(nodes[i].innerText);
}
return JSON.stringify(out);
})()"))
}
11.3 只取最新一条
函数 最新一条() 文本 {
返回(g.执行(@"(function(){
var nodes=document.querySelectorAll('.chat-item');
if(!nodes.length) return '';
return nodes[nodes.length-1].innerText;
})()"))
}
11.4 解析昵称 + 内容(结构示例)
文本 json = g.执行(@"(function(){
var nodes=document.querySelectorAll('.chat-item');
var out=[];
for(var i=0;i<nodes.length;i++){
var n=nodes[i];
var nameEl=n.querySelector('.nick');
var textEl=n.querySelector('.text');
out.push({
name: nameEl?nameEl.innerText:'',
text: textEl?textEl.innerText:(n.innerText||'')
});
}
return JSON.stringify(out);
})()")
11.5 礼物 / 用户列表
同理:F12 找到礼物条、在线用户节点,换成对应 class:
g.执行("document.querySelectorAll('.gift-item').length")
g.执行(@"(function(){
var u=document.querySelectorAll('.user-list .user');
var out=[];
for(var i=0;i<u.length;i++) out.push(u[i].innerText);
return JSON.stringify(out);
})()")
11.6 从全局状态读(若站点有)
文本 room = g.执行("JSON.stringify(window.__ROOM__ || window.__STORE__ || {})")
11.7 去重轮询思路
文本 上次 = ""
函数 拉增量() {
文本 现在 = 最新一条()
如果 (现在 != "" 且 现在 != 上次) {
上次 = 现在
输出(现在)
}
}
配合「第 14 节」定时器即可。
12. 表单与登录场景
12.1 经典登录
g.打开("https://example.com/login")
g.等待出现("#user", 10000)
g.填入("#user", "admin")
g.填入("#password", "secret")
g.点击("button[type=submit]")
g.等待出现("#dashboard", 15000)
输出(g.取标题())
12.2 验证码 / 二次验证
自动化填验证码依赖业务;常见做法是:等到验证码输入框出现后暂停,人工输入,再继续脚本(或接打码接口——需你自己接,本类不内置)。
12.3 多步向导
g.填入("#step1-name", "张三")
g.点击("#next")
g.等待出现("#step2", 8000)
g.填入("#step2-phone", "13800000000")
g.点击("#submit")
12.4 搜索页
g.打开("https://www.baidu.com")
g.等待出现("#kw", 8000)
g.填入("#kw", "关键词")
g.点击("#su")
g.等待出现("#content_left", 12000)
输出(g.取标题())
13. iframe、Shadow DOM、多标签
13.1 iframe(穿透框架)
填入 / 点击 / 取文本 / 取值 / 是否存在 / 等待出现 已支持同源框架:
- 未置框架:先查顶层
document;找不到再递归穿透所有同源iframe/frame(含嵌套)。 - 置框架(选择器):之后上述 API 都只在该框架内操作,直到
清除框架()或再次打开(导航会自动清框架)。 - 框架填入 / 框架点击 / …:一次性指定框架,不改会话里的「置框架」。
' 方式 A:自动穿透(常见登录框在同源 iframe 里)
g.填入("#user", "admin")
g.点击("button[type=submit]")
' 方式 B:先锁定框架,再连续操作
g.置框架("iframe#login")
g.填入("#user", "admin")
g.填入("#password", "123")
g.点击("button.submit")
g.清除框架()
' 方式 C:一次性指定
g.框架填入("iframe#main", "#user", "admin")
g.框架点击("iframe#main", "button.submit")
文本 t = g.框架取文本("iframe#main", "#msg")
限制:
- 跨域 iframe 读不了
contentDocument(浏览器同源策略),会报「跨域框架无法穿透」。 - 框架尚未加载完可能「框架无文档」——先
等待出现或稍后再试。 - Shadow DOM 仍需
执行(见 13.2)。
仍可用手动 执行(复杂场景):
g.执行(@"(function(){
var f=document.querySelector('iframe#main');
if(!f||!f.contentDocument) return 'no-frame';
var e=f.contentDocument.querySelector('#user');
if(!e) return 'no-el';
e.value='admin';
e.dispatchEvent(new Event('input',{bubbles:true}));
return 'ok';
})()")
13.2 Shadow DOM
g.执行(@"(function(){
var host=document.querySelector('my-widget');
if(!host||!host.shadowRoot) return 'no-shadow';
var e=host.shadowRoot.querySelector('input');
if(!e) return 'no-el';
e.value='x';
return e.value;
})()")
13.3 多标签
打开新标签(url):新标签并附着- 或浏览器
/json/list取其它页的webSocketDebuggerUrl,再连接调试地址 - 一次会话通常只附着一个 page target;切换标签需重新连接对应调试 URL
14. 与定时器配合轮询
谷歌填表类 g
定时器类 tm
文本 上次弹幕 = ""
函数 拉弹幕() {
如果 (g.是否已连接 == 假) { 返回() }
文本 现 = g.执行(@"(function(){
var n=document.querySelectorAll('.chat-item');
if(!n.length) return '';
return n[n.length-1].innerText;
})()")
如果 (现 != "" 且 现 != 上次弹幕) {
上次弹幕 = 现
输出(现)
}
}
函数 主窗口.创建完毕() {
g.置端口(9333)
如果 (g.连接() == 假) { 信息框(g.错误信息) 返回() }
g.打开("你的页面地址")
g.等待出现(".chat-item", 60000)
tm.启动(1000, &拉弹幕) ' 每秒拉一次;方法名以你工程定时器类为准
}
(定时器类具体 API 见扩展类库文档;此处表达的是「周期调用 执行」模式。)
15. 方法 / 属性总表
配置
| 签名 | 返回 |
|---|---|
置超时([整数 毫秒=30000]) |
无 |
取超时() |
整数 |
置用户目录(文本 路径) |
无 |
置缓存目录(文本 路径) |
无 |
置浏览器路径(文本 路径) |
无 |
置端口([整数 端口=9222]) |
无 |
置主机([文本 主机="127.0.0.1"]) |
无 |
置框架([文本 框架选择器=""]) |
无 |
清除框架() |
无 |
取框架() |
文本 |
生命周期
| 签名 | 返回 |
|---|---|
启动() / 启动浏览器() |
逻辑 |
连接([整数 端口=0], [文本 主机=""]) |
逻辑 |
连接调试地址(文本 调试URL) |
逻辑 |
打开新标签([文本 url], [整数 端口], [文本 主机]) |
逻辑 |
断开() |
无 |
重置() |
无 |
是否已连接() |
逻辑 |
导航与等待
| 签名 | 返回 |
|---|---|
打开(文本 url) |
逻辑 |
等待加载([整数 毫秒=0]) |
逻辑 |
等待出现(文本 选择器, [整数 毫秒=0]) |
逻辑 |
是否存在(文本 选择器) |
逻辑 |
DOM
| 签名 | 返回 |
|---|---|
填入(文本 选择器, 文本 值) |
逻辑 |
点击(文本 选择器) |
逻辑 |
取文本(文本 选择器) |
文本 |
取值(文本 选择器) |
文本 |
框架(iframe)
| 签名 | 返回 |
|---|---|
置框架([文本 框架选择器=""]) |
无 |
清除框架() |
无 |
取框架() |
文本 |
框架填入(文本 框架选择器, 文本 选择器, 文本 值) |
逻辑 |
框架点击(文本 框架选择器, 文本 选择器) |
逻辑 |
框架取文本(文本 框架选择器, 文本 选择器) |
文本 |
框架取值(文本 框架选择器, 文本 选择器) |
文本 |
框架是否存在(文本 框架选择器, 文本 选择器) |
逻辑 |
框架等待出现(文本 框架选择器, 文本 选择器, [整数 毫秒=0]) |
逻辑 |
详见第 13.1 节。
JS / 状态
| 签名 | 返回 |
|---|---|
执行(文本 表达式) |
文本 |
取错误() |
文本 |
取页面URL() |
文本 |
取标题() |
文本 |
属性
超时、错误信息、是否已连接、页面URL、页面标题(见第 5 节)。
16. 常见错误与排查
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 连接失败 / 调试口未就绪 | 端口被占、Chrome 未开调试 | 换 置端口;结束残留 chrome;看错误信息 |
| 窗口「未响应」 | 旧版本阻塞 connect | 更新运行时库 |
填入/点击 假 |
选择器错、未加载完、跨域框架 | F12 验证;先 等待出现;同源用 置框架/框架填入 |
执行 空 |
表达式无返回值、JS 抛错 | IIFE + return;先在 Console 试 |
| 点了没反应 | 框架拦截了 click | 第 9.8 节完整鼠标事件 |
| iframe 里填不了 | 跨域,或框架未加载 | 第 13.1 节;同源用穿透/置框架 |
| 日常 Chrome 已开,调试参数无效 | 单例合并 | 用 置用户目录 独立配置 |
| 组件 [g] 不存在 | 写成了控件方法如 打开开发者工具 |
用本类的 打开 / 执行 |
手动验证调试口:
浏览器打开:http://127.0.0.1:9333/json/version(端口按你的设置),应返回 JSON。
17. 限制与注意
- 下标 / 多元素:封装 API 只打第一个
querySelector;批量用执行。 - 加载策略:
打开在interactive/complete即可继续,不等无穷长资源。 - 断开 ≠ 关浏览器:只断 CDP。
- 本机 CDP:
ws://127.0.0.1:端口/...,不走系统代理。 - 安全:
执行能跑任意页面 JS,等同你在 Console 操作。 - 合规:抓取直播/用户数据须遵守平台协议与法律;文档只讲技术写法。
附录 A — 一页速查
谷歌填表类 g
g.置超时(15000)
g.置端口(9333)
g.连接()
g.打开(url)
g.等待出现(sel, ms)
g.填入(sel, 值)
g.点击(sel)
g.取文本(sel)
g.取值(sel)
g.执行("JS 表达式")
g.取标题()
g.错误信息
g.断开()
附录 B — 相关文档
- 自定义类型嵌套(若要把抓到的 JSON 映到结构体):usertype.md、examples/usertype/09-多层嵌套与下标链.md