- 后端
【免费下载链接】pholcus
Pholcus is a distributed high-concurrency crawler software written in pure golang
本篇技术指南以 pholcus 仓库内置的搜房(fang.com)二手房列表爬虫规则 readme.md 及其完整实现 fang_resell_list.go 为主线,拆解一个真实可运行的静态爬虫规则:从Spider结构定义、RuleTree分页入口、goqueryDOM 解析,到字段清洗与Output结果回传的完整调用链。读完本文,你将掌握 pholcus 静态规则的标准写法、如何按页码批量入队、如何在解析函数里用字符串与 DOM 操作抽取结构化字段,以及当"页数过多导致蜘蛛崩溃"时可以从源码的哪些 panic 防护机制入手排查。
规则定位:一次只爬一页,字段结构清晰
搜房二手房列表规则是 pholcus 内置静态规则库 sample/static_rules 中的一员,目标站点为http://esf.zz.fang.com/house/i31/(郑州搜房二手房列表页)。根据 readme.md 的说明,它仅爬取列表页、一次爬取一页,不做详情页深入,属于典型的"列表采集 + 结构化字段输出"入门级规则。
规则的字段设计(文档声明的 11 个字段,外加源码实现中补充的 2 个),在 ItemFields 中按输出顺序定义如下:
| 字段名 | 含义 | 来源说明 |
|---|---|---|
communityName | 小区名 | .info p.mt10 a span文本 |
totalFloor | 总层数 | 从(共N层)字符串中剥离 |
rooms | 房间数 | 从N室M厅中拆分 |
halls | 厅数量 | 从N室M厅中拆分 |
buildTime | 建筑年代 | |建筑年代:前缀剥离 |
address | 地址 | |拆分后半段 |
direction | 朝向 | |向后缀剥离 |
area | 面积(㎡) | 剥离㎡单位 |
price | 总价(万) | 剥离万单位 |
unitPrice | 单价(元/㎡) | 剥离元/㎡单位 |
locationType | 所在层数高低 | 从低层|共33层中提取 |
remoteId | 搜房房源 id | 从详情链接_id.htm提取(源码补充) |
business | 商圈 | 从地址商圈-小区拆分(源码补充) |
相比原文档,实际代码多出remoteId(房源唯一标识,可用于后续增量去重)与business(商圈)两个字段,说明规则在维护中做过字段扩展。
规则骨架:Spider 结构与注册机制
整个规则是一个包级变量fangList,类型为*spider.Spider,在init()中调用fangList.Register()完成注册(fang_resell_list.go)。Spider结构体定义在 app/spider/spider.go,规则中使用到的关键字段:
Name:蜘蛛名称"resell house of fang.com",在规则库中必须唯一;注册时若重名,Species.Add 会自动追加数字后缀。Description:任务描述,同时会在命令行蜘蛛列表、Web 界面中展示。EnableCookie: true:请求携带 Cookie,适合目标站点要求会话保持的场景;该开关会通过 AddQueue 自动透传给每个请求。RuleTree:规则树,包含Root(任务入口)和Trunk(规则节点映射),是 pholcus 静态规则的核心组织方式。
注册后,规则会进入全局单例spider.Species列表。首次访问时 Get() 还会按拼音首字母对蜘蛛排序,因此命令行界面里搜房规则的序号由该排序结果决定,选择时以-h帮助输出的实际序号为准。
分页入口:Root 函数与 URL 构造
RuleTree.Root是任务的起始点(fang_resell_list.go):
Root: func(ctx *spider.Context) { var i = 1 //for i = 1; i < 101; i++ { ctx.AddQueue(&request.Request{ URL: "http://esf.zz.fang.com/house/i3" + strconv.Itoa(i) + "/", Rule: "fang_collection", Temp: map[string]interface{}{"p": 1}, }) //} },要点解读:
- URL 分页规律:搜房列表页 URL 形如
house/i31/、house/i32/……即页码拼接在i3之后。当前默认i=1只抓首页,即文档所述"一次爬取一页"。 - 打开多页爬取:文档第 2 条提到的"修改 37 行打开多页爬取",对应的正是把
var i = 1上方的注释//for i = 1; i < 101; i++ {取消注释,并在ctx.AddQueue(...)之后补上右大括号},即可循环入队第 1~100 页。 Temp传递临时数据:这里写入{"p": 1},配合分页循环可用于后续解析中标记页码(当前解析函数未使用,但这是 pholcus 规则间传参的标准通道)。request.Request的完整可选字段(Method、DialTimeout、TryTimes、RedirectTimes、DownloaderID等)及其默认值见 app/downloader/request/request.go,未显式设置时由 Prepare() 自动补齐默认值(如TryTimes默认 3 次重试、DialTimeout默认 2 分钟)。
ctx.AddQueue内部会校验URL与Rule两个必填项,自动设置蜘蛛名与 Cookie 开关,完成 Prepare 后把请求推入调度矩阵(spider.RequestPush),随后由爬虫引擎按并发配置从矩阵中拉取执行。
页面解析:goquery 选择器与字符串清洗
请求下载成功后,响应被交给Trunk中名为fang_collection的规则节点执行ParseFunc(fang_resell_list.go)。整体流程是:定位列表容器 → 逐条房源遍历 → DOM 取文本 → 字符串拆分清洗 → Output 输出。
列表遍历
ctx.GetDom().Find(".houseList dl").Each(func(i int, s *goquery.Selection) { ... })ctx.GetDom()返回的是 pholcus 内置的 goquery 文档对象(基于 CSS 选择器),Find(".houseList dl")选中每一条房源条目,Each逐条回调。DOM 是惰性初始化的:首次调用时由 GetDom() 从响应体解析,内部会先经initText按页面charset做编码探测与 UTF-8 转换(app/spider/context.go),对中文站点尤其重要。
字段抽取的三种技巧
- 直接取文本:小区名、地址直接
s.Find(".info p.mt10 a span").Text()。 - 链接提取 id:
s.Find("dd.info p.title a").Attr("href")返回一个Option类型,用IsSome()判断存在后用Unwrap()取出,再按_与.htm拆分得到remoteId。 - 正则式字符串拆分:这是本规则最有代表性的部分。房源信息行的原始文本形如
3室2厅 | 低层|共33层 | 南向 | 建筑年代:2015年,代码用strings.Fields按空白切分为 4 段,再逐一清洗:
roomLine := strings.Fields(roomLineTmp) if len(roomLine) == 4 { roomsTmp := roomLine[0] // "3室2厅" roomsTmp = strings.Replace(roomsTmp, "厅", "", 1) roomsS := strings.Split(roomsTmp, "室") // ["3", "2"] rooms, halls = roomsS[0], roomsS[1] buildingTmpSec := strings.Split(roomLine[1], "(共") // ["低层|", "33层)"] locationType = strings.Replace(buildingTmpSec[0], "|", "", 1) totalFloor = strings.Replace(buildingTmpSec[1], "层)", "", 1) buildTime = strings.Replace(roomLine[3], "|建筑年代:", "", 1) direction = strings.Replace(roomLine[2], "|", "", 1) direction = strings.Replace(direction, "向", "", 1) }地址同样利用strings.Split(address, "-")把"商圈-小区"拆成商圈与地址两段,实现一个选择器喂出两个字段。
结果回传:map[int] 索引与 ItemFields 的映射
解析完成后调用:
ctx.Output(map[int]interface{}{ 0: strings.Trim(communityName, " "), 1: strings.Trim(totalFloor, " "), // ... 依次对应 ItemFields 下标 12: strings.Trim(business, " "), })这里的关键机制在 Context.CreateItem:当传入map[int]interface{}时,pholcus 会按当前规则ItemFields的下标顺序将整数键映射为字段名——即0 → communityName、1 → totalFloor……12 → business。因此ItemFields的书写顺序必须与Output的整数键严格对应,这是静态规则中容易踩坑、但效率最高(无需重复写字段名)的输出方式。
Output生成的数据单元DataCell默认还会附带Url、ParentUrl、DownloadTime三个默认字段(除非蜘蛛设置NotDefaultField: true),见 app/spider/context.go。解析后的条目经爬虫引擎 crawler.Process 统一拉取并送入 Pipeline,最终落盘。
如何运行这条规则
规则已通过_ "github.com/andeya/pholcus/sample/static_rules"批量导入(pholcus_rules.go 中可见fang_resell_list的注册项),随 sample/main.go 一同编译:
go build -o pholcus ./sample/ ./pholcus -h # 查看全部参数与蜘蛛序号采用 Cmd 模式运行时,需通过-c_spider传入蜘蛛在列表中的序号(多蜘蛛以,分隔,传*表示全部),示例(cmd/pholcus-cmd.go 与 README.md):
pholcus -_ui=cmd -a_mode=0 -c_spider=<搜房规则序号> -a_outtype=csv \ -a_thread=20 -a_batchcap=5000 -a_pause=300 -a_proxyminute=0 \ -a_keyins="<pholcus><golang>" -a_limit=10 -a_success=true -a_failure=true常用参数说明:
| 参数 | 作用 |
|---|---|
-_ui | 操作界面:web/gui(仅 Windows)/cmd |
-a_mode | 运行模式:0单机、服务端、客户端(分布式) |
-c_spider | 选择蜘蛛序号(cmd 模式专有) |
-a_thread | 并发协程数,范围[1~99999] |
-a_pause | 平均暂停毫秒数,>=100,实际按 50%~200% 随机化 |
-a_limit | 采集上限(默认限制 URL 数),>=0 |
-a_outtype | 输出方式,如csv、mgo、mysql、kafka等 |
-a_batchcap | 分批输出容量[1~5000000] |
-a_proxyminute | 代理 IP 更换频率(/分钟),为 0 不使用代理 |
CSV 输出时(output_csv.go),文件会写入 UTF-8 BOM,表头即规则ItemFields的字段名,并追加"当前链接、上级链接、下载时间"三个默认列,输出目录由 config.ini 的textoutdir(默认pholcus_pkg/text_out)与任务开始时间共同决定。规则的subNamespace默认取RuleName(即fang_collection),因此多批次结果会按蜘蛛名__fang_collection的目录层级区分。
关于"页数过多导致蜘蛛崩溃"的源码级排查线索
readme 第 3 条记录了已知问题:"如果爬取的页面数太多会导致蜘蛛崩溃,原因未知,待查"。原文并未给出结论,本文不臆测根因,仅从当前仓库源码的防护与恢复机制出发,给出可验证的排查方向:
- Root 入口的 panic 防护:
spider.Start()对RuleTree.Root的调用包了defer/recover,只会记录Panic [root]日志而不会终止整个进程(app/spider/spider.go)。 - 请求处理链的 panic 防护:
crawler.Process对下载、解析全程有defer/recover,崩溃时会记录堆栈并调用DoHistory(req, false)将该请求记入失败队列(app/crawler/crawler.go)。 - 可重点观察的侧面:批量入队第 1~100 页时,若未对
-a_limit或调度矩阵做总量控制,瞬间入队的大量请求会全部进入调度矩阵等待拉取;结合-a_thread并发与-a_pause限速调小后复现,同时打开日志文件pholcus_pkg/logs/pholcus.log(路径定义见 config/config.go)检索Panic关键字,是定位"崩溃"发生在入队阶段还是下载/解析阶段的最直接手段。
由于原文档标注"原因未知,待查",以上仅为基于现有代码结构的排查建议,不作为崩溃结论。
小结与扩展方向
搜房二手房规则是一份典型的 pholcus 静态爬虫模板,麻雀虽小但五脏俱全:Spider注册、RuleTree分页入口、AddQueue请求入队、goqueryDOM 解析、字符串清洗、map[int]索引式Output回传,全部在 fang_resell_list.go 的 130 余行内闭环。基于它可以自然扩展的能力包括:
- 取消
for循环注释实现多页抓取,并用-a_limit控制总量、用-a_pause控制频率; - 利用已提取的
remoteId配合-a_success/-a_failure的历史记录机制实现增量去重; - 参照 sample/static_rules/README.md 的维护规范,为规则补充
AidFunc、Namespace/SubNamespace或切换mgo/mysql等输出后端。
如果想要对照更多解析技巧,仓库内 jdsearch、baidusearch 等规则与 app/spider/context.go 中的ContextAPI 注释(如Aid、SetTemp、SetTimer、JsAddQueue等)都是很好的参考资料。
- 后端
【免费下载链接】pholcus
Pholcus is a distributed high-concurrency crawler software written in pure golang
相关推荐
Pholcus 静态爬虫规则库(static_rules):规则结构、注册机制与社区维护规范全解析
Pholcus 静态爬虫规则库(static_rules):规则结构、注册机制与社区维护规范全解析 本文以 sample/static_rules/README
后端10分钟掌握mRemoteNG:一站式远程连接管理终极解决方案
10分钟掌握mRemoteNG:一站式远程连接管理终极解决方案 你是否经常需要在Windows远程桌面、Linux SSH终端、网络设备VNC等不同工具间频繁切
桌面应用网络Vigil协议解析:深入理解Manager和Reporter的HTTP API
Vigil协议解析:深入理解Manager和Reporter的HTTP API 🚦 Vigil 是一个开源的微服务状态页面监控工具,专为分布式基础设施设计。通
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考