
简介这是一套面向开发者与数据工程师的开源网页抓取系统源码专为解决自主可控、免依赖第三方API的网站数据采集需求而设计适用于数据挖掘、竞品分析及学术爬虫实践等场景。资源共28个文件包含8个核心PHP后端逻辑文件如api.php、wget_site.sh、smtp类等、3个CSS与2个JS前端样式交互文件、3张操作演示图JPG格式及README.md、LICENSE等工程文档整体压缩包仅318KB轻量易部署。已有346人学习下载体现了社区对本地化、可定制爬虫方案的关注。用户可直接运行基于wget命令行的扒站脚本深入理解任务调度、数据解析与反爬适配等关键模块源码结构清晰含Config.php配置中心、work任务目录及assets静态资源组织配套演示图直观呈现界面操作流程是学习Web抓取底层实现与二次开发的理想实践样本。1. 用 wget PHP 自建整站镜像服务为什么“至白扒站系统”不是玩具而是可落地的本地化抓取基础设施你有没有试过想把某企业官网完整存到本地电脑离线查看、做竞品分析、甚至二次开发不是截图不是收藏是真正把 HTML、CSS、JS、图片、字体全拉下来结构不变、链接可点、样式不崩——这种需求在渗透测试复盘、政务网站归档、教育机构课程资源备份、中小企业官网迁移前验证等场景里真实存在。但主流浏览器插件只能浅层保存Python 爬虫要自己写 URL 去重和资源路径重写而“至白在线扒站系统”直接绕过这些复杂度它本质是一个基于 wget 的 PHP 封装调度器把命令行工具的能力包装成 Web 界面所有逻辑跑在你自己的服务器或本地 WAMP/LNMP 环境里不调用任何外部 API不依赖云服务不上传目标站点数据。它解决的不是“能不能抓”而是“怎么让非开发者也能安全、可控、可审计地完成整站镜像”。适合两类人一是需要快速生成静态副本的技术支持/运维人员二是想从真实项目反向学习 wget 高级参数、PHP 进程管理、HTML 资源路径重写逻辑的爬虫初学者。它不承诺绕过反爬但把 wget 的-k -p -E -r -l 5 --convert-links这套成熟方案变成了点选式操作。2. 核心机制拆解wget 如何实现“整站扒取”以及 PHP 如何接管其生命周期2.1 wget 的四大关键参数组合为什么必须用-k -p -E -r而不是简单wget URL单纯执行wget https://example.com只会下载首页 HTML其他资源CSS、JS、图片不会自动获取链接也不会本地化。至白系统底层调用的是经过严格组合的 wget 命令典型示例如下wget -k -p -E -r -l 5 --no-parent --restrict-file-nameswindows --user-agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 --timeout30 --tries3 --wait1 --random-wait -P /var/www/html/mirror/example.com https://example.com/提示该命令需在 Linux 终端手动验证后再集成进 PHP避免因权限或路径问题导致静默失败。-k--convert-links下载完成后将 HTML 中的绝对 URL如https://example.com/css/style.css重写为相对路径如css/style.css确保离线打开时资源能正确加载-p--page-requisites强制下载页面渲染必需的所有资源包括 CSS、JS、图片、字体等即使它们未在 HTML 中显式link或img引用而是由 JS 动态加载-E--adjust-extension为 HTML 文件自动添加.html后缀如将/about保存为/about.html避免部分浏览器因缺少后缀无法解析-r--recursive启用递归下载配合-l 5最大递归深度 5 层控制抓取范围防止无限遍历--no-parent禁止向上跳转到父目录如从/product/不爬/保障只抓目标子站--restrict-file-nameswindows将文件名中的非法字符如:、*、?转义适配 Windows 文件系统方便后续在本地双击打开--user-agent伪装浏览器标识降低被目标站 403 拦截概率--wait1 --random-wait每请求间隔 1 秒且随机浮动 ±0.5 秒模拟人工访问节奏这些参数不是凭空堆砌而是针对“整站镜像”这一明确目标的最小可行集。少-k离线打不开少-p页面白屏少--no-parent可能误爬整个域名。2.2 PHP 如何安全调用 wget 并监控进程从exec()到proc_open()的演进至白系统中index.php接收表单提交的目标 URL 后并非直接exec(wget ...)而是通过proc_open()启动独立进程并捕获实时输出。关键代码片段位于work/wget_site.sh或common.php中如下?php function startWgetMirror($url, $targetDir) { $cmd wget -k -p -E -r -l 5 --no-parent --restrict-file-nameswindows --user-agentMozilla/5.0 --timeout30 --tries3 --wait1 --random-wait -P . escapeshellarg($targetDir) . . escapeshellarg($url); $descriptorspec [ 0 [pipe, r], // stdin 1 [pipe, w], // stdout 2 [pipe, w] // stderr ]; $process proc_open($cmd, $descriptorspec, $pipes, dirname(__FILE__), null); if (!is_resource($process)) { throw new Exception(Failed to start wget process); } // 实时读取 stdout写入日志文件供前端 AJAX 轮询 stream_set_blocking($pipes[1], false); $logFile $targetDir . /wget.log; $fp fopen($logFile, a); while ($process proc_get_status($process)[running]) { $output fgets($pipes[1], 1024); if ($output ! false) { fwrite($fp, date(Y-m-d H:i:s) . [WGET] . $output); fflush($fp); } usleep(500000); // 0.5秒轮询一次 } fclose($fp); foreach ($pipes as $pipe) fclose($pipe); proc_close($process); } ?escapeshellarg()是关键对用户输入的$url和$targetDir进行 Shell 参数转义杜绝命令注入如https://example.com; rm -rf /proc_open()替代exec()获得进程句柄可主动检查proc_get_status()获取运行状态而非被动等待超时stream_set_blocking($pipes[1], false)设置 stdout 管道为非阻塞避免fgets()卡死配合usleep()实现低开销轮询日志文件wget.log是前端进度条的数据源JavaScript 通过fetch(/work/log.php?task_idxxx)每 2 秒读取最新行解析Downloaded: xxx of yyy files提取进度百分比若直接使用exec()一旦 wget 卡住或崩溃PHP 进程将无感知任务状态永远停留在 “Running”而proc_open()提供了真正的进程生命周期控制能力。2.3 HTML 资源路径重写的底层逻辑--convert-links不足时的 PHP 补位wget 的-k参数虽能处理大部分链接但对以下情况失效内联 CSS 中的background-image: url(/images/logo.png)JavaScript 中动态拼接的路径window.location.href /contact;base hrefhttps://example.com/标签导致的相对路径基准偏移。至白系统在common.php中提供了rewriteHtmlLinks()函数在 wget 完成后二次扫描 HTML 文件?php function rewriteHtmlLinks($htmlContent, $baseUrl, $localPath) { // 1. 替换 base 标签防止后续相对路径解析错误 $htmlContent preg_replace(/base\shref[\]([^\])[\]\s*\/?/i, , $htmlContent); // 2. 替换所有 href/src 属性中的绝对 URL 为相对路径 $htmlContent preg_replace_callback( /(href|src|action|data-src|poster)[\]([^\])[\]/i, function ($matches) use ($baseUrl, $localPath) { $fullUrl $matches[2]; if (filter_var($fullUrl, FILTER_VALIDATE_URL) strpos($fullUrl, parse_url($baseUrl, PHP_URL_HOST)) ! false) { // 提取路径部分转为相对于 $localPath 的路径 $parsed parse_url($fullUrl); $relativePath ltrim($parsed[path], /); return $matches[1] . . $relativePath . ; } return $matches[0]; }, $htmlContent ); // 3. 处理内联 CSS 中的 url() $htmlContent preg_replace_callback( /url\([\]?([^\)])[\]?\)/i, function ($matches) use ($baseUrl, $localPath) { $url $matches[1]; if (filter_var($url, FILTER_VALIDATE_URL) strpos($url, parse_url($baseUrl, PHP_URL_HOST)) ! false) { $parsed parse_url($url); $relativePath ltrim($parsed[path], /); return url( . $relativePath . ); } return $matches[0]; }, $htmlContent ); return $htmlContent; } ?此函数在index.php的任务完成钩子中被调用遍历wget下载目录下的所有.html、.htm文件parse_url($baseUrl, PHP_URL_HOST)提取目标站域名确保只重写同域资源避免误改 CDN 或第三方脚本ltrim($parsed[path], /)去除路径开头的/使https://example.com/images/logo.png→images/logo.png与本地文件结构对齐正则中[\]?允许url(images/logo.png)和url(images/logo.png)两种写法覆盖主流 CMS 输出没有这一步某些企业站的导航菜单、轮播图、表单提交按钮仍会指向线上地址导致离线体验断裂。3. 部署与配置实战从零搭建可运行的扒站服务3.1 环境准备Linux Nginx PHP 7.4 wget 的最小化安装清单至白系统要求环境必须满足三项硬性条件wget 版本 ≥ 1.18支持--restrict-file-names和--random-waitPHP 开启proc_open、exec、shell_exec函数默认禁用需修改php.iniWeb 服务器有写入权限的目录用于存放镜像文件如/var/www/html/mirror/。标准 Ubuntu 22.04 部署步骤# 1. 安装基础组件 sudo apt update sudo apt install -y nginx php-fpm php-cli php-curl wget # 2. 验证 wget 版本必须 ≥1.18 wget --version # 若低于执行sudo apt install -y wget # 3. 修改 PHP 配置启用危险函数仅限内网环境 sudo sed -i s/;disable_functions .*/disable_functions / /etc/php/7.4/fpm/php.ini sudo sed -i s/;enable_dl .*/enable_dl On/ /etc/php/7.4/fpm/php.ini sudo systemctl restart php7.4-fpm # 4. 创建镜像存储目录并赋权 sudo mkdir -p /var/www/html/mirror sudo chown www-data:www-data /var/www/html/mirror sudo chmod 755 /var/www/html/mirror # 5. 将至白源码解压到 /var/www/html/确保 index.php 在根目录 unzip 至白在线扒站系统源码.zip -d /var/www/html/ sudo chown -R www-data:www-data /var/www/html/注意disable_functions行必须清空否则proc_open()调用失败日志中会出现PHP Warning: proc_open() has been disabled for security reasons。生产环境务必限制该服务器仅内网访问避免成为肉鸡。3.2 Nginx 配置要点解决跨域、大文件上传与 PHP 超时问题默认 Nginx 配置会拦截大体积镜像包企业站常达 500MB和长时 wget 进程60 秒。需在server块中追加server { listen 80; root /var/www/html; index index.php; location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.4-fpm.sock; # 关键延长 PHP 执行时间避免 wget 未完成就被 kill fastcgi_read_timeout 3600; # 1小时 fastcgi_send_timeout 3600; # 传递真实客户端 IP 给 PHP用于日志记录 fastcgi_param REMOTE_ADDR $remote_addr; } # 允许上传大文件表单提交 URL 和配置 client_max_body_size 100M; # 防止镜像目录被直接列目录 location ^~ /mirror/ { autoindex off; # 强制下载而非渲染避免 XSS镜像文件可能含恶意 JS add_header Content-Disposition attachment; } # 静态资源缓存优化 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }fastcgi_read_timeout 3600是核心PHP-FPM 默认 60 秒超时而 wget 抓取大型站可能耗时 20 分钟以上此参数确保 PHP 进程不被提前终止client_max_body_size 100M虽然表单本身很小但某些定制版至白可能支持上传config.json配置文件预留空间add_header Content-Disposition attachment对/mirror/下所有文件强制下载防止浏览器直接执行其中的exploit.js这是安全底线配置完成后执行sudo nginx -t sudo systemctl reload nginx。3.3 首次任务提交与日志诊断如何读懂 wget 输出并定位失败原因访问http://your-server-ip/输入目标网址如https://example.com点击“开始扒站”。若页面卡在 “任务进行中…” 超过 5 分钟按以下顺序排查日志位置关键线索典型错误及修复/var/www/html/mirror/example.com/wget.logERROR 403: Forbidden目标站屏蔽了 wget UA修改wget_site.sh中的--user-agent为 Chrome 真实 UA/var/log/nginx/error.logPHP message: PHP Warning: proc_open(): unable to create processPHPdisable_functions未清空或www-data用户被 SELinux 限制/var/www/html/mirror/example.com/目录为空--no-parent导致根目录未被抓取检查 URL 是否带尾部/应为https://example.com/而非https://example.com页面打开后 CSS/JS 404wget.log中出现Cannot write to ‘xxx’ (No such file or directory)目标站 URL 含非法字符如#--restrict-file-nameswindows已转义但 PHP 创建目录时仍失败需在Config.php中增加str_replace([#, ?], _, $url)预处理一个真实案例某政府站启用robots.txt禁止/news/目录wget 默认遵守导致新闻页缺失。解决方案是在命令中添加--ignore-robots参数并在Config.php的$wgetOptions数组中追加该开关。4. 进阶技巧批量任务调度、增量更新与镜像校验4.1 用 crontab 实现每日自动镜像避免手动操作遗漏对于需长期监控的竞品官网可编写auto_mirror.sh脚本配合 crontab 每日凌晨执行#!/bin/bash # auto_mirror.sh SITES(https://company-a.com/ https://company-b.net/ https://product-c.org/) MIRROR_DIR/var/www/html/mirror LOG_DIR/var/log/autobackup mkdir -p $LOG_DIR for site in ${SITES[]}; do domain$(echo $site | sed s/https\?:\/\///; s/\/$//) timestamp$(date %Y%m%d_%H%M%S) # 清理昨日镜像保留最近3份 find $MIRROR_DIR/$domain -maxdepth 1 -name $domain-* -type d -mtime 2 -exec rm -rf {} \; 2/dev/null # 执行 wget输出到独立日志 wget -k -p -E -r -l 3 --no-parent --restrict-file-nameswindows \ --user-agentAutoMirrorBot/1.0 --timeout600 --tries2 \ -P $MIRROR_DIR/$domain/$domain-$timestamp $site \ $LOG_DIR/$domain-$timestamp.log 21 # 校验是否成功检查是否创建了 index.html if [ -f $MIRROR_DIR/$domain/$domain-$timestamp/index.html ]; then echo $(date): SUCCESS $site - $domain-$timestamp $LOG_DIR/backup.log # 更新软链接指向最新版 ln -sf $domain-$timestamp $MIRROR_DIR/$domain/latest else echo $(date): FAILED $site $LOG_DIR/backup.log fi done赋予执行权限并加入 crontabchmod x /root/auto_mirror.sh # 每天凌晨2:15执行 echo 15 2 * * * /root/auto_mirror.sh | sudo crontab -find ... -mtime 2保证磁盘不被旧镜像占满符合运维规范ln -sf创建latest软链接前端可固定访问https://your-server/mirror/company-a.com/latest/获取最新副本日志分离$domain-$timestamp.log便于按站点排查backup.log记录整体成功率4.2 增量更新策略用--timestamping避免重复下载全量抓取耗时耗带宽。对已存在的镜像目录启用--timestamping参数可仅下载修改过的文件wget -k -p -E -r -l 5 --no-parent --timestamping \ --restrict-file-nameswindows -P /var/www/html/mirror/example.com \ https://example.com/原理wget 比较远程文件的Last-ModifiedHTTP 头与本地文件的mtime仅当远程更新时才下载。但需注意目标站必须返回正确的Last-Modified静态资源通常有动态 PHP 页面常无首次抓取后手动执行touch -d 1 week ago /var/www/html/mirror/example.com/*可强制触发首次增量在Config.php中将$incrementalMode true前端表单增加“增量更新”复选框勾选后追加--timestamping4.3 镜像完整性校验用sha256sum生成指纹文件为验证镜像未被篡改或下载损坏可在任务完成时生成校验文件// 在 wget 完成后的回调中执行 $mirrorPath /var/www/html/mirror/example.com/; exec(find $mirrorPath -type f -not -name SHA256SUMS -print0 | xargs -0 sha256sum $mirrorPath/SHA256SUMS, $output, $returnCode); if ($returnCode 0) { // 校验文件生成成功记录到数据库或日志 }用户下载镜像 ZIP 包时可运行sha256sum -c SHA256SUMS验证所有文件哈希值确保离线浏览的可靠性。此步骤虽增加 2-3 分钟计算时间但对法律合规性存档场景不可或缺。本文还有配套的精品资源点击获取