Files
universal-crawler/static/index.html
T

218 lines
10 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>通用爬虫系统</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<div class="logo">🕷️ 通用爬虫系统 <span id="version" class="version"></span></div>
<div class="header-right">
<div class="search-box">
<input id="searchInput" placeholder="搜索网址 / 标题 / 任务名..." maxlength="100">
<button id="btnSearch" class="btn sm primary" title="搜索">🔍</button>
</div>
<span class="status-pill" id="statusPill">运行中任务: 0</span>
<button id="btnTheme" class="btn ghost" title="切换日间/夜间主题">☀️</button>
<button id="btnTrash" class="btn ghost" title="回收站">🗑️ 回收站 <span id="trashCount" class="trash-count">0</span></button>
<button id="btnRefresh" class="btn ghost">⟳ 刷新</button>
<button id="btnNew" class="btn primary"> 新建任务</button>
</div>
</header>
<main>
<div class="stats-bar" id="statsBar">
<div class="stat-card"><div class="stat-num" id="stTasks">0</div><div class="stat-label">📋 任务总数</div></div>
<div class="stat-card"><div class="stat-num num-run" id="stRunning">0</div><div class="stat-label">🔄 正在运行</div></div>
<div class="stat-card"><div class="stat-num" id="stRuns">0</div><div class="stat-label">📊 累计运行次数</div></div>
<div class="stat-card"><div class="stat-num num-ok" id="stOk">0</div><div class="stat-label">✅ 成功页面</div></div>
<div class="stat-card"><div class="stat-num num-fail" id="stFail">0</div><div class="stat-label">❌ 失败页面</div></div>
<div class="stat-card"><div class="stat-num" id="stImgs">0</div><div class="stat-label">🖼️ 已爬图片</div></div>
<div class="stat-card"><div class="stat-num" id="stDisk">0</div><div class="stat-label">💾 磁盘占用</div></div>
</div>
<div id="taskList" class="task-grid"></div>
<div id="emptyState" class="empty hidden">
<div class="empty-icon">🕸️</div>
<p>还没有爬取任务</p>
<button id="btnNew2" class="btn primary"> 创建第一个任务</button>
</div>
</main>
<!-- 新建 / 编辑任务弹窗 -->
<div id="taskModal" class="modal-overlay hidden">
<div class="modal">
<div class="modal-head">
<span id="modalTitle">新建爬取任务</span>
<button class="btn ghost sm" data-close></button>
</div>
<div class="tabs" id="modeTabs">
<button class="tab active" data-mode="batch">📄 批量爬取</button>
<button class="tab" data-mode="scheduled">⏰ 定时爬取</button>
<button class="tab" data-mode="auto">🤖 自动爬取</button>
</div>
<form id="taskForm">
<div class="form-body">
<div class="field"><label>项目名称 *</label><input name="name" required placeholder="例如: TPU 评测抓取"></div>
<div class="field"><label>输出目录</label><input name="out_dir" placeholder="留空自动: out/任务ID;可填绝对路径"></div>
<div class="row2">
<div class="field"><label>爬取间隔(秒) 最小</label><input name="delay_min" type="number" min="0.1" step="0.1" value="2"></div>
<div class="field"><label>最大</label><input name="delay_max" type="number" min="0.1" step="0.1" value="5"></div>
</div>
<div class="row2">
<div class="field"><label>单页超时(秒)</label><input name="timeout" type="number" value="60"></div>
<div class="field"><label>失败重试次数</label><input name="retry_count" type="number" value="2"></div>
</div>
<div class="row2">
<div class="field"><label>重试间隔(秒)</label><input name="retry_interval" type="number" value="3"></div>
<div class="field check"><label><input name="crawl_images" type="checkbox"> 爬取图片</label></div>
</div>
<div class="row2">
<div class="field check"><label><input name="notify" type="checkbox"> 完成后邮件通知</label></div>
<div class="field"><label>通知邮箱</label><input name="notify_email" value="wlq@tphai.com"></div>
</div>
<div class="field" id="urlsField">
<label>网址列表(每行一个,# 开头为注释)</label>
<div class="row2" style="align-items:center">
<button type="button" class="btn sm" id="btnImportUrls">📂 导入网址文件(.txt)</button>
<select id="importMode" title="对已有网址的处理方式">
<option value="append" selected>追加(保留已有)</option>
<option value="overwrite">覆盖(清空已有)</option>
</select>
<span class="card-line">支持 UTF-8 / GBK,自动去重</span>
<input type="file" id="urlFileInput" accept=".txt,.csv,.urls,text/plain" hidden>
</div>
<textarea name="urls" rows="5" placeholder="https://www.example.com/&#10;https://www.example.com/page2"></textarea>
</div>
<div id="scheduleBox" class="hidden box">
<div class="field"><label>首次执行时间(可留空;留空 = 尽快执行;已过的时间将立即执行)</label>
<input name="first_run" type="datetime-local"></div>
<div class="row2">
<div class="field"><label>调度类型</label>
<select name="schedule_type">
<option value="interval">间隔调度(每 N 时间)</option>
<option value="cron">cron 表达式</option>
</select>
</div>
<div class="field check"><label><input name="schedule_enabled" type="checkbox" checked> 启用调度</label></div>
</div>
<div id="intervalBox" class="row2">
<div class="field"><label>每隔</label><input name="interval_value" type="number" value="24"></div>
<div class="field"><label>单位</label>
<select name="interval_unit">
<option value="minutes">分钟</option>
<option value="hours" selected>小时</option>
<option value="days"></option>
</select>
</div>
</div>
<div id="cronBox" class="field hidden">
<label>cron 表达式(分 时 日 月 周,周 0/7=周日)</label>
<input name="cron" placeholder="0 3 * * * 每天凌晨3点">
</div>
</div>
<div id="autoBox" class="hidden box">
<div class="field"><label>起始网址 *(系统将自动发现符合规则的链接并爬取)</label>
<div class="row2">
<input name="seed_url" placeholder="https://example.com/news" style="flex:1">
<button type="button" class="btn sm" id="btnProbe">🧪 试爬取</button>
</div>
</div>
<div class="row2">
<div class="field"><label>包含规则(每行一个,子串或正则)</label>
<textarea name="include" rows="3" placeholder="techpowerup.com/review&#10;/news/"></textarea></div>
<div class="field"><label>排除规则</label>
<textarea name="exclude" rows="3" placeholder="login, signup, /tag/, /forum/"></textarea></div>
</div>
<div class="row2">
<div class="field check"><label><input name="same_domain" type="checkbox" checked> 仅爬同域名</label></div>
<div class="field check"><label><input name="use_regex" type="checkbox"> 规则按正则匹配</label></div>
</div>
<div class="row2">
<div class="field"><label>最大页数</label><input name="max_pages" type="number" value="50"></div>
<div class="field"><label>最大爬取深度</label><input name="max_depth" type="number" value="2"></div>
</div>
</div>
</div>
<div class="modal-foot">
<span id="formHint" class="hint"></span>
<button type="button" class="btn ghost" data-close>取消</button>
<button type="submit" class="btn primary">保存</button>
</div>
</form>
</div>
</div>
<!-- 任务详情弹窗 -->
<div id="detailModal" class="modal-overlay hidden">
<div class="modal wide">
<div class="modal-head">
<span id="detailTitle">任务详情</span>
<button class="btn ghost sm" data-close-detail></button>
</div>
<div id="detailBody"></div>
</div>
</div>
<!-- 搜索结果弹窗 -->
<div id="searchModal" class="modal-overlay hidden">
<div class="modal wide">
<div class="modal-head">
<span>🔍 搜索结果</span>
<button class="btn ghost sm" data-close-search></button>
</div>
<div id="searchBody" class="detail-wrap"></div>
</div>
</div>
<!-- 回收站弹窗 -->
<div id="trashModal" class="modal-overlay hidden">
<div class="modal wide">
<div class="modal-head">
<span>🗑️ 回收站(删除的任务统一在这里,可恢复或彻底删除)</span>
<button class="btn ghost sm" data-close-trash></button>
</div>
<div id="trashBody" class="detail-wrap"></div>
</div>
</div>
<!-- 试爬取结果弹窗 -->
<div id="probeModal" class="modal-overlay hidden">
<div class="modal wide">
<div class="modal-head">
<span>🧪 试爬取结果(规则筛选预览)</span>
<button class="btn ghost sm" data-close-probe></button>
</div>
<div id="probeBody" class="detail-wrap"></div>
</div>
</div>
<!-- 元数据弹窗 -->
<div id="metaModal" class="modal-overlay hidden">
<div class="modal">
<div class="modal-head">
<span>📋 资源操作信息(元数据)</span>
<button class="btn ghost sm" data-close-meta></button>
</div>
<div id="metaBody" class="detail-wrap"></div>
</div>
</div>
<!-- 文件预览弹窗 -->
<div id="previewModal" class="modal-overlay hidden">
<div class="modal wide tall">
<div class="modal-head">
<span id="previewTitle">预览</span>
<button class="btn ghost sm" data-close-preview></button>
</div>
<iframe id="previewFrame" sandbox="allow-same-origin"></iframe>
</div>
</div>
<script src="app.js"></script>
</body>
</html>