Webman 仅负责调度、API 入口和状态管理,爬虫逻辑必须交由 PHPCreeper 或 MediaCrawler 等专用引擎执行;在路由中直接写爬虫代码会导致超时、内存溢出或 502 错误,因其同步阻塞模型无法支撑 IO 密集型任务。

Webman 本身不处理爬虫逻辑,所谓“Webman 驱动”只是指它承担调度、API 入口和状态管理角色;真实爬取必须交给 PHPCreeper 或 MediaCrawler 这类专用引擎,否则必然触发 max_execution_time 超时、内存溢出或 502 错误。
为什么不能在 Webman 的 HTTP 路由里写爬虫代码
常见错误现象:max_execution_time 报错、页面卡死、并发稍高就返回 502、memory_limit 被突破。根本原因是 Webman 的 onRequest 回调是同步阻塞模型,每个请求独占一个进程,而爬虫本质是 IO 密集型任务,需要连接复用、异步回调、可控重试——这些 Webman 原生不支持。
正确做法只在路由中做三件事:
- 校验参数(如
url、platform、keywords) - 构造任务数组并写入 Redis 队列(例如用
$redis->rPush('spider:queue', json_encode($task))) - 返回任务 ID 或状态码,不执行任何
$client->request()或 DOM 解析
PHPCreeper 生产器(Producer)怎么写才不踩坑
PHPCreeper 是目前与 Webman 兼容性最好、性能最稳的 PHP 爬虫运行时,但它不是“插件”,而是基于 Workerman 内核重构的完整爬虫环境,必须按其生命周期编写 Handler。
关键配置注意点:
-
cache_enabled设为true时,cache_directory必须是持久路径(如/data/cache/phpcreeper),不能用sys_get_temp_dir(),否则容器重启后缓存丢失 - 动态页面(如小红书、抖音)必须启用
headless_browser,但单个 Worker 进程建议最多跑 1–2 个无头实例,否则内存飙升 - 去重依赖 Redis,务必禁用
SCAN命令(会阻塞),改用ZSET+score控制任务优先级和去重时效 -
makeTask()返回的任务数组中,url必须是绝对地址,context里的allow_url_repeat默认为false,重复 URL 不会再次入队
MediaCrawler 作为 Python 侧主力采集工具怎么对接 Webman
MediaCrawler 适合处理小红书、抖音等强反爬平台,但它和 Webman 是异构系统,不能混跑。对接方式只能是“松耦合命令调用”或“队列驱动”。
推荐做法:
- Webman 接收用户请求后,生成标准化任务 JSON(含
platform、keywords、login_type、save_data_option),写入 Redis 或本地文件(如/tmp/media_task_12345.json) - 用 Supervisor 或 systemd 管理一个常驻 Python 进程,轮询该目录或 Redis 队列,发现新任务就执行:
python media_crawler.py --config /tmp/media_task_12345.json - MediaCrawler 输出结果存为 JSON 文件后,Webman 通过定时任务或 WebSocket 主动拉取状态,避免轮询接口
- 别用
shell_exec()直接调用 Python 脚本——超时难控制、错误不透出、无法回收子进程
GuzzleHttp 在 Webman 里轻量采集时的致命细节
仅适用于 API 数据拉取、静态页抓取等简单场景。一旦涉及翻页、登录态维持、中文解析,立刻暴露缺陷。
必须遵守的底线规则:
-
GuzzleHttp\Client实例必须全局复用(如绑定到 Webman 的Container或static属性),每次 new 会导致 DNS 缓存失效、TCP 连接无法复用,QPS 直接腰斩 - 务必设置
http_errors => false,否则遇到 404/429/503 会抛GuzzleException中断整个流程 - HTML 解析前必须先用
mb_convert_encoding()统一转为 UTF-8,DOMDocument::loadHTML()直接加载原始响应体会因编码混乱导致节点丢失或乱码 - 不要在
onWorkerStart里初始化 Client——Worker 启动时 Redis 可能未就绪;应延迟到首次请求时 lazy 初始化
真正容易被忽略的是任务边界:Webman 永远不该持有爬虫上下文(如 CookieJar、Browser 实例、渲染上下文),所有状态必须外置到 Redis、文件或独立进程。一旦把爬虫逻辑塞进 Webman 生命周期,问题不是“会不会出错”,而是“什么时候崩”。



















