
简介这是一套面向PHP开发者与建站爱好者的网站采集程序源码核心为VIVI万能小偷程序只需填入目标站地址即可自动抓取内容据描述可兼容约98%的单级域名站点适合想研究采集逻辑、搭建聚合类站点或做数据抓取练习的中初级开发者参考。资源以zip压缩包形式提供整体约1.37MB包内以PHP源码文件为主涵盖采集入口、页面解析与内容输出等核心逻辑便于直接阅读与二次修改。目前已有289人学习下载属于有一定关注度的实用型源码。读者可从中了解小偷程序如何解析目标页面、提取正文与列表、处理单级域名适配并据此搭建自己的采集流程或改造为定制化爬虫工具对理解PHP网络请求与HTML解析思路有直接帮助。1. 从一份 PHP 采集源码说起网站小偷程序到底解决什么问题手里这份vivi网站小偷程序5.5PHP版.zip名字听着像黑产工具其实拆开看就是一套用 PHP 写的目标站点内容采集与本地化重建脚本。它的核心场景很明确你有一个已经上线的 PHP 站点想把另一个站点的文章、列表、详情页结构批量搬到自己的库里又不想从零写爬虫、解析、入库、模板替换这一整条链路。这套东西把「抓取—解析—清洗—入库—伪静态输出」串成了一条流水线适合做内容聚合站、行业资讯站、资源导航站的从业者快速搭原型。我第一次拿到这类源码时也犯嘀咕PHP 做采集并发和稳定性扛得住吗实际拆完发现它的定位不是工业级爬虫框架而是「单机小规模、规则驱动、开箱即用」的轻量方案。你给它一个目标栏目地址和几条 CSS/XPath 规则它就能把列表页翻页、详情页正文、缩略图一起拉下来按你预设的模板生成静态页。对预算有限、又需要快速验证内容模型的小团队来说这比上重型框架省事得多。下面我按「它怎么跑起来 → 规则怎么配 → 哪里会翻车 → 怎么稳住」的顺序把这份源码拆给你看。2. 环境搭建与目录结构把 5.5 版跑起来的第一公里2.1 运行环境与依赖确认这套程序是纯 PHP 实现没有 Composer 依赖理论上 PHP 5.6 到 7.4 都能跑但 5.5 这个版本号对应的代码风格偏老我建议用 PHP 7.2 配 Apache 或 Nginx别直接上 PHP 8否则一些ereg、each之类的老函数会直接报致命错误。数据库用 MySQL 5.7 就够字符集统一utf8mb4不然后面抓 emoji 或生僻字会乱码。先把压缩包解到 Web 根目录下的一个子目录比如/var/www/html/collector然后确认三件事allow_url_fopen打开、curl扩展启用、mbstring扩展启用。这三个是采集和编码转换的命脉缺一个都会在运行到一半时给你脸色看。# 检查 PHP 扩展是否齐全 php -m | grep -E curl|mbstring|pdo_mysql # 预期输出类似 # curl # mbstring # pdo_mysql上面这条命令是排查环境的第一步。如果curl没出现去php.ini里把;extensioncurl前面的分号去掉再重启服务。mbstring负责把 GBK 目标站转成 UTF-8少了它抓回来的中文全是问号这个坑后面还会细说。2.2 目录结构与核心文件职责解压后你会看到大致这么几个部分config/放数据库和采集参数lib/是抓取和解析的类库rule/存每个目标站的规则文件template/是生成静态页的模板admin/是后台管理入口。别急着改代码先摸清哪个文件管哪件事能省掉大量瞎找的时间。目录/文件职责改动频率config/db.php数据库连接与表前缀部署时改一次config/setting.php采集间隔、超时、编码按目标站调lib/Fetcher.class.phpHTTP 请求与重试基本不动lib/Parser.class.php规则解析与字段提取按需扩展rule/*.php单站采集规则每加一个站写一份template/default/静态页模板按自己站点风格改这张表是我拆包后整理的核心映射。新手最容易犯的错是直接去改lib/里的类其实九成需求在rule/和template/里就能解决。Fetcher负责发请求Parser负责按规则抠数据两者解耦得还算干净你换目标站只需要新增规则文件不用动底层。2.3 数据库初始化与首次运行导入建表 SQL 通常在install/或根目录的install.sql里。用命令行导入比 phpMyAdmin 稳尤其是表多的时候。# 创建库并导入结构 mysql -u root -p -e CREATE DATABASE collector DEFAULT CHARSET utf8mb4; mysql -u root -p collector install.sql # 确认表已建好 mysql -u root -p collector -e SHOW TABLES;导入完成后改config/db.php里的主机、库名、账号密码然后浏览器访问后台入口登录。首次运行建议先跑一个「测试采集」只抓一页列表、不入库看解析结果对不对。这一步能帮你把规则问题在污染数据库之前就暴露出来。很多人图快直接开全量结果规则写错几万条脏数据进了库清理起来比重抓还麻烦。3. 采集规则配置列表页翻页与详情页字段提取3.1 规则文件的基本结构每个目标站对应rule/下一份 PHP 数组配置。它要回答四个问题从哪个 URL 开始、列表页怎么翻、详情链接怎么定位、详情页每个字段从哪抠。下面是一份我常用的规则骨架字段名按你实际表结构调整。?php // rule/example_site.php return [ name example_site, charset gbk, // 目标站编码gbk 或 utf-8 list_url https://target.com/news/list_1.html, page_rule https://target.com/news/list_{page}.html, // 翻页模板 page_start 1, page_end 20, list [ item div.news-list li, // 列表项选择器 link a, // 详情链接所在标签 title a, // 标题所在标签 ], detail [ title h1.title, content div.article-content, pubtime span.time, source span.source, ], ];这份配置里charset决定要不要做编码转换page_rule里的{page}是翻页占位符程序会用它替换页码循环抓取。list.item是列表项的选择器link和title是相对该项的子选择器。detail下每个键对应数据库一个字段值就是 CSS 选择器。逻辑很直白先定位列表项再在每项里找链接和标题进详情页后按字段选择器逐个抠。3.2 翻页策略与去重逻辑翻页有两种常见写法一种是 URL 里带页码用{page}占位另一种是「下一页」链接跟随。这套程序默认支持第一种第二种需要在规则里加next_rule字段。我一般优先用页码模板因为可控、可断点续抓翻到第几页心里有数。去重靠的是详情页 URL 的哈希。程序入库前会算一次md5(url)在表里建唯一索引重复的直接跳过。这里有个细节有些站点的 URL 带随机参数同一个页面每次抓到的 URL 都不一样去重就失效了。解决办法是在规则里加一个url_clean正则把无关参数剔掉再算哈希。// 在规则里追加 URL 清洗 url_clean /\?.*$/, // 去掉问号及其后所有参数加上这行后https://target.com/news/123.html?fromlist和https://target.com/news/123.html会被视为同一条避免重复入库。这个坑我在做行业资讯聚合时踩过一个站因为带追踪参数同一篇文章进了七遍库后台列表惨不忍睹。3.3 正文提取与图片本地化正文提取最怕两件事一是选择器抓到了广告或推荐位二是正文里的图片是外链目标站一改图就全挂。前者靠调选择器精度解决后者需要在规则里开图片本地化开关。content_filter [ remove [div.ad, div.related, script, style], // 先删干扰节点 img_local true, // 图片下载到本地 img_dir /uploads/collect/, img_url https://your-site.com/uploads/collect/, ],remove里的选择器会在提取正文前先把广告、相关阅读、脚本样式删掉剩下的才是干净正文。img_local打开后程序会把img标签的src换成你站点的地址同时把图片文件下载到img_dir。注意img_url要和你站点的实际访问路径一致否则页面能生成但图片 404。图片下载是同步的量大时会拖慢采集速度我一般把img_local在调试阶段关掉确认正文没问题再打开跑全量。4. 避坑与排查采集跑不通时先看这几处4.1 抓回来全是乱码现象入库的中文显示为??????或一串看不懂的字符。原因目标站是 GBK 编码但规则里charset写成了utf-8或者服务器没装mbstring扩展转换函数直接失效。解决先用浏览器查看目标站源码里的meta charset确认真实编码再检查php -m里有没有mbstring最后在规则里把charset改对。如果目标站是混合编码可以在Fetcher里强制按mb_convert_encoding转一次。4.2 列表页抓得到详情页全空现象列表能翻页标题也抓到了但进详情页后正文字段为空。原因详情页的选择器写错了或者详情页结构和列表页不在同一个域名下请求被拦。解决把详情页 URL 单独拿出来用浏览器的开发者工具复制正确的 CSS 选择器如果是跨域检查Fetcher里的Referer和User-Agent有没有带上很多站会校验这两个头。4.3 采集到一半进程卡死现象跑了十几页后脚本不动了也不报错。原因目标站响应变慢或触发了频率限制而Fetcher的默认超时设得太长或者没有重试上限。解决在config/setting.php里把timeout调到 10 秒以内retry设为 2 次并在每次请求之间加sleep(1)到sleep(3)的随机间隔。别把间隔设成固定值固定间隔反而容易被识别出是脚本。4.4 图片下载了但页面不显示现象uploads/collect/里确实有图片文件但生成的静态页里图片是裂的。原因img_url配的是相对路径或域名不对或者图片目录没有写权限。解决确认img_url是完整的https://开头地址且和站点实际访问路径一致用chmod 755给图片目录写权限如果用了 CDN还要确认 CDN 回源路径能命中这个目录。4.5 重复入库清不掉现象同一篇文章反复出现在后台列表里。原因URL 带随机参数导致哈希不同或者唯一索引没建在url_hash字段上。解决按 3.2 节加url_clean正则清洗 URL检查表结构确认url_hash上有UNIQUE索引如果历史脏数据已经进了库写一条 SQL 按标题去重保留最早一条。-- 按标题去重保留 id 最小的一条 DELETE t1 FROM articles t1 INNER JOIN articles t2 WHERE t1.title t2.title AND t1.id t2.id;这条 SQL 执行前先备份别问我怎么知道的。去重逻辑最好在入库前用代码拦而不是事后用 SQL 擦屁股后者在数据量大时又慢又危险。5. 进阶技巧把采集频率和内容质量同时稳住5.1 用队列削峰别让脚本裸奔直接for循环翻页抓取在目标站响应快的时候没问题一旦对方变慢你的脚本就卡在某个请求上整批任务停摆。我后来改成「先入队、再消费」列表页只负责把详情 URL 写进一张queue表另一个常驻脚本按固定节奏从队列取任务、抓详情、入库。这样即使某个详情页超时也只影响那一条不会拖垮整批。// 列表阶段只收集 URL 入队 foreach ($items as $item) { $url build_url($item[link]); $hash md5(preg_replace($rule[url_clean], , $url)); $db-exec(INSERT IGNORE INTO queue (url, url_hash, status) VALUES (?, ?, 0), [$url, $hash]); } // 消费阶段单独脚本按批取任务 $tasks $db-query(SELECT * FROM queue WHERE status 0 LIMIT 20)-fetchAll(); foreach ($tasks as $task) { $html $fetcher-get($task[url]); // 解析、入库、更新 status 1 }队列方案的好处是可断点、可限速、可并行。INSERT IGNORE配合url_hash唯一索引天然去重。消费脚本里把LIMIT调小配合sleep对目标站的压力就平缓了。这套改法是我从「跑一次挂一次」到「挂机跑一晚上」的分水岭。5.2 内容质量校验三道过滤网采集来的内容不能直接上站我一般加三道过滤。第一道是长度过滤正文少于 200 字的直接丢弃多半是抓到了列表页或错误页。第二道是关键词黑名单命中「404」「验证码」「访问受限」的丢弃。第三道是重复度检测用similar_text或简单的 SimHash 比对最近 1000 篇相似度超阈值的不入库。// 正文长度与黑名单校验 $len mb_strlen(strip_tags($content), utf-8); if ($len 200) { return false; } $blacklist [404, 验证码, 访问受限, 页面不存在]; foreach ($blacklist as $word) { if (mb_strpos($content, $word) ! false) { return false; } }这三道网能挡掉八成脏数据。长度过滤最有效因为错误页和列表页的正文通常很短。黑名单要按目标站的实际返回文案维护不同站的拦截提示不一样。重复度检测开销稍大我一般放在入库前异步跑不阻塞主流程。5.3 定时任务与日志留存最后一步是让它自己跑。用crontab每 30 分钟触发一次消费脚本每次只跑固定条数跑完退出避免常驻进程内存泄漏。# 每 30 分钟消费一批日志按天切 */30 * * * * /usr/bin/php /var/www/html/collector/consume.php /var/log/collector/$(date \%Y\%m\%d).log 21日志一定要留而且要按天切。采集出问题时日志里的 HTTP 状态码、超时记录、解析失败的行号是你唯一能回溯的线索。我现在的习惯是任何采集任务上线前先把日志路径、轮转策略、失败重试次数这三样配好再开跑。从那以后我每次部署采集脚本都强制走一遍「小批量试跑 → 看日志 → 确认无异常 → 再放量」的流程省下来的排错时间远比多花的那十分钟值。希望帮到你。本文还有配套的精品资源点击获取