webman本身不提供爬虫能力,所谓“基于webman的高性能爬虫系统”实为用其构建调度/控制层,将真实爬取交由phpcreeper或异步guzzlehttp实现;直接在onrequest中调用同步http请求必然导致超时、502、内存溢出等问题,因其http server默认同步阻塞,无法满足io密集型任务所需的连接复用、自动重试等特性。

Webman 本身不提供爬虫能力,所谓“基于 Webman 的高性能爬虫系统”,本质是用 Webman 做调度和控制层,把真实爬取任务交给 PHPCreeper 或复用 GuzzleHttp 的异步/队列化方案——直接在 HTTP 路由里写 $client->request() 必然崩。
为什么不能在 Webman 的 onRequest 里写爬虫逻辑
常见错误现象:max_execution_time 超时、内存溢出、Nginx 返回 502、并发稍高就卡死。根本原因是 Webman 的 HTTP Server 默认是同步阻塞模型:每个请求独占一个进程,而爬虫是典型的 IO 密集型任务,需要连接复用、可控超时、自动重试、非阻塞等待——这些它原生不支持。
正确使用场景只有一类:接收用户配置(如目标 URL、抓取深度、回调地址),校验后写入 Redis 队列,然后立即返回任务 ID。真实下载和解析必须交由独立 Worker 进程完成。
- 绝对不要在
app/controller或路由闭包中调用GuzzleHttp\Client::request()或file_get_contents() - 所有耗时操作必须剥离到
app/worker目录下的自定义 Worker 类中运行 - 若用 PHPCreeper,生产器(Producer)必须注册为独立进程,不能挂载在 HTTP 进程下
PHPCreeper 是当前最匹配 Webman 的爬虫引擎
它不是插件,而是基于 Workerman 内核重构的完整爬虫运行时,与 Webman 共享底层事件循环和多进程模型,能真正发挥“高性能”价值。部署时需注意几个关键点:
-
cache_enabled设为true可避免重复下载,但cache_directory必须指向有写权限的持久化路径(比如/data/cache/phpcreeper),不能用/tmp - 动态页面必须启用
headless_browser,但单个 Worker 进程建议只跑 1–2 个无头实例,否则内存飙升 - 分布式部署时,
redis作为任务队列和去重存储,禁用SCAN命令(性能差),改用ZSET+ score 控制优先级 - 生产器类中的
makeTask()方法应只构造任务数组,不执行任何网络或磁盘 IO
GuzzleHttp + Webman 做轻量采集时的三个硬性约束
适合单页抓取、API 数据拉取等简单场景,但极易因配置不当导致 QPS 断崖式下跌或中文乱码:
-
GuzzleHttp\Client实例必须全局复用(例如注入到 Service 类中),不能每次请求都new Client()——否则 DNS 缓存失效、TCP 连接无法复用 - 务必显式设置
http_errors => false,否则遇到 4xx/5xx 状态码会抛GuzzleException中断整个流程 - HTML 解析前必须先做编码转换:
mb_convert_encoding($html, 'UTF-8', 'auto'),再喂给DOMDocument::loadHTML(),否则中文乱码或解析失败
真正难的不是写几行爬取代码,而是让系统在持续运行一周后仍不丢任务、不爆内存、不漏重试、不误判状态。PHPCreeper 的 onTaskError 和 onTaskSuccess 回调、Guzzle 的 RetryMiddleware、Redis 的 zrem + zadd 原子操作——这些细节才是决定系统是否“能用”的分水岭。











