ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

苹果CMS火车头接口实现:PHP自定义采集API与避坑指南

苹果CMS火车头接口实现:PHP自定义采集API与避坑指南 简介围绕苹果CMS与MAXCMS的自动化内容采集需求这份资源专门整理了火车头采集器所需的核心接口与工作流模板适合希望自动化采集视频、文章内容的站长或二次开发人员。包内共13个文件主要包含wpm工作流模板、ljobx任务配置、lgrp规则分组以及jiekou.php接口文件和使用说明txtwpm可导入采集器使用ljobx负责任务调度lgrp用于组织采集规则php文件用于服务端数据交互txt则是配置与调用指南整体仅54KB。已有470人学习下载。通过模板可快速复用苹果CMS8.x视频与文章站点的采集规则理解API调用和PHP接口的交互方式减少手工发布成本使用说明中还包含接口配置与导入步骤能帮助规避权限、参数校验等常见问题。适合具备一定PHP或CMS基础、正在搭建内容采集站的用户作为入门与参考。1. 苹果CMS火车头接口到底解决的是什么问题苹果CMS火车头接口这个标题拆开看就是两件事让火车头采集器能通过 API 从苹果CMS英文代号 maccms/maxcms读出视频列表和详情再用 web 发布接口把处理后的数据写回 mac_vod 表。很多人会把它当成“神器压缩包”其实这类 zip 里通常就是几个 PHP 接口文件、一段 SQL 脚本和若干采集规则模板本质上做的是数据对接不是前端自动爬网页。它适合正在维护苹果CMS站点、做数据迁移、或者想用火车头统一管理多个内容源的人。启动前必须确认内容源有授权别拿这套接口去采集无授权资源后面讲的所有参数和代码都建立在合规数据源的前提上。2. 先看懂 maxcms 采集接口的请求链路和字段映射2.1 火车头采集接口和普通网页采集差在哪普通网页采集要先去抓 HTML再根据正则或 XPath 从乱糟糟的标签里抠数据maxcms 采集接口直接换了一种玩法接口按固定参数返回结构化的 XML火车头只需要把“列表页地址”和“内容页地址”指向两个 PHP 文件即可。常见的接口地址形态是这样的curl http://your-site.com/api/locoy_list.php?aclisttype1pg1 curl http://your-site.com/api/locoy_detail.php?acdetailid1024参数ac表示动作type表示苹果CMS后台的分类 IDpg是页码id是视频 ID。火车头拿到列表接口返回的 XML 后会自动提取里面的链接再把链接作为内容页地址访问详情接口。相比直接抓网页这种方式的字段边界清楚不会因为页面改版把采集规则废掉。2.2 苹果CMS数据表里最关键的字段怎么映射苹果CMS的核心表叫mac_vod几乎所有采集接口做的事就是把外部字段写进这张表。下面这些字段在采集场景里基本都会用到API 返回字段mac_vod 字段火车头里怎么用titlevod_name标题发布时必填subtitlevod_sub副标题没有就留空covervod_pic封面图地址actorvod_actor演员多个用逗号分隔directorvod_director导演area / lang / yearvod_area / vod_lang / vod_year地区、语言、年份remarkvod_remarks更新状态比如“更新至12集”contentvod_content简介XML 里建议放 CDATAplay_fromvod_play_from播放器来源多个用 $$$ 分隔play_urlvod_play_url播放地址组格式见下vod_play_url是较容易写错的一个字段。苹果CMS约定同一播放器的多集合成一个段落集与集之间用#分隔集名和地址之间用$分隔多个播放器之间再用$$$分隔第1集$http://a.com/1.m3u8#第2集$http://a.com/2.m3u8$$$第1集$http://b.com/1.m3u8#第2集$http://b.com/2.m3u8采集接口拿到这个字符串后不要自作主张去拆分原样入库反而最安全。火车头端如果对$做了变量替换需要在发布模块里把 URL 里的美元符还原否则苹果CMS后台解析播放地址时会把它截断。2.3 列表接口为什么用 XML 而不是 JSON火车头对 RSS 2.0 的字段识别成本最低列表接口直接用 RSS 结构返回采集规则里写 XPath 时几乎不会踩空。JSON 也能用但字段多的时候正则容易漏。一个典型的列表响应长这样rss version2.0 channel item title![CDATA[明日边缘]]/title linkhttp://your-site.com/api/locoy_detail.php?acdetailamp;id1024/link description![CDATA[一段剧情简介]]/description /item /channel /rss这里最关键的是link它必须指向详情接口火车头会带着这个 URL 去请求内容页。description用 CDATA 包住是为了避免简介里的、破坏 XML 结构。接口返回时不要对中文做二次转义UTF-8 直接输出即可。3. 用 PHP 手写苹果CMS采集接口的最小实现3.1 列表接口分类、分页、发布时间排序先写一个可以直接放到站点/api目录下的列表接口。这个文件不依赖苹果CMS框架直接用 PDO 连数据库方便在不改动主程序的情况下调试。?php // 苹果CMS火车头接口列表输出最小实现 header(Content-Type: application/xml; charsetutf-8); $dsn mysql:host127.0.0.1;dbnamemaccms;charsetutf8mb4; $pdo new PDO($dsn, db_user, db_pass, [ PDO::ATTR_ERRMODE PDO::ERRMODE_EXCEPTION, ]); $typeId max(0, (int)($_GET[type] ?? 0)); $page max(1, (int)($_GET[pg] ?? 1)); $size min(50, max(10, (int)($_GET[pagesize] ?? 30))); $offset ($page - 1) * $size; if ($typeId 0) { $countSql SELECT COUNT(*) FROM mac_vod WHERE type_id :type_id; } else { $countSql SELECT COUNT(*) FROM mac_vod; } $countStmt $pdo-prepare($countSql); if ($typeId 0) { $countStmt-bindValue(:type_id, $typeId, PDO::PARAM_INT); } $countStmt-execute(); $total $countStmt-fetchColumn(); $listSql SELECT vod_id, vod_name, vod_pic, vod_actor, vod_director, vod_area, vod_lang, vod_year, vod_remarks, vod_content FROM mac_vod ; if ($typeId 0) { $listSql . WHERE type_id :type_id ; } $listSql . ORDER BY vod_time_add DESC LIMIT $offset, $size; $stmt $pdo-prepare($listSql); if ($typeId 0) { $stmt-bindValue(:type_id, $typeId, PDO::PARAM_INT); } $stmt-execute(); $rows $stmt-fetchAll(PDO::FETCH_ASSOC); $xml new DOMDocument(1.0, utf-8); $rss $xml-createElement(rss); $rss-setAttribute(version, 2.0); $channel $xml-createElement(channel); $rss-appendChild($channel); $apiBase http:// . ($_SERVER[HTTP_HOST] ?? 127.0.0.1) . /api/locoy_detail.php; foreach ($rows as $row) { $item $xml-createElement(item); $item-appendChild($xml-createElement(title, htmlspecialchars($row[vod_name]))); $item-appendChild($xml-createElement(link, $apiBase . ?acdetailid . $row[vod_id])); $desc $xml-createElement(description); $desc-appendChild($xml-createCDATASection($row[vod_content])); $item-appendChild($desc); $channel-appendChild($item); } echo $xml-saveXML();type用max(0, intval())约束成整数pg从 1 开始pagesize封顶 50这些参数在做苹果CMS api 调用时都要在接口侧做兜底避免有人把pagesize改成 999999 拖库。LIMIT $offset, $size里的两个变量已经转成整数可以安全拼接不需要担心 SQL 注入。htmlspecialchars只用在标题上description走 CDATA 而不是转义。3.2 详情接口把播放地址原样留给苹果CMS详情接口的逻辑更简单核心是拿着id查一条视频然后把标题、简介、播放来源、播放地址全部输出。播放地址这块有一个常见误区接口里对vod_play_url千万不要做htmlspecialchars否则$不会变但会变成amp;入库后播放地址就被破坏了。正确做法是放进 CDATA。?php // 苹果CMS火车头接口详情输出 $id max(0, (int)($_GET[id] ?? 0)); $stmt $pdo-prepare( SELECT vod_name, vod_pic, vod_actor, vod_director, vod_area, vod_lang, vod_year, vod_remarks, vod_content, vod_play_from, vod_play_url FROM mac_vod WHERE vod_id :id ); $stmt-bindValue(:id, $id, PDO::PARAM_INT); $stmt-execute(); $row $stmt-fetch(PDO::FETCH_ASSOC); if (!$row) { exit(empty); } header(Content-Type: application/xml; charsetutf-8); $xml new DOMDocument(1.0, utf-8); $item $xml-createElement(item); $item-appendChild($xml-createElement(title, htmlspecialchars($row[vod_name]))); $item-appendChild($xml-createElement(actor, htmlspecialchars($row[vod_actor]))); $playFrom $xml-createElement(play_from); $playFrom-appendChild($xml-createCDATASection($row[vod_play_from])); $item-appendChild($playFrom); $playUrl $xml-createElement(play_url); $playUrl-appendChild($xml-createCDATASection($row[vod_play_url])); $item-appendChild($playUrl); $content $xml-createElement(content); $content-appendChild($xml-createCDATASection($row[vod_content])); $item-appendChild($content); echo $xml-saveXML();play_from和play_url的对应关系要严格保持一致。如果play_from是m3u8$$$youku那么play_url里也必须有两个用$$$分隔的段落否则苹果CMS后台读取播放器来源时会找不到对应的播放地址。这个规则在写外部 api 服务时最容易漏漏掉之后前台会显示“加载失败”。3.3 苹果CMS api 调用的参数约定参数示例说明aclist / detail动作列表还是详情type1苹果CMS后台的分类 IDpg2页码从 1 开始pagesize30每页条数接口内上限 50id1024acdetail 时必填这套参数不是 Restful 风格就是最传统的 GET 参数。字段名一旦定下来火车头采集规则、发布模块、接口文件三处必须保持一致。很多“接口不工作”的问题不在 PHP 代码而是火车头发布模块里把play_url写成了playurl或者列表接口返回的link漏了id参数。4. 火车头端配置和 maxcms 发布接口的坑4.1 列表地址和内容地址怎么填在火车头里新建采集规则时列表地址直接填带参数的接口地址。常见做法是把分类 ID 做成下拉范围把页码做成递增范围http://your-site.com/api/locoy_list.php?aclisttype[分类:1,2,3,4]pg[页码:1,10,1]pagesize30列表区域的 XPath 按 RSS 结构写列表链接//item/link/text() 列表标题//item/title/text() 内容标题//item/title/text() 内容简介//item/content/text() 内容播放地址//item/play_url/text()火车头会自动把列表里取到的链接当成内容页地址所以详情接口不需要再配置一个“内容地址模板”。如果列表接口返回的link写成了固定域名换域名采集时要记得同步修改接口文件这个坑比 PHP 本身更容易踩。4.2 API 返回特殊字符导致播放地址被截断我用这套接口最常见的故障是播放地址后半段消失。原因通常是接口文件用echo $row[vod_play_url]直接输出URL 里的触发了 XML 解析错误或者被采集规则误认为属性结束符。解决办法有两个一是接口里统一用 CDATA 包播放地址二是发布模块里对play_url做一次str_replace([amp;, lt;], [, ], $value)。还要提醒一点火车头本身有变量替换逻辑$在某些规则里会被误判成变量边界。如果发现入库后的播放地址少了$优先看发布模块里有没有开启“URL 解码”或“特殊字符替换”把这两个选项关掉即可。提示接口文件里不要对vod_play_url调用stripslashes。苹果CMS字段本身不需要转义多转一次反而会让$、#被吞掉。4.3 web 发布接口、类型映射和重复判断火车头采集完数据后通过 web 发布模块向苹果CMS提交入库。发布接口不一定要写在苹果CMS框架里独立 PHP 文件也能完成插入只是要自己维护分类映射。下面是一个可复制的发布端骨架?php // locoy_publish.php $typeMap [1 18, 2 19, 3 20]; // 火车头分类 - mac_vod.type_id $typeId $typeMap[(int)($_POST[type] ?? 0)] ?? 1; $stmt $pdo-prepare(SELECT vod_id FROM mac_vod WHERE vod_name ?); $stmt-execute([trim($_POST[title] ?? )]); if ($stmt-fetch()) { echo json_encode([code 0, msg exists]); exit; } $sql INSERT INTO mac_vod (type_id, vod_name, vod_pic, vod_area, vod_lang, vod_year, vod_actor, vod_director, vod_remarks, vod_content, vod_play_from, vod_play_url, vod_time_add) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); $pdo-prepare($sql)-execute([ $typeId, trim($_POST[title] ?? ), $_POST[pic] ?? , $_POST[area] ?? , $_POST[lang] ?? , (int)($_POST[year] ?? 0), $_POST[actor] ?? , $_POST[director] ?? , $_POST[remark] ?? , $_POST[content] ?? , $_POST[play_from] ?? m3u8, $_POST[play_url] ?? , time() ]); echo json_encode([code 1, msg ok]);发布模块字段与数据库字段的对应关系可以参考这张表火车头发布字段数据库字段说明typetype_id必须经过 typeMap 转换titlevod_name重复判断依据pic / contentvod_pic / vod_content建议原样入库play_from / play_urlvod_play_from / vod_play_url保持 $$$/# 分隔remarkvod_remarks更新状态重复判断只按vod_name比较会误伤同名但不同年份的影片你可以改成vod_name vod_year联合判断。接口返回 JSON 后火车头发布模块里用一次正则code:1判断是否发布成功即可。5. 给苹果CMS采集接口加上签名、缓存和验证5.1 用签名挡住非授权 API 调用采集接口一旦挂到公网就会被别人拿来当免费数据源。常见做法是在列表和详情接口里都加一个sign参数用hash_hmac签名$secret 换成你自己的随机字符串; $type (int)($_GET[type] ?? 0); $page (int)($_GET[pg] ?? 1); $expect hash_hmac(sha256, $type . | . $page, $secret); if (!hash_equals($expect, $_GET[sign] ?? )) { exit(api error: invalid sign); }签名只防随手调用不防专业爬虫别把 secret 写进前端 JS。火车头规则里填的地址要改成带sign的完整地址比如pg从 1 到 10 时sign 也要跟着页码变化。5.2 给列表接口加 60 秒 APCu 缓存火车头多线程采集时同一个列表页会被反复请求。最直接的做法是在列表接口里套一层 APCu 缓存只缓存列表 XML不缓存详情接口因为详情接口需要保证播放地址最新。$cacheKey locoy_list_ . $typeId . _ . $page . _ . $size; if (function_exists(apcu_fetch) apcu_fetch($cacheKey)) { header(Content-Type: application/xml; charsetutf-8); echo apcu_fetch($cacheKey); exit; } // 生成 XML 后执行缓存写入 if (function_exists(apcu_store)) { apcu_store($cacheKey, $xml-saveXML(), 60); }没有 APCu 的环境可以用file_put_contents写到runtime目录但要注意生成缓存文件的并发冲突写文件时先写好临时文件再rename。5.3 用 curl 完成一次完整验证接口部署完不要直接进火车头先用 curl 把链路走一遍curl -s http://127.0.0.1/api/locoy_list.php?aclisttype1pg1signxxx | head -c 2000 curl -s http://127.0.0.1/api/locoy_detail.php?acdetailid1signxxx | xmllint --format -没有 xmllint 就用浏览器直接访问详情地址右键查看源代码。验证时重点看三件事列表里的link是否指向详情接口、play_url是否完整出现在 CDATA 里、play_from的段数是否和play_url一致。返回的 XML 能同时看到 title、link、play_url就说明这条苹果CMS火车头接口链路已经通了。本文还有配套的精品资源点击获取
返回列表