init: Web-Access Skill 源码解析研究页

- 克隆 eze-is/web-access 完整源码
- 创建功能说明网页(架构、API、对比、评估)
- 端口 4310

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 14:36:22 +08:00
parent 9f78c6d6d8
commit 2686d94ab6
2 changed files with 843 additions and 36 deletions

View File

@@ -1,46 +1,852 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web-Access Skill 源码解析</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #0a0a0a; color: #e0e0e0;
min-height: 100vh; padding: 2rem;
}
.container { max-width: 1200px; margin: 0 auto; }
h1 {
font-size: 2.5rem; font-weight: 700;
background: linear-gradient(135deg, #60a5fa, #a78bfa);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
margin-bottom: 0.5rem;
}
.subtitle { color: #888; font-size: 1.1rem; margin-bottom: 2rem; }
.card {
background: #141414; border: 1px solid #222; border-radius: 12px;
padding: 2rem; margin-bottom: 1.5rem;
}
.card h2 { color: #60a5fa; margin-bottom: 1rem; font-size: 1.3rem; }
.card p { line-height: 1.8; color: #aaa; }
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web-Access Skill - 源码解析与功能说明</title>
<style>
:root {
--bg: #0a0a0f;
--surface: #12121a;
--surface2: #1a1a26;
--border: #2a2a3a;
--text: #e0e0e8;
--text2: #888899;
--accent: #6c5ce7;
--accent2: #a855f7;
--green: #10b981;
--orange: #f59e0b;
--red: #ef4444;
--blue: #3b82f6;
--cyan: #06b6d4;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.7;
overflow-x: hidden;
}
/* Hero */
.hero {
position: relative;
min-height: 50vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 80px 24px 60px;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(ellipse at 50% 50%, rgba(108,92,231,0.08) 0%, transparent 60%),
radial-gradient(ellipse at 20% 80%, rgba(168,85,247,0.06) 0%, transparent 50%);
animation: drift 20s ease-in-out infinite alternate;
}
@keyframes drift {
0% { transform: translate(0, 0) rotate(0deg); }
100% { transform: translate(-30px, 20px) rotate(2deg); }
}
.hero-content { position: relative; z-index: 1; }
.hero h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 800;
letter-spacing: -0.03em;
background: linear-gradient(135deg, #e0e0e8, #a855f7, #6c5ce7);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 16px;
}
.hero .subtitle {
font-size: 1.15rem;
color: var(--text2);
max-width: 600px;
margin: 0 auto 32px;
}
.badge-row {
display: flex;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
}
.badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
border-radius: 20px;
font-size: 0.82rem;
font-weight: 600;
border: 1px solid var(--border);
background: var(--surface);
}
.badge .dot {
width: 8px;
height: 8px;
border-radius: 50%;
display: inline-block;
}
.badge .dot.green { background: var(--green); }
.badge .dot.orange { background: var(--orange); }
.badge .dot.blue { background: var(--blue); }
.badge .dot.purple { background: var(--accent2); }
/* Container */
.container {
max-width: 1100px;
margin: 0 auto;
padding: 0 24px;
}
/* Section */
section {
margin-bottom: 64px;
}
.section-title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 24px;
display: flex;
align-items: center;
gap: 10px;
}
.section-title .icon {
width: 32px;
height: 32px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
flex-shrink: 0;
}
/* Cards */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
transition: border-color 0.2s, transform 0.2s;
}
.card:hover {
border-color: var(--accent);
transform: translateY(-2px);
}
.card h3 {
font-size: 1.05rem;
font-weight: 700;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 8px;
}
.card p, .card li {
font-size: 0.92rem;
color: var(--text2);
line-height: 1.7;
}
.card ul {
list-style: none;
padding-left: 0;
}
.card ul li::before {
content: '>';
color: var(--accent);
margin-right: 8px;
font-weight: bold;
font-family: monospace;
}
/* Architecture diagram */
.arch-box {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 32px;
overflow-x: auto;
}
.arch-flow {
display: flex;
align-items: center;
justify-content: center;
gap: 0;
flex-wrap: wrap;
padding: 16px 0;
}
.arch-node {
background: var(--surface2);
border: 1px solid var(--border);
border-radius: 10px;
padding: 16px 20px;
text-align: center;
min-width: 140px;
transition: border-color 0.2s;
}
.arch-node:hover { border-color: var(--accent2); }
.arch-node .label {
font-size: 0.78rem;
color: var(--text2);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 6px;
}
.arch-node .name {
font-size: 1rem;
font-weight: 700;
}
.arch-arrow {
color: var(--accent);
font-size: 1.3rem;
padding: 0 12px;
flex-shrink: 0;
}
/* API Table */
.api-table-wrap {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
}
.api-table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
.api-table th {
background: var(--surface2);
padding: 12px 16px;
text-align: left;
font-weight: 700;
font-size: 0.82rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text2);
border-bottom: 1px solid var(--border);
}
.api-table td {
padding: 10px 16px;
border-bottom: 1px solid var(--border);
vertical-align: top;
}
.api-table tr:last-child td { border-bottom: none; }
.api-table tr:hover td { background: rgba(108,92,231,0.04); }
.method-badge {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 700;
font-family: monospace;
}
.method-badge.get { background: rgba(16,185,129,0.15); color: var(--green); }
.method-badge.post { background: rgba(59,130,246,0.15); color: var(--blue); }
code, .mono {
font-family: 'SF Mono', 'Fira Code', monospace;
font-size: 0.85em;
background: var(--surface2);
padding: 2px 6px;
border-radius: 4px;
color: var(--cyan);
}
/* File tree */
.file-tree {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
font-family: 'SF Mono', 'Fira Code', monospace;
font-size: 0.88rem;
line-height: 2;
}
.file-tree .dir { color: var(--accent2); }
.file-tree .file { color: var(--text2); }
.file-tree .comment { color: #555566; font-style: italic; }
/* Comparison */
.compare-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 700px) {
.compare-grid { grid-template-columns: 1fr; }
}
.compare-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
}
.compare-card h3 {
font-size: 1rem;
font-weight: 700;
margin-bottom: 12px;
}
.compare-card.highlight {
border-color: var(--accent);
background: linear-gradient(135deg, var(--surface), rgba(108,92,231,0.05));
}
.tag {
display: inline-block;
padding: 3px 10px;
border-radius: 6px;
font-size: 0.78rem;
font-weight: 600;
margin-bottom: 8px;
}
.tag.green { background: rgba(16,185,129,0.15); color: var(--green); }
.tag.red { background: rgba(239,68,68,0.15); color: var(--red); }
.tag.purple { background: rgba(168,85,247,0.15); color: var(--accent2); }
.stat-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 12px;
margin-bottom: 24px;
}
.stat-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 10px;
padding: 18px;
text-align: center;
}
.stat-card .num {
font-size: 1.8rem;
font-weight: 800;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.stat-card .label {
font-size: 0.82rem;
color: var(--text2);
margin-top: 4px;
}
/* Philosophy */
.philosophy-steps {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}
.step-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
position: relative;
}
.step-num {
position: absolute;
top: -12px;
left: 20px;
background: var(--accent);
color: white;
width: 28px;
height: 28px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.82rem;
font-weight: 800;
}
.step-card h4 {
margin-top: 8px;
margin-bottom: 8px;
font-size: 0.95rem;
}
.step-card p {
font-size: 0.85rem;
color: var(--text2);
}
/* Code block */
.code-block {
background: #0d0d15;
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px;
overflow-x: auto;
font-family: 'SF Mono', 'Fira Code', monospace;
font-size: 0.85rem;
line-height: 1.8;
color: var(--text2);
margin: 16px 0;
}
.code-block .kw { color: var(--accent2); }
.code-block .str { color: var(--green); }
.code-block .cmt { color: #555566; }
.code-block .fn { color: var(--cyan); }
/* Footer */
footer {
border-top: 1px solid var(--border);
padding: 32px 24px;
text-align: center;
color: var(--text2);
font-size: 0.85rem;
}
footer a {
color: var(--accent2);
text-decoration: none;
}
a { color: var(--accent2); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Verdict */
.verdict-box {
background: linear-gradient(135deg, var(--surface), rgba(108,92,231,0.06));
border: 1px solid var(--accent);
border-radius: 12px;
padding: 28px;
}
.verdict-box h3 {
font-size: 1.15rem;
font-weight: 700;
margin-bottom: 12px;
}
.verdict-box p, .verdict-box li {
font-size: 0.92rem;
color: var(--text2);
line-height: 1.8;
}
.verdict-box ul {
padding-left: 20px;
margin: 8px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>Web-Access Skill 源码解析</h1>
<p class="subtitle">Claude Code 联网增强 Skill 源码分析与功能说明</p>
<div class="card">
<h2>概述</h2>
<p>待补充研究内容...</p>
</div>
<div class="card">
<h2>核心发现</h2>
<p>待补充...</p>
<!-- Hero -->
<header class="hero">
<div class="hero-content">
<h1>Web-Access Skill</h1>
<p class="subtitle">
Claude Code 联网增强 Skill &mdash; 三层通道调度 + CDP 浏览器自动化 + 站点经验积累
</p>
<div class="badge-row">
<span class="badge"><span class="dot green"></span> v2.4.1</span>
<span class="badge"><span class="dot orange"></span> 1,800+ Stars</span>
<span class="badge"><span class="dot blue"></span> MIT License</span>
<span class="badge"><span class="dot purple"></span> by 一泽 Eze</span>
</div>
</div>
</header>
<div class="container">
<!-- Stats -->
<div class="stat-row">
<div class="stat-card">
<div class="num">5</div>
<div class="label">联网通道</div>
</div>
<div class="stat-card">
<div class="num">14</div>
<div class="label">CDP API 端点</div>
</div>
<div class="stat-card">
<div class="num">573</div>
<div class="label">行核心代码</div>
</div>
<div class="stat-card">
<div class="num">29</div>
<div class="label">Commits</div>
</div>
<div class="stat-card">
<div class="num">0</div>
<div class="label">外部依赖</div>
</div>
</div>
<!-- Architecture -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(108,92,231,0.15)">&#9881;</span>
架构总览
</h2>
<div class="arch-box">
<div class="arch-flow">
<div class="arch-node">
<div class="label">用户指令</div>
<div class="name">Claude Code</div>
</div>
<div class="arch-arrow">&rarr;</div>
<div class="arch-node" style="border-color:var(--accent)">
<div class="label">决策层</div>
<div class="name">SKILL.md</div>
</div>
<div class="arch-arrow">&rarr;</div>
<div class="arch-node">
<div class="label">通道选择</div>
<div class="name" style="font-size:0.85rem">WebSearch / WebFetch<br>curl / Jina / CDP</div>
</div>
<div class="arch-arrow">&rarr;</div>
<div class="arch-node">
<div class="label">浏览器层</div>
<div class="name">cdp-proxy.mjs</div>
</div>
<div class="arch-arrow">&rarr;</div>
<div class="arch-node" style="border-color:var(--green)">
<div class="label">目标</div>
<div class="name">用户 Chrome</div>
</div>
</div>
<p style="text-align:center;color:var(--text2);font-size:0.85rem;margin-top:16px;">
SKILL.md 提供策略哲学 &rarr; AI 自主推理选通道 &rarr; CDP Proxy 通过 WebSocket 直连 Chrome
</p>
</div>
</section>
<!-- Core Capabilities -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(16,185,129,0.15)">&#9733;</span>
核心能力
</h2>
<div class="card-grid">
<div class="card">
<h3>&#128268; 智能通道调度</h3>
<p>根据任务场景自动选择最优联网方式:</p>
<ul>
<li><strong>WebSearch</strong> &mdash; 搜索摘要、关键词结果</li>
<li><strong>WebFetch</strong> &mdash; 已知 URL 定向提取信息</li>
<li><strong>curl</strong> &mdash; 需要原始 HTML/JSON-LD</li>
<li><strong>Jina</strong> &mdash; 网页转 Markdown省 token</li>
<li><strong>CDP 浏览器</strong> &mdash; 动态页面、登录态</li>
</ul>
</div>
<div class="card">
<h3>&#127760; CDP 浏览器操作</h3>
<p>直连用户日常 Chrome天然携带所有登录态。通过 HTTP API 提供:</p>
<ul>
<li>新建/关闭 Tab导航、后退</li>
<li>执行任意 JavaScript</li>
<li>JS 点击 + CDP 真实鼠标事件</li>
<li>文件上传(绕过文件对话框)</li>
<li>截图(含视频当前帧)</li>
<li>滚动触发懒加载</li>
</ul>
</div>
<div class="card">
<h3>&#9889; 并行分治</h3>
<p>多目标任务自动分发子 Agent 并行执行:</p>
<ul>
<li>共享一个 Chrome + Proxy</li>
<li>Tab 级隔离,无竞态风险</li>
<li>抓取内容不进主 Agent 上下文</li>
<li>总耗时 &asymp; 单任务时长</li>
</ul>
</div>
<div class="card">
<h3>&#128218; 站点经验积累</h3>
<p>按域名存储操作经验,跨 session 复用:</p>
<ul>
<li>URL 模式、平台特征、已知陷阱</li>
<li>小红书 xsec_token 机制</li>
<li>自动匹配目标站点经验</li>
<li>操作成功后自动更新经验</li>
</ul>
</div>
<div class="card">
<h3>&#127909; 媒体提取</h3>
<p>从 DOM 直取图片/视频 URL或对视频进行定点截帧分析</p>
<ul>
<li>eval 操控 &lt;video&gt; 元素</li>
<li>seek 到任意时间点 + screenshot</li>
<li>图片 URL 直接提取,无需全页截图</li>
</ul>
</div>
<div class="card">
<h3>&#128270; 信息核实</h3>
<p>追溯一手来源而非二手报道:</p>
<ul>
<li>政策法规 &rarr; 发布机构官网</li>
<li>企业公告 &rarr; 公司官方页面</li>
<li>学术声明 &rarr; 原始论文</li>
<li>避免循环引证假象</li>
</ul>
</div>
</div>
</section>
<!-- File Structure -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(59,130,246,0.15)">&#128193;</span>
源码结构
</h2>
<div class="file-tree">
<span class="dir">web-access/</span><br>
&nbsp;&nbsp;<span class="file">SKILL.md</span> <span class="comment">&larr; 核心:联网策略 + 浏览哲学 + API 指引371 行AI 的"大脑"</span><br>
&nbsp;&nbsp;<span class="file">README.md</span> <span class="comment">&larr; 项目说明 + 安装指南</span><br>
&nbsp;&nbsp;<span class="dir">scripts/</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="file">cdp-proxy.mjs</span> <span class="comment">&larr; CDP Proxy 服务器573 行 JS零外部依赖</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="file">check-deps.sh</span> <span class="comment">&larr; 环境检查 + 自动启动 Proxy</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="file">match-site.sh</span> <span class="comment">&larr; 站点经验匹配脚本</span><br>
&nbsp;&nbsp;<span class="dir">references/</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="file">cdp-api.md</span> <span class="comment">&larr; CDP API 详细参考文档</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="dir">site-patterns/</span> <span class="comment">&larr; 站点经验文件(按域名存储)</span><br>
</div>
</section>
<!-- CDP Proxy API -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(6,182,212,0.15)">&#128640;</span>
CDP Proxy API &mdash; 14 个端点
</h2>
<p style="color:var(--text2);margin-bottom:16px;font-size:0.92rem">
Proxy 监听 <code>localhost:3456</code>,通过 WebSocket 直连 Chrome DevTools Protocol所有操作通过 curl 调用。
</p>
<div class="api-table-wrap">
<table class="api-table">
<thead>
<tr><th>端点</th><th>方法</th><th>功能</th></tr>
</thead>
<tbody>
<tr><td><code>/health</code></td><td><span class="method-badge get">GET</span></td><td>健康检查,返回连接状态</td></tr>
<tr><td><code>/targets</code></td><td><span class="method-badge get">GET</span></td><td>列出所有已打开的页面 Tab</td></tr>
<tr><td><code>/new?url=</code></td><td><span class="method-badge get">GET</span></td><td>创建新后台 Tab自动等待加载完成</td></tr>
<tr><td><code>/close?target=</code></td><td><span class="method-badge get">GET</span></td><td>关闭指定 Tab</td></tr>
<tr><td><code>/navigate?target=&url=</code></td><td><span class="method-badge get">GET</span></td><td>在已有 Tab 中导航(自动等待加载)</td></tr>
<tr><td><code>/back?target=</code></td><td><span class="method-badge get">GET</span></td><td>后退一页</td></tr>
<tr><td><code>/info?target=</code></td><td><span class="method-badge get">GET</span></td><td>获取页面 title / URL / readyState</td></tr>
<tr><td><code>/eval?target=</code></td><td><span class="method-badge post">POST</span></td><td>执行任意 JS 表达式,支持 async</td></tr>
<tr><td><code>/click?target=</code></td><td><span class="method-badge post">POST</span></td><td>JS 层面点击el.click()</td></tr>
<tr><td><code>/clickAt?target=</code></td><td><span class="method-badge post">POST</span></td><td>CDP 真实鼠标事件(绕过反自动化)</td></tr>
<tr><td><code>/setFiles?target=</code></td><td><span class="method-badge post">POST</span></td><td>文件上传(绕过文件对话框)</td></tr>
<tr><td><code>/scroll?target=&y=</code></td><td><span class="method-badge get">GET</span></td><td>滚动页面(触发懒加载,等待 800ms</td></tr>
<tr><td><code>/screenshot?target=&file=</code></td><td><span class="method-badge get">GET</span></td><td>截图保存到文件或返回二进制</td></tr>
</tbody>
</table>
</div>
</section>
<!-- Design Philosophy -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(245,158,11,0.15)">&#128161;</span>
设计哲学
</h2>
<p style="color:var(--text2);margin-bottom:20px;font-size:0.92rem">
<strong>"Skill = 哲学 + 技术事实,不是操作手册。"</strong> 讲清 tradeoff 让 AI 自己选,不替它推理。
</p>
<div class="philosophy-steps">
<div class="step-card">
<span class="step-num">1</span>
<h4>拿到请求</h4>
<p>明确用户要做什么,定义成功标准:什么算完成?需要获取什么信息、达到什么结果?这是后续所有判断的锚点。</p>
</div>
<div class="step-card">
<span class="step-num">2</span>
<h4>选择起点</h4>
<p>根据任务性质、平台特征,选最可能直达的方式作为第一步去验证。需要登录态/动态页面 &rarr; 直接 CDP。</p>
</div>
<div class="step-card">
<span class="step-num">3</span>
<h4>过程校验</h4>
<p>每一步结果都是证据。对照成功标准更新判断。方向错了立即调整,不在同一方式上反复重试。</p>
</div>
<div class="step-card">
<span class="step-num">4</span>
<h4>完成判断</h4>
<p>对照成功标准确认完成后才停止。不为了"完整"而浪费代价,也不因为"差不多"而提前放弃。</p>
</div>
</div>
</section>
<!-- Comparison -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(239,68,68,0.15)">&#9878;</span>
对比web-access vs 现有工具
</h2>
<div class="compare-grid">
<div class="compare-card">
<span class="tag green">已有</span>
<h3>Claude Code 原生 + Playwright MCP + gptr</h3>
<ul style="list-style:none;padding:0;font-size:0.9rem;color:var(--text2)">
<li style="margin-bottom:6px">&#10003; WebSearch / WebFetch 基础联网</li>
<li style="margin-bottom:6px">&#10003; Playwright 完整浏览器自动化</li>
<li style="margin-bottom:6px">&#10003; gptr 深度调研出报告</li>
<li style="margin-bottom:6px">&#10007; 每次启动全新浏览器,无登录态</li>
<li style="margin-bottom:6px">&#10007; 需手动判断该用哪个工具</li>
<li>&#10007; 无站点经验积累</li>
</ul>
</div>
<div class="compare-card highlight">
<span class="tag purple">web-access 增量价值</span>
<h3>CDP 直连 + 策略调度 + 经验复用</h3>
<ul style="list-style:none;padding:0;font-size:0.9rem;color:var(--text2)">
<li style="margin-bottom:6px">&#9733; <strong>直连用户 Chrome 登录态</strong>(核心差异)</li>
<li style="margin-bottom:6px">&#9733; AI 自主选通道,无需手动指定</li>
<li style="margin-bottom:6px">&#9733; 站点经验跨 session 复用</li>
<li style="margin-bottom:6px">&#9733; 零外部依赖573 行代码</li>
<li style="margin-bottom:6px">&#9733; 子 Agent 并行分治</li>
<li>&#9733; 视频截帧分析能力</li>
</ul>
</div>
</div>
</section>
<!-- Code Highlight -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(168,85,247,0.15)">&lt;/&gt;</span>
技术亮点
</h2>
<div class="card-grid">
<div class="card">
<h3>&#128268; 零依赖设计</h3>
<p>整个 CDP Proxy 仅使用 Node.js 原生模块:<code>http</code><code>url</code><code>fs</code><code>net</code><code>os</code>
Node 22+ 的原生 WebSocket 替代了 <code>ws</code> 模块,做到真正零 <code>npm install</code></p>
</div>
<div class="card">
<h3>&#128270; 自动发现 Chrome 端口</h3>
<p>不需要用户手动指定端口。自动读取 <code>DevToolsActivePort</code> 文件获取端口和 WebSocket 路径,
支持 macOS / Linux / Windows 三平台。回退扫描 9222、9229、9333 常用端口。</p>
</div>
<div class="card">
<h3>&#128737; 防重复启动</h3>
<p>启动时先用 TCP 探测端口是否被占用。若已有实例运行且健康(<code>/health</code> 返回 ok静默退出。
避免多个 Proxy 实例冲突。</p>
</div>
<div class="card">
<h3>&#128200; 站点经验匹配</h3>
<p><code>match-site.sh</code> 读取用户输入,遍历 <code>site-patterns/*.md</code> 文件,
用域名 + aliases 做模式匹配,自动输出相关站点经验。跨会话积累,越用越聪明。</p>
</div>
</div>
<div class="code-block">
<span class="cmt">// cdp-proxy.mjs 核心连接逻辑(简化)</span><br>
<span class="kw">async function</span> <span class="fn">discoverChromePort</span>() {<br>
&nbsp;&nbsp;<span class="cmt">// 1. 读 DevToolsActivePort 文件获取端口</span><br>
&nbsp;&nbsp;<span class="kw">for</span> (<span class="kw">const</span> p <span class="kw">of</span> possiblePaths) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">const</span> port = <span class="fn">parseInt</span>(fs.<span class="fn">readFileSync</span>(p));<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="kw">if</span> (<span class="kw">await</span> <span class="fn">checkPort</span>(port)) <span class="kw">return</span> { port, wsPath };<br>
&nbsp;&nbsp;}<br>
&nbsp;&nbsp;<span class="cmt">// 2. 回退扫描常用端口 [9222, 9229, 9333]</span><br>
}<br><br>
<span class="cmt">// HTTP API &rarr; CDP WebSocket &rarr; Chrome</span><br>
<span class="kw">function</span> <span class="fn">sendCDP</span>(method, params, sessionId) {<br>
&nbsp;&nbsp;ws.<span class="fn">send</span>(JSON.<span class="fn">stringify</span>({ id: ++cmdId, method, params, sessionId }));<br>
}
</div>
</section>
<!-- Verdict -->
<section>
<h2 class="section-title">
<span class="icon" style="background:rgba(108,92,231,0.15)">&#128203;</span>
评估结论
</h2>
<div class="verdict-box">
<h3>适合安装的场景</h3>
<ul>
<li>需要 Claude Code 操作<strong>已登录的网站</strong>(后台管理、社交平台、内部系统)</li>
<li>经常访问<strong>反爬严格的站点</strong>(小红书、微信公众号等)</li>
<li>希望联网操作<strong>更智能</strong>,不用手动选 WebFetch 还是 Playwright</li>
<li>需要<strong>视频截帧分析</strong>或复杂的浏览器交互</li>
</ul>
<h3 style="margin-top:16px">不需要安装的场景</h3>
<ul>
<li>现有 WebFetch + Playwright + gptr 已满足需求</li>
<li>不需要操作需登录的网站</li>
<li>主要做代码开发,联网需求少</li>
</ul>
<p style="margin-top:16px;padding:12px 16px;background:rgba(108,92,231,0.08);border-radius:8px;font-size:0.92rem">
<strong>核心价值:</strong>一句话总结 &mdash; web-access 的不可替代优势是<strong>直连用户 Chrome 登录态</strong>
其余能力搜索、抓取、浏览器操作在现有工具链中已有覆盖web-access 做的是<strong>更聪明的调度 + 更省心的体验</strong>
</p>
</div>
</section>
</div>
<footer>
<p>
源码仓库:<a href="https://github.com/eze-is/web-access" target="_blank">eze-is/web-access</a>
&nbsp;&middot;&nbsp; 作者:<a href="https://github.com/eze-is" target="_blank">一泽 Eze</a>
&nbsp;&middot;&nbsp; 许可证MIT
</p>
<p style="margin-top:8px;color:#555">研究存档 &middot; 2026-03-27</p>
</footer>
</body>
</html>

1
source Submodule

Submodule source added at 1116c082a7