
Webman 本身不是爬虫框架,它只是个高性能 PHP 网络应用框架;所谓“Webman 驱动的高性能爬虫系统”,实际是指基于 Webman 构建调度/服务层,再搭配专用爬虫引擎(如 PHPCreeper)或 HTTP 客户端(如 GuzzleHttp)来实现数据采集。直接用 Webman 的 Worker 或 HttpServer 去发请求、解析 HTML,性能和稳定性都会很快见顶。
为什么不能直接在 Webman 的 HTTP 路由里写爬虫逻辑
常见错误现象:max_execution_time 超时、内存溢出、页面卡死、并发一高就 502。这是因为 Webman 的 HTTP 请求生命周期默认是同步阻塞的,每个请求独占一个进程/线程,而爬虫本质是 IO 密集型任务,需要异步、复用连接、可控超时、自动重试——这些 Webman 原生不提供。
使用场景:适合做爬虫任务的 Web 控制台、状态看板、API 触发入口,而不是执行爬取动作本身。
- 路由中只负责接收任务参数(如 URL、抓取深度、回调地址),写入队列(如 Redis)
- 真实爬取由独立的
Worker进程或PHPCreeper的 Producer/Consumer 模型完成 - 避免在
onRequest回调里调用$client->request()这类同步阻塞操作
PHPCreeper 是当前最匹配 Webman 的爬虫引擎
PHPCreeper(爬山虎)不是插件,而是基于 Workerman 内核重构的完整爬虫运行时,与 Webman 共享底层事件循环和多进程模型,因此能真正发挥“高性能”价值。
关键配置差异:
-
cache_enabled设为true可避免重复下载,但需确保cache_directory有写权限且路径非临时目录(否则重启丢失) - 动态页面必须启用
headless_browser,但会显著增加内存占用,建议单个 Worker 进程只跑 1–2 个无头实例 - 分布式部署时,
redis作为任务队列和去重存储,redis的SCAN命令要禁用,改用zset+score控制优先级
示例片段(app/spider/TinywanProducer.php):
public function makeTask()
{
return [
'url' => 'https://example.com/list?page=1',
'context' => ['depth' => 1, 'max_depth' => 3],
'options' => ['timeout' => 8, 'connect_timeout' => 5]
];
}
用 GuzzleHttp + Webman 做轻量采集时的避坑点
适合单页抓取、API 数据拉取等简单场景,但极易踩坑:
-
GuzzleHttp\Client实例必须复用,不能每次请求都 new 一个——否则 DNS 缓存失效、TCP 连接无法复用,QPS 直接腰斩 - 务必设置
http_errors => false,否则 4xx/5xx 会抛GuzzleException中断流程 - HTML 解析别用
DOMDocument::loadHTML()直接加载远程响应体,先用mb_convert_encoding()处理编码,否则中文乱码或解析失败 - 并发控制靠
Pool,但Pool::send()的最大协程数别设超过 20,PHP 的 curl 扩展对高并发支持有限
海量数据下的关键瓶颈不在“怎么发请求”,而在“怎么存”和“怎么去重”
当目标站点 URL 数量超 100 万,或单日采集量超 50GB 时,以下两点比选什么框架更重要:
- URL 去重必须用布隆过滤器(
BloomFilter)+ RedisPFADD组合,纯 MySQLUNIQUE KEY插入会成为 I/O 瓶颈 - 原始 HTML 存储建议用对象存储(如 MinIO),而非数据库 blob 字段——数据库只存元信息(URL、状态、指纹 hash、抓取时间)
-
PHPCreeper的parseHtml()方法若含复杂 XPath 查询,务必加缓存层(如 APCu),否则 DOM 构建开销远超网络耗时
真正的海量采集,从来不是“写个脚本能跑就行”,而是调度粒度、失败重试策略、指纹生成一致性、存储分片规则这些细节决定成败。别迷信“高性能框架”,先想清楚你的 URL 规模、页面平均大小、更新频率和容忍丢率——这些才是压倒一切的设计前提。











