Compare commits
8 Commits
66a8086a17
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0096805a49 | ||
|
|
7f910ee22f | ||
|
|
97aefcf86b | ||
|
|
b764e7555d | ||
|
|
04242363a8 | ||
|
|
c1ac050c6a | ||
|
|
b943ea2ab7 | ||
|
|
e568577ce0 |
1
code/.gitignore
vendored
1
code/.gitignore
vendored
@@ -21,4 +21,5 @@ public/static/favicon/generated/*
|
|||||||
/app/public/_admin_templates/video-metadata-missing-task-pool/*
|
/app/public/_admin_templates/video-metadata-missing-task-pool/*
|
||||||
/app/public/_admin_templates/video-metadata-missing-workbench/*
|
/app/public/_admin_templates/video-metadata-missing-workbench/*
|
||||||
/data/seo_copy_published/*
|
/data/seo_copy_published/*
|
||||||
|
/data/seo_resource/keyword_feedback/*
|
||||||
/storage/*
|
/storage/*
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use app\admin\controller\Index;
|
|||||||
use app\admin\controller\Domain;
|
use app\admin\controller\Domain;
|
||||||
use app\admin\controller\SeoSupply;
|
use app\admin\controller\SeoSupply;
|
||||||
use app\admin\controller\Novel;
|
use app\admin\controller\Novel;
|
||||||
|
use app\admin\controller\ServerNode;
|
||||||
use app\admin\controller\Site;
|
use app\admin\controller\Site;
|
||||||
use app\admin\controller\SystemConfig;
|
use app\admin\controller\SystemConfig;
|
||||||
use app\admin\controller\Video;
|
use app\admin\controller\Video;
|
||||||
@@ -32,6 +33,9 @@ Route::group("/system", function () {
|
|||||||
Route::post("/config/save", [SystemConfig::class, "saveSystemConfig"])->name("SystemConfig@saveSystemConfig");
|
Route::post("/config/save", [SystemConfig::class, "saveSystemConfig"])->name("SystemConfig@saveSystemConfig");
|
||||||
Route::post("/config/seo-ai-rules/reset", [SystemConfig::class, "resetSeoAiRules"])->name("SystemConfig@resetSeoAiRules");
|
Route::post("/config/seo-ai-rules/reset", [SystemConfig::class, "resetSeoAiRules"])->name("SystemConfig@resetSeoAiRules");
|
||||||
Route::get("/storage/file", [SystemConfig::class, "previewStorageFile"])->name("SystemConfig@previewStorageFile");
|
Route::get("/storage/file", [SystemConfig::class, "previewStorageFile"])->name("SystemConfig@previewStorageFile");
|
||||||
|
Route::get("/node/list", [ServerNode::class, "getServerNodeList"])->name("ServerNode@getServerNodeList");
|
||||||
|
Route::post("/node/save", [ServerNode::class, "saveServerNode"])->name("ServerNode@saveServerNode");
|
||||||
|
Route::post("/node/del", [ServerNode::class, "delServerNode"])->name("ServerNode@delServerNode");
|
||||||
|
|
||||||
Route::get("/cjpz/list", [SystemConfig::class, "getCaiJiPeiZhiList"])->name("SystemConfig@getCaiJiPeiZhiList");
|
Route::get("/cjpz/list", [SystemConfig::class, "getCaiJiPeiZhiList"])->name("SystemConfig@getCaiJiPeiZhiList");
|
||||||
Route::post("/cjpz/save", [SystemConfig::class, "saveCaiJiPeiZhi"])->name("SystemConfig@saveCaiJiPeiZhi");
|
Route::post("/cjpz/save", [SystemConfig::class, "saveCaiJiPeiZhi"])->name("SystemConfig@saveCaiJiPeiZhi");
|
||||||
|
|||||||
210
code/app/admin/controller/ServerNode.php
Normal file
210
code/app/admin/controller/ServerNode.php
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\admin\controller;
|
||||||
|
|
||||||
|
use app\admin\BaseController;
|
||||||
|
use app\model\AdminUserModel;
|
||||||
|
use app\model\ServerNodeModel;
|
||||||
|
use app\Request;
|
||||||
|
use think\Response;
|
||||||
|
|
||||||
|
class ServerNode extends BaseController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 前端服务器节点列表
|
||||||
|
*/
|
||||||
|
public function getServerNodeList(Request $Request, ?AdminUserModel $AdminUserModel): Response
|
||||||
|
{
|
||||||
|
$arrData = [
|
||||||
|
'page' => (int)$Request->get('page', 1),
|
||||||
|
'limit' => (int)$Request->get('limit', 10),
|
||||||
|
'key' => trim((string)$Request->get('key', '')),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->validate($arrData, [
|
||||||
|
'page' => 'require|number',
|
||||||
|
'limit' => 'require|number',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$ServerNodeModel = ServerNodeModel::alias('sn')
|
||||||
|
->order('sn.sn_status', 'desc')
|
||||||
|
->order('sn.updated_at', 'desc')
|
||||||
|
->order('sn.sn_id', 'desc');
|
||||||
|
|
||||||
|
if ($arrData['key'] !== '') {
|
||||||
|
$strKey = $arrData['key'];
|
||||||
|
$ServerNodeModel->where(function ($query) use ($strKey) {
|
||||||
|
$query->whereOr([
|
||||||
|
['sn.sn_name', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_code', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_host', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_username', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_region', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_purpose', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_project_dir', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_log_dir', 'like', '%' . $strKey . '%'],
|
||||||
|
['sn.sn_nginx_dir', 'like', '%' . $strKey . '%'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$Paginate = $ServerNodeModel->paginate([
|
||||||
|
'list_rows' => $arrData['limit'],
|
||||||
|
'page' => $arrData['page'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$arrItems = [];
|
||||||
|
foreach ($Paginate->items() as $arrItem) {
|
||||||
|
$arrItems[] = $this->serializeServerNodeRow($arrItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success([
|
||||||
|
'items' => $arrItems,
|
||||||
|
'total' => $Paginate->total(),
|
||||||
|
'current_page' => $Paginate->currentPage(),
|
||||||
|
'total_pages' => $Paginate->lastPage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存前端服务器节点
|
||||||
|
*/
|
||||||
|
public function saveServerNode(Request $Request, ?AdminUserModel $AdminUserModel): Response
|
||||||
|
{
|
||||||
|
$arrData = [
|
||||||
|
'sn_id' => $Request->post('sn_id'),
|
||||||
|
'sn_name' => trim((string)$Request->post('sn_name', '')),
|
||||||
|
'sn_code' => $this->normalizeNullableString($Request->post('sn_code')),
|
||||||
|
'sn_host' => trim((string)$Request->post('sn_host', '')),
|
||||||
|
'sn_port' => (int)$Request->post('sn_port', 22),
|
||||||
|
'sn_username' => trim((string)$Request->post('sn_username', '')),
|
||||||
|
'sn_auth_type' => trim((string)$Request->post('sn_auth_type', 'password')),
|
||||||
|
'sn_password' => trim((string)$Request->post('sn_password', '')),
|
||||||
|
'sn_private_key' => trim((string)$Request->post('sn_private_key', '')),
|
||||||
|
'sn_passphrase' => trim((string)$Request->post('sn_passphrase', '')),
|
||||||
|
'sn_region' => $this->normalizeNullableString($Request->post('sn_region')),
|
||||||
|
'sn_purpose' => $this->normalizeNullableString($Request->post('sn_purpose')),
|
||||||
|
'sn_project_dir' => $this->normalizeNullableString($Request->post('sn_project_dir')),
|
||||||
|
'sn_log_dir' => $this->normalizeNullableString($Request->post('sn_log_dir')),
|
||||||
|
'sn_nginx_dir' => $this->normalizeNullableString($Request->post('sn_nginx_dir')),
|
||||||
|
'sn_note' => $this->normalizeNullableString($Request->post('sn_note')),
|
||||||
|
'sn_status' => (int)$Request->post('sn_status', 1),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->validate($arrData, [
|
||||||
|
'sn_name' => 'require|max:255',
|
||||||
|
'sn_host' => 'require|max:255',
|
||||||
|
'sn_port' => 'require|number|between:1,65535',
|
||||||
|
'sn_username' => 'require|max:100',
|
||||||
|
'sn_auth_type' => 'require|in:password,private_key',
|
||||||
|
'sn_status' => 'require|in:0,1',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$boolIsCreate = empty($arrData['sn_id']);
|
||||||
|
if ($boolIsCreate) {
|
||||||
|
$ServerNodeModel = new ServerNodeModel();
|
||||||
|
} else {
|
||||||
|
$ServerNodeModel = ServerNodeModel::where('sn_id', (int)$arrData['sn_id'])->find();
|
||||||
|
if (empty($ServerNodeModel)) {
|
||||||
|
return $this->error('9993', '服务器节点不存在');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($arrData['sn_code'] !== null) {
|
||||||
|
$DuplicateModel = ServerNodeModel::where('sn_code', $arrData['sn_code']);
|
||||||
|
if (!$boolIsCreate) {
|
||||||
|
$DuplicateModel->where('sn_id', '<>', (int)$arrData['sn_id']);
|
||||||
|
}
|
||||||
|
if ($DuplicateModel->find() !== null) {
|
||||||
|
return $this->error('9993', '节点编码已存在,请更换后重试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$strCurrentAuthType = trim((string)($ServerNodeModel->sn_auth_type ?? ''));
|
||||||
|
$boolHasExistingPassword = trim((string)($ServerNodeModel->sn_password ?? '')) !== '';
|
||||||
|
$boolHasExistingPrivateKey = trim((string)($ServerNodeModel->sn_private_key ?? '')) !== '';
|
||||||
|
|
||||||
|
if ($arrData['sn_auth_type'] === 'password') {
|
||||||
|
if ($arrData['sn_password'] === '') {
|
||||||
|
if ($boolIsCreate || $strCurrentAuthType !== 'password' || !$boolHasExistingPassword) {
|
||||||
|
return $this->error('9993', '当前登录方式为密码,请填写 SSH 密码');
|
||||||
|
}
|
||||||
|
unset($arrData['sn_password']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrData['sn_private_key'] = '';
|
||||||
|
$arrData['sn_passphrase'] = '';
|
||||||
|
} else {
|
||||||
|
if ($arrData['sn_private_key'] === '') {
|
||||||
|
if ($boolIsCreate || $strCurrentAuthType !== 'private_key' || !$boolHasExistingPrivateKey) {
|
||||||
|
return $this->error('9993', '当前登录方式为私钥,请填写 SSH 私钥');
|
||||||
|
}
|
||||||
|
unset($arrData['sn_private_key']);
|
||||||
|
if ($arrData['sn_passphrase'] === '') {
|
||||||
|
unset($arrData['sn_passphrase']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrData['sn_password'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$ServerNodeModel->fill($arrData);
|
||||||
|
$ServerNodeModel->save();
|
||||||
|
|
||||||
|
return $this->success([
|
||||||
|
'sn_id' => (int)$ServerNodeModel->sn_id,
|
||||||
|
], $boolIsCreate ? '服务器节点新增成功' : '服务器节点保存成功');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除前端服务器节点
|
||||||
|
*/
|
||||||
|
public function delServerNode(Request $Request, ?AdminUserModel $AdminUserModel): Response
|
||||||
|
{
|
||||||
|
$arrData = [
|
||||||
|
'sn_id' => trim((string)$Request->post('sn_id', '')),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->validate($arrData, [
|
||||||
|
'sn_id' => 'require',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$arrIds = array_values(array_unique(array_filter(array_map('intval', explode(',', $arrData['sn_id'])), static function (int $intId): bool {
|
||||||
|
return $intId > 0;
|
||||||
|
})));
|
||||||
|
|
||||||
|
if ($arrIds === []) {
|
||||||
|
return $this->error('9993', '未识别到可删除的服务器节点');
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerNodeModel::whereIn('sn_id', $arrIds)->delete();
|
||||||
|
|
||||||
|
return $this->success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 屏蔽列表接口里的敏感 SSH 凭证,只返回配置状态。
|
||||||
|
*/
|
||||||
|
protected function serializeServerNodeRow($arrItem): array
|
||||||
|
{
|
||||||
|
$arrRow = is_array($arrItem) ? $arrItem : $arrItem->toArray();
|
||||||
|
$arrRow['sn_port'] = (int)($arrRow['sn_port'] ?? 22);
|
||||||
|
$arrRow['sn_status'] = (int)($arrRow['sn_status'] ?? 1);
|
||||||
|
$arrRow['sn_password_configured'] = trim((string)($arrRow['sn_password'] ?? '')) !== '';
|
||||||
|
$arrRow['sn_private_key_configured'] = trim((string)($arrRow['sn_private_key'] ?? '')) !== '';
|
||||||
|
$arrRow['sn_passphrase_configured'] = trim((string)($arrRow['sn_passphrase'] ?? '')) !== '';
|
||||||
|
|
||||||
|
unset($arrRow['sn_password'], $arrRow['sn_private_key'], $arrRow['sn_passphrase']);
|
||||||
|
|
||||||
|
return $arrRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function normalizeNullableString($value): ?string
|
||||||
|
{
|
||||||
|
$strValue = trim((string)$value);
|
||||||
|
|
||||||
|
return $strValue === '' ? null : $strValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -776,18 +776,24 @@ namespace {
|
|||||||
return $strZh;
|
return $strZh;
|
||||||
}
|
}
|
||||||
|
|
||||||
$strPinYinToolsPath = root_path() . '/extend/tools/pinyin-tool';
|
$strText = trim($strZh);
|
||||||
|
|
||||||
$strPinYin = shell_exec(sprintf("%s %s", $strPinYinToolsPath, escapeshellcmd($strZh)));
|
if (class_exists(\Transliterator::class)) {
|
||||||
|
$Transliterator = \Transliterator::create('Han-Latin; Latin-ASCII; Lower()');
|
||||||
$strPinYin = trim((string) $strPinYin);
|
if ($Transliterator !== null) {
|
||||||
|
$strText = (string) $Transliterator->transliterate($strText);
|
||||||
if (!is_string($strPinYin) || trim($strPinYin) === '') {
|
}
|
||||||
return 'k_' . substr(sha1($strZh), 0, 12);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$strText = strtolower($strText);
|
||||||
|
$strText = preg_replace('/[^a-z0-9]+/i', '-', $strText) ?? '';
|
||||||
|
$strText = trim($strText, '-');
|
||||||
|
|
||||||
return $strPinYin;
|
if ($strText === '') {
|
||||||
|
return 'k-' . substr(sha1($strZh), 0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $strText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -864,17 +870,41 @@ namespace {
|
|||||||
*/
|
*/
|
||||||
function convertToWebP(string $strInputFile, string $strOutputFile, int $intQuality = 80): bool
|
function convertToWebP(string $strInputFile, string $strOutputFile, int $intQuality = 80): bool
|
||||||
{
|
{
|
||||||
$strCwebpPath = root_path() . '/extend/tools/cwebp';
|
if (!is_file($strInputFile) || !function_exists('imagewebp')) {
|
||||||
|
|
||||||
$strCMD = escapeshellcmd("$strCwebpPath -q $intQuality " . escapeshellarg($strInputFile) . " -o " . escapeshellarg($strOutputFile));
|
|
||||||
|
|
||||||
exec($strCMD . ' 2>&1', $strOutput, $intReturnCode);
|
|
||||||
|
|
||||||
if ($intReturnCode === 0) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$arrImageInfo = @getimagesize($strInputFile);
|
||||||
|
if (!is_array($arrImageInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Image = match ($arrImageInfo[2] ?? null) {
|
||||||
|
IMAGETYPE_JPEG => @imagecreatefromjpeg($strInputFile),
|
||||||
|
IMAGETYPE_PNG => @imagecreatefrompng($strInputFile),
|
||||||
|
IMAGETYPE_GIF => @imagecreatefromgif($strInputFile),
|
||||||
|
IMAGETYPE_WEBP => function_exists('imagecreatefromwebp') ? @imagecreatefromwebp($strInputFile) : false,
|
||||||
|
default => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($Image === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
imagepalettetotruecolor($Image);
|
||||||
|
imagealphablending($Image, true);
|
||||||
|
imagesavealpha($Image, true);
|
||||||
|
|
||||||
|
$strOutputDir = dirname($strOutputFile);
|
||||||
|
if (!is_dir($strOutputDir) && !@mkdir($strOutputDir, 0777, true) && !is_dir($strOutputDir)) {
|
||||||
|
imagedestroy($Image);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$boolResult = @imagewebp($Image, $strOutputFile, max(0, min(100, $intQuality)));
|
||||||
|
imagedestroy($Image);
|
||||||
|
|
||||||
|
return $boolResult && is_file($strOutputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class DomainExternalSeoSnapshotAnalysisHelper
|
|||||||
|
|
||||||
$arrProviders = [];
|
$arrProviders = [];
|
||||||
$arrHosts = [];
|
$arrHosts = [];
|
||||||
$arrLatestIndexByHost = [];
|
$arrLatestSignalsByHost = [];
|
||||||
$intKeywordSnapshots = (int)SeoExternalSnapshotModel::where('metric_date', '>=', $strStartDate)
|
$intKeywordSnapshots = (int)SeoExternalSnapshotModel::where('metric_date', '>=', $strStartDate)
|
||||||
->where('scope', 'keyword')
|
->where('scope', 'keyword')
|
||||||
->count();
|
->count();
|
||||||
@@ -28,9 +28,10 @@ class DomainExternalSeoSnapshotAnalysisHelper
|
|||||||
self::eachSnapshotRow(
|
self::eachSnapshotRow(
|
||||||
SeoExternalSnapshotModel::where('metric_date', '>=', $strStartDate)
|
SeoExternalSnapshotModel::where('metric_date', '>=', $strStartDate)
|
||||||
->where('scope', 'host'),
|
->where('scope', 'host'),
|
||||||
['id', 'provider', 'host', 'scope', 'metric_date', 'status', 'indexed_status', 'baidu_pc_ip_range', 'baidu_mobile_ip_range', 'pc_keyword_count', 'mobile_keyword_count', 'queried_at'],
|
['id', 'provider', 'snapshot_type', 'host', 'scope', 'metric_date', 'status', 'indexed_status', 'result_count_text', 'baidu_pc_ip_range', 'baidu_mobile_ip_range', 'pc_keyword_count', 'mobile_keyword_count', 'queried_at'],
|
||||||
static function (array $arrItem) use (&$arrProviders, &$arrHosts, &$arrLatestIndexByHost, &$strLatestMetricDate): void {
|
static function (array $arrItem) use (&$arrProviders, &$arrHosts, &$arrLatestSignalsByHost, &$strLatestMetricDate): void {
|
||||||
$strProvider = trim((string)($arrItem['provider'] ?? ''));
|
$strProvider = trim((string)($arrItem['provider'] ?? ''));
|
||||||
|
$strSnapshotType = trim((string)($arrItem['snapshot_type'] ?? ''));
|
||||||
$strHost = trim((string)($arrItem['host'] ?? ''));
|
$strHost = trim((string)($arrItem['host'] ?? ''));
|
||||||
$strMetricDate = trim((string)($arrItem['metric_date'] ?? ''));
|
$strMetricDate = trim((string)($arrItem['metric_date'] ?? ''));
|
||||||
$strStatus = trim((string)($arrItem['status'] ?? ''));
|
$strStatus = trim((string)($arrItem['status'] ?? ''));
|
||||||
@@ -48,34 +49,33 @@ class DomainExternalSeoSnapshotAnalysisHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($strHost !== '') {
|
if ($strHost !== '') {
|
||||||
$strHostKey = $strHost;
|
$arrCandidate = [
|
||||||
$arrCurrent = $arrLatestIndexByHost[$strHostKey] ?? null;
|
|
||||||
$boolShouldReplace = false;
|
|
||||||
if (!$arrCurrent) {
|
|
||||||
$boolShouldReplace = true;
|
|
||||||
} else {
|
|
||||||
$strCurrentDate = (string)($arrCurrent['metric_date'] ?? '');
|
|
||||||
$intCurrentQueriedAt = (int)($arrCurrent['queried_at'] ?? 0);
|
|
||||||
if (strcmp($strCurrentDate, $strMetricDate) < 0) {
|
|
||||||
$boolShouldReplace = true;
|
|
||||||
} elseif ($strCurrentDate === $strMetricDate && $intCurrentQueriedAt < $intQueriedAt) {
|
|
||||||
$boolShouldReplace = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($boolShouldReplace) {
|
|
||||||
$arrLatestIndexByHost[$strHostKey] = [
|
|
||||||
'host' => $strHost,
|
'host' => $strHost,
|
||||||
'provider' => $strProvider,
|
'provider' => $strProvider,
|
||||||
|
'snapshot_type' => $strSnapshotType,
|
||||||
'metric_date' => $strMetricDate,
|
'metric_date' => $strMetricDate,
|
||||||
'queried_at' => $intQueriedAt,
|
'queried_at' => $intQueriedAt,
|
||||||
'status' => $strStatus,
|
'status' => $strStatus,
|
||||||
'indexed_status' => $strIndexedStatus,
|
'indexed_status' => $strIndexedStatus,
|
||||||
|
'result_count_text' => trim((string)($arrItem['result_count_text'] ?? '')),
|
||||||
'baidu_pc_ip_range' => trim((string)($arrItem['baidu_pc_ip_range'] ?? '')),
|
'baidu_pc_ip_range' => trim((string)($arrItem['baidu_pc_ip_range'] ?? '')),
|
||||||
'baidu_mobile_ip_range' => trim((string)($arrItem['baidu_mobile_ip_range'] ?? '')),
|
'baidu_mobile_ip_range' => trim((string)($arrItem['baidu_mobile_ip_range'] ?? '')),
|
||||||
'pc_keyword_count' => (int)($arrItem['pc_keyword_count'] ?? 0),
|
'pc_keyword_count' => (int)($arrItem['pc_keyword_count'] ?? 0),
|
||||||
'mobile_keyword_count' => (int)($arrItem['mobile_keyword_count'] ?? 0),
|
'mobile_keyword_count' => (int)($arrItem['mobile_keyword_count'] ?? 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (self::shouldReplaceSnapshot($arrLatestSignalsByHost[$strHost]['display'] ?? null, $strMetricDate, $intQueriedAt)) {
|
||||||
|
$arrLatestSignalsByHost[$strHost]['display'] = $arrCandidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($strSnapshotType === 'site_query'
|
||||||
|
&& self::shouldReplaceSnapshot($arrLatestSignalsByHost[$strHost]['index'] ?? null, $strMetricDate, $intQueriedAt)) {
|
||||||
|
$arrLatestSignalsByHost[$strHost]['index'] = $arrCandidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($strSnapshotType === 'aizhan_summary'
|
||||||
|
&& self::shouldReplaceSnapshot($arrLatestSignalsByHost[$strHost]['keyword'] ?? null, $strMetricDate, $intQueriedAt)) {
|
||||||
|
$arrLatestSignalsByHost[$strHost]['keyword'] = $arrCandidate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -85,13 +85,44 @@ class DomainExternalSeoSnapshotAnalysisHelper
|
|||||||
$intIndexedLikeCount = 0;
|
$intIndexedLikeCount = 0;
|
||||||
$intKeywordReadyCount = 0;
|
$intKeywordReadyCount = 0;
|
||||||
$intTrafficReadyCount = 0;
|
$intTrafficReadyCount = 0;
|
||||||
$arrHostRows = array_values($arrLatestIndexByHost);
|
$arrHostRows = [];
|
||||||
|
|
||||||
|
foreach ($arrLatestSignalsByHost as $strHost => $arrSignals) {
|
||||||
|
$arrDisplay = (array)($arrSignals['display'] ?? []);
|
||||||
|
$arrIndex = (array)($arrSignals['index'] ?? []);
|
||||||
|
$arrKeyword = (array)($arrSignals['keyword'] ?? []);
|
||||||
|
$arrProvidersForHost = [];
|
||||||
|
|
||||||
|
foreach ([$arrIndex, $arrKeyword, $arrDisplay] as $arrSignalRow) {
|
||||||
|
$strSignalProvider = trim((string)($arrSignalRow['provider'] ?? ''));
|
||||||
|
if ($strSignalProvider !== '') {
|
||||||
|
$arrProvidersForHost[$strSignalProvider] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrHostRows[] = [
|
||||||
|
'host' => $strHost,
|
||||||
|
'provider' => implode(',', array_keys($arrProvidersForHost)),
|
||||||
|
'index_provider' => (string)($arrIndex['provider'] ?? ''),
|
||||||
|
'keyword_provider' => (string)($arrKeyword['provider'] ?? ''),
|
||||||
|
'metric_date' => max((string)($arrDisplay['metric_date'] ?? ''), (string)($arrIndex['metric_date'] ?? ''), (string)($arrKeyword['metric_date'] ?? '')),
|
||||||
|
'queried_at' => max((int)($arrDisplay['queried_at'] ?? 0), (int)($arrIndex['queried_at'] ?? 0), (int)($arrKeyword['queried_at'] ?? 0)),
|
||||||
|
'status' => (string)($arrDisplay['status'] ?? ''),
|
||||||
|
'indexed_status' => (string)($arrIndex['indexed_status'] ?? ''),
|
||||||
|
'result_count_text' => (string)($arrIndex['result_count_text'] ?? ''),
|
||||||
|
'baidu_pc_ip_range' => (string)($arrKeyword['baidu_pc_ip_range'] ?? ''),
|
||||||
|
'baidu_mobile_ip_range' => (string)($arrKeyword['baidu_mobile_ip_range'] ?? ''),
|
||||||
|
'pc_keyword_count' => (int)($arrKeyword['pc_keyword_count'] ?? 0),
|
||||||
|
'mobile_keyword_count' => (int)($arrKeyword['mobile_keyword_count'] ?? 0),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($arrHostRows as &$arrRow) {
|
foreach ($arrHostRows as &$arrRow) {
|
||||||
$boolIndexedLike = (string)($arrRow['indexed_status'] ?? '') === 'indexed_like';
|
$boolIndexedLike = self::normalizeIndexState($arrRow) === 'indexed_like';
|
||||||
$boolKeywordReady = (int)($arrRow['pc_keyword_count'] ?? 0) > 0 || (int)($arrRow['mobile_keyword_count'] ?? 0) > 0;
|
$boolKeywordReady = (int)($arrRow['pc_keyword_count'] ?? 0) > 0 || (int)($arrRow['mobile_keyword_count'] ?? 0) > 0;
|
||||||
$boolTrafficReady = !self::isZeroRange((string)($arrRow['baidu_pc_ip_range'] ?? ''))
|
$boolTrafficReady = !self::isZeroRange((string)($arrRow['baidu_pc_ip_range'] ?? ''))
|
||||||
|| !self::isZeroRange((string)($arrRow['baidu_mobile_ip_range'] ?? ''));
|
|| !self::isZeroRange((string)($arrRow['baidu_mobile_ip_range'] ?? ''));
|
||||||
|
$arrRow['indexed_like'] = $boolIndexedLike;
|
||||||
$arrRow['keyword_ready'] = $boolKeywordReady;
|
$arrRow['keyword_ready'] = $boolKeywordReady;
|
||||||
$arrRow['traffic_ready'] = $boolTrafficReady;
|
$arrRow['traffic_ready'] = $boolTrafficReady;
|
||||||
|
|
||||||
@@ -113,6 +144,11 @@ class DomainExternalSeoSnapshotAnalysisHelper
|
|||||||
if ($intLeftKeyword !== $intRightKeyword) {
|
if ($intLeftKeyword !== $intRightKeyword) {
|
||||||
return $intRightKeyword <=> $intLeftKeyword;
|
return $intRightKeyword <=> $intLeftKeyword;
|
||||||
}
|
}
|
||||||
|
$intLeftIndexed = !empty($arrLeft['indexed_like']) ? 1 : 0;
|
||||||
|
$intRightIndexed = !empty($arrRight['indexed_like']) ? 1 : 0;
|
||||||
|
if ($intLeftIndexed !== $intRightIndexed) {
|
||||||
|
return $intRightIndexed <=> $intLeftIndexed;
|
||||||
|
}
|
||||||
return strcmp((string)($arrLeft['host'] ?? ''), (string)($arrRight['host'] ?? ''));
|
return strcmp((string)($arrLeft['host'] ?? ''), (string)($arrRight['host'] ?? ''));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -402,6 +438,19 @@ class DomainExternalSeoSnapshotAnalysisHelper
|
|||||||
return $strRange === '' || $strRange === '0 ~ 0' || $strRange === '0~0';
|
return $strRange === '' || $strRange === '0 ~ 0' || $strRange === '0~0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function shouldReplaceSnapshot(?array $arrCurrent, string $strMetricDate, int $intQueriedAt): bool
|
||||||
|
{
|
||||||
|
if (!$arrCurrent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$strCurrentDate = (string)($arrCurrent['metric_date'] ?? '');
|
||||||
|
$intCurrentQueriedAt = (int)($arrCurrent['queried_at'] ?? 0);
|
||||||
|
|
||||||
|
return strcmp($strCurrentDate, $strMetricDate) < 0
|
||||||
|
|| ($strCurrentDate === $strMetricDate && $intCurrentQueriedAt < $intQueriedAt);
|
||||||
|
}
|
||||||
|
|
||||||
protected static function normalizeIndexState(array $arrRow): string
|
protected static function normalizeIndexState(array $arrRow): string
|
||||||
{
|
{
|
||||||
$strIndexedStatus = trim((string)($arrRow['indexed_status'] ?? ''));
|
$strIndexedStatus = trim((string)($arrRow['indexed_status'] ?? ''));
|
||||||
|
|||||||
@@ -27,14 +27,6 @@ class JsBuilder
|
|||||||
@mkdir($targetDir, 0755, true);
|
@mkdir($targetDir, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 输出文件名(域名专属缓存)
|
|
||||||
$targetFile = $targetDir . "{$staticHash}.js";
|
|
||||||
|
|
||||||
// 如果已经生成过,直接返回
|
|
||||||
if (file_exists($targetFile)) {
|
|
||||||
return "/static/js/compiled/{$staticHash}.js";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 你可以像 CSS 一样在这里挂一个“全站基础 JS”
|
// 你可以像 CSS 一样在这里挂一个“全站基础 JS”
|
||||||
// 注意:如果没有这个文件,就别写入,否则会被 skip
|
// 注意:如果没有这个文件,就别写入,否则会被 skip
|
||||||
$listJs = [
|
$listJs = [
|
||||||
@@ -46,9 +38,46 @@ class JsBuilder
|
|||||||
$finalJsFiles = array_merge($listJs, $jsFiles);
|
$finalJsFiles = array_merge($listJs, $jsFiles);
|
||||||
$finalJsFiles = array_values(array_unique(array_filter($finalJsFiles)));
|
$finalJsFiles = array_values(array_unique(array_filter($finalJsFiles)));
|
||||||
|
|
||||||
|
$signatureParts = [
|
||||||
|
'static_hash' => $staticHash,
|
||||||
|
'dom_prefix' => $domPrefix,
|
||||||
|
'builder' => is_file(__FILE__) ? sha1_file(__FILE__) : (string)@filemtime(__FILE__),
|
||||||
|
'files' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
// 如果 compiled 已存在且比所有源文件都新,直接返回;否则自动重建。
|
||||||
|
$intLatestSourceTime = @filemtime(__FILE__) ?: 0;
|
||||||
|
foreach ($finalJsFiles as $file) {
|
||||||
|
$file = ltrim((string)$file, '/');
|
||||||
|
$path = $baseDir . $file;
|
||||||
|
if (is_file($path)) {
|
||||||
|
$intLatestSourceTime = max($intLatestSourceTime, (int)@filemtime($path));
|
||||||
|
$signatureParts['files'][] = [
|
||||||
|
'file' => $file,
|
||||||
|
'mtime' => (int)@filemtime($path),
|
||||||
|
'size' => (int)@filesize($path),
|
||||||
|
'sha1' => sha1_file($path),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$signatureParts['files'][] = [
|
||||||
|
'file' => $file,
|
||||||
|
'missing' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前端代理的静态缓存按 path 命中,query version 无法兜底;文件名必须跟随源码变化。
|
||||||
|
$sourceHash = substr(sha1((string)json_encode($signatureParts, JSON_UNESCAPED_SLASHES)), 0, 10);
|
||||||
|
$targetName = "{$staticHash}-{$sourceHash}.js";
|
||||||
|
$targetFile = $targetDir . $targetName;
|
||||||
|
|
||||||
|
if (file_exists($targetFile) && (int)@filemtime($targetFile) >= $intLatestSourceTime) {
|
||||||
|
return "/static/js/compiled/{$targetName}";
|
||||||
|
}
|
||||||
|
|
||||||
// 合并 JS 文件内容
|
// 合并 JS 文件内容
|
||||||
$allJs = "";
|
$allJs = "";
|
||||||
$allJs .= "/*! compiled: {$staticHash}.js */\n";
|
$allJs .= "/*! compiled: {$targetName} */\n";
|
||||||
$allJs .= "(function(){\n'use strict';\n";
|
$allJs .= "(function(){\n'use strict';\n";
|
||||||
|
|
||||||
foreach ($finalJsFiles as $file) {
|
foreach ($finalJsFiles as $file) {
|
||||||
@@ -82,6 +111,6 @@ class JsBuilder
|
|||||||
file_put_contents($targetFile, $allJs);
|
file_put_contents($targetFile, $allJs);
|
||||||
|
|
||||||
// 返回前端可访问路径
|
// 返回前端可访问路径
|
||||||
return "/static/js/compiled/{$staticHash}.js";
|
return "/static/js/compiled/{$targetName}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ if ($strTmpCode == 'videoGpt1') {
|
|||||||
return view('rss/baidu.xml')->contentType('text/xml');
|
return view('rss/baidu.xml')->contentType('text/xml');
|
||||||
})->ext('xml');
|
})->ext('xml');
|
||||||
|
|
||||||
$routeGetHead('rss/so', function () {
|
$routeGetHead('rss/so', function (\think\Request $Request, SiteContext $SiteContext) {
|
||||||
return view('rss/so.xml')->contentType('text/xml');
|
return $SiteContext->getSoSitemapResponse();
|
||||||
})->ext('xml');
|
})->ext('xml');
|
||||||
|
|
||||||
$routeGetHead('/sitemap_index', function (\think\Request $Request, SiteContext $SiteContext) {
|
$routeGetHead('/sitemap_index', function (\think\Request $Request, SiteContext $SiteContext) {
|
||||||
@@ -413,9 +413,8 @@ if ($strTmpCode == 'videoGpt1') {
|
|||||||
/**
|
/**
|
||||||
* /rss/so
|
* /rss/so
|
||||||
*/
|
*/
|
||||||
Route::get('rss/so', function () {
|
Route::get('rss/so', function (\think\Request $Request, SiteContext $SiteContext) {
|
||||||
return view('rss/so.xml')
|
return $SiteContext->getSoSitemapResponse();
|
||||||
->contentType('text/xml');
|
|
||||||
})->ext('xml');
|
})->ext('xml');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ sort_type="news"
|
|||||||
d_key="d_key" d_val="Video" cache_life="86400"}
|
d_key="d_key" d_val="Video" cache_life="86400"}
|
||||||
|
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>https://www.{$DomainModel->d_domain}{site:vurl v_id='$Video.v_id' v_py='$Video.v_name_en'/}</loc>
|
<loc>https://{$DomainModel->d_domain}{site:vurl v_id='$Video.v_id' v_py='$Video.v_name_en'/}</loc>
|
||||||
<lastmod>{$Video.v_publish_date}</lastmod>
|
<lastmod>{$Video.v_publish_date}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ cache_life="3600" func="generateCategoryPager" export_name="resData" /}
|
|||||||
|
|
||||||
{foreach $resData.data as $key=>$Novel}
|
{foreach $resData.data as $key=>$Novel}
|
||||||
<url>
|
<url>
|
||||||
<loc>https://www.{$DomainModel->d_domain}{site:nclurl n_id="$Novel.n_id" n_py="$Novel.n_name_pinyin" order="zheng" page="1"/}</loc>
|
<loc>https://{$DomainModel->d_domain}{site:nclurl n_id="$Novel.n_id" n_py="$Novel.n_name_pinyin" order="zheng" page="1"/}</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ cache_life="3600" func="generateCategoryPager" export_name="resData" /}
|
|||||||
|
|
||||||
{foreach $resData.data as $key=>$Novel}
|
{foreach $resData.data as $key=>$Novel}
|
||||||
<url>
|
<url>
|
||||||
<loc>https://www.{$DomainModel->d_domain}{site:nurl n_id="$Novel->n_id" n_py="$Novel->n_name_pinyin"/}</loc>
|
<loc>https://{$DomainModel->d_domain}{site:nurl n_id="$Novel->n_id" n_py="$Novel->n_name_pinyin"/}</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ cache_life="3600" func="generateCategoryPager" export_name="resData" /}
|
|||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
{foreach $resData.data as $key=>$Novel}
|
{foreach $resData.data as $key=>$Novel}
|
||||||
<url>
|
<url>
|
||||||
<loc>https://www.{$DomainModel->d_domain}{site:lcpurl n_id="$Novel.n_id" n_py="$Novel.n_name_pinyin" /}</loc>
|
<loc>https://{$DomainModel->d_domain}{site:lcpurl n_id="$Novel.n_id" n_py="$Novel.n_name_pinyin" /}</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.6</priority>
|
<priority>0.6</priority>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url>
|
<url>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/</loc>
|
<loc>https://{$DomainModel->d_domain}/</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
<changefreq>daily</changefreq>
|
<changefreq>daily</changefreq>
|
||||||
<priority>1.0</priority>
|
<priority>1.0</priority>
|
||||||
</url>
|
</url>
|
||||||
|
|
||||||
<url>
|
<url>
|
||||||
<loc>https://www.{$DomainModel->d_domain}{$strRankUrlTemp}</loc>
|
<loc>https://{$DomainModel->d_domain}{$strRankUrlTemp}</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
<changefreq>daily</changefreq>
|
<changefreq>daily</changefreq>
|
||||||
<priority>1.0</priority>
|
<priority>1.0</priority>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<!-- 状态 -->
|
<!-- 状态 -->
|
||||||
{novel:status d_key="status_key" d_val="strStatusName"}
|
{novel:status d_key="status_key" d_val="strStatusName"}
|
||||||
<url>
|
<url>
|
||||||
<loc>https://www.{$DomainModel->d_domain}{site:nflurl category="$strCategoryPinyin" order="$sort_key" status="$status_key" /}</loc>
|
<loc>https://{$DomainModel->d_domain}{site:nflurl category="$strCategoryPinyin" order="$sort_key" status="$status_key" /}</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
<changefreq>weekly</changefreq>
|
<changefreq>weekly</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ cache_life="3600" func="generateCategoryPager" export_name="resData" /}
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/sitemap-main.xml</loc>
|
<loc>https://{$DomainModel->d_domain}/sitemap-main.xml</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
|
|
||||||
<!--小说总数量/50000 得出 sitemap-books 一共有多少个 -->
|
<!--小说总数量/50000 得出 sitemap-books 一共有多少个 -->
|
||||||
{for start="0" end="$resData.p_data.pages"}
|
{for start="0" end="$resData.p_data.pages"}
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/sitemap-books-{$i+1}.xml</loc>
|
<loc>https://{$DomainModel->d_domain}/sitemap-books-{$i+1}.xml</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
{/for}
|
{/for}
|
||||||
@@ -22,7 +22,7 @@ cache_life="3600" func="generateCategoryPager" export_name="resData" /}
|
|||||||
<!-- 小说总数量/50000 得出 sitemap-books-catalog一共有多少个,每个小说只取一个目录链接,分页不需要加入去 -->
|
<!-- 小说总数量/50000 得出 sitemap-books-catalog一共有多少个,每个小说只取一个目录链接,分页不需要加入去 -->
|
||||||
{for start="0" end="$resData.p_data.pages"}
|
{for start="0" end="$resData.p_data.pages"}
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/sitemap-books-catalog-{$i+1}.xml</loc>
|
<loc>https://{$DomainModel->d_domain}/sitemap-books-catalog-{$i+1}.xml</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
{/for}
|
{/for}
|
||||||
@@ -30,7 +30,7 @@ cache_life="3600" func="generateCategoryPager" export_name="resData" /}
|
|||||||
<!-- 小说章节取最新章节 -->
|
<!-- 小说章节取最新章节 -->
|
||||||
{for start="0" end="$resData.p_data.pages"}
|
{for start="0" end="$resData.p_data.pages"}
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/sitemap-chapters-{$i+1}.xml</loc>
|
<loc>https://{$DomainModel->d_domain}/sitemap-chapters-{$i+1}.xml</loc>
|
||||||
<lastmod>{:date('Y-m-d')}</lastmod>
|
<lastmod>{:date('Y-m-d')}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
{/for}
|
{/for}
|
||||||
|
|||||||
@@ -1017,9 +1017,11 @@ class DomainModel extends BaseModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!is_array($this->t_cfg) || !array_key_exists($strKey, $this->t_cfg)) {
|
if (!is_array($this->t_cfg) || !array_key_exists($strKey, $this->t_cfg)) {
|
||||||
|
$strFallbackValue = $this->resolveLegacyTemplateFallback((string)$strKey);
|
||||||
|
if ($strFallbackValue !== null) {
|
||||||
|
return $strFallbackValue;
|
||||||
|
}
|
||||||
return '';
|
return '';
|
||||||
$strError = sprintf("t_cfg [%s] not found! %s ", $strKey , $strDomain . '-' . $strController . '-' . $strAction. '-' . $strDiff. '-' . $boolJoin.'-'.request()->url);
|
|
||||||
throw new \Exception($strError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$intSfgId = $this->t_cfg[$strKey]['sfg_id'];
|
$intSfgId = $this->t_cfg[$strKey]['sfg_id'];
|
||||||
@@ -1074,6 +1076,76 @@ class DomainModel extends BaseModel
|
|||||||
return $SubjectFomartModel->sf_val;
|
return $SubjectFomartModel->sf_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function resolveLegacyTemplateFallback(string $strKey): ?string
|
||||||
|
{
|
||||||
|
if (!is_array($this->t_cfg) || !isset($this->t_cfg['pages'], $this->t_cfg['url_family'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrSeoKeyMap = [
|
||||||
|
'VIDEO@INDEX@INDEX@TITLE' => ['title', 'home'],
|
||||||
|
'VIDEO@INDEX@INDEX@KEYWORDS' => ['keywords', 'home'],
|
||||||
|
'VIDEO@INDEX@INDEX@DESCRIPTION' => ['description', 'home'],
|
||||||
|
'VIDEO@GETCATEGORYINDEX@TITLE' => ['title', 'category_index'],
|
||||||
|
'VIDEO@GETCATEGORYINDEX@KEYWORDS' => ['keywords', 'category_index'],
|
||||||
|
'VIDEO@GETCATEGORYINDEX@DESCRIPTION' => ['description', 'category_index'],
|
||||||
|
'VIDEO@GETCATEGORY@TITLE' => ['title', 'category_list'],
|
||||||
|
'VIDEO@GETCATEGORY@KEYWORDS' => ['keywords', 'category_list'],
|
||||||
|
'VIDEO@GETCATEGORY@DESCRIPTION' => ['description', 'category_list'],
|
||||||
|
'VIDEO@GETSEARCHVIDEO@TITLE' => ['title', 'search'],
|
||||||
|
'VIDEO@GETSEARCHVIDEO@KEYWORDS' => ['keywords', 'search'],
|
||||||
|
'VIDEO@GETSEARCHVIDEO@DESCRIPTION' => ['description', 'search'],
|
||||||
|
'VIDEO@GETVIDEORANKINDEX@TITLE' => ['title', 'rank_index'],
|
||||||
|
'VIDEO@GETVIDEORANKINDEX@KEYWORDS' => ['keywords', 'rank_index'],
|
||||||
|
'VIDEO@GETVIDEORANKINDEX@DESCRIPTION' => ['description', 'rank_index'],
|
||||||
|
'VIDEO@GETVIDEORANKLIST@TITLE' => ['title', 'rank_list'],
|
||||||
|
'VIDEO@GETVIDEORANKLIST@KEYWORDS' => ['keywords', 'rank_list'],
|
||||||
|
'VIDEO@GETVIDEORANKLIST@DESCRIPTION' => ['description', 'rank_list'],
|
||||||
|
'VIDEO@GETVIDEOINFO@TITLE' => ['title', 'detail'],
|
||||||
|
'VIDEO@GETVIDEOINFO@KEYWORDS' => ['keywords', 'detail'],
|
||||||
|
'VIDEO@GETVIDEOINFO@DESCRIPTION' => ['description', 'detail'],
|
||||||
|
'VIDEO@GETVIDEOPLAY@TITLE' => ['title', 'play'],
|
||||||
|
'VIDEO@GETVIDEOPLAY@KEYWORDS' => ['keywords', 'play'],
|
||||||
|
'VIDEO@GETVIDEOPLAY@DESCRIPTION' => ['description', 'play'],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($arrSeoKeyMap[$strKey])) {
|
||||||
|
[$strSeoCode, $strSeoPage] = $arrSeoKeyMap[$strKey];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$SiteContext = \think\Container::getInstance()->make(\app\services\SiteContext::class);
|
||||||
|
return (string)$SiteContext->getSeoTkd($strSeoCode, $strSeoPage);
|
||||||
|
} catch (\Throwable $Throwable) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$arrRuntimeStyle = \app\common\helper\SiteStyle::getConfig($this, (string)($this->d_domain ?? ''));
|
||||||
|
$UrlBuilder = new \app\common\helper\UrlBuilder($arrRuntimeStyle);
|
||||||
|
} catch (\Throwable $Throwable) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$strTemplateCode = (string)(request()->TemplatesModel->t_code ?? '');
|
||||||
|
if ($strTemplateCode !== '' && $strTemplateCode !== 'videoGpt1') {
|
||||||
|
return match ($strKey) {
|
||||||
|
'VIDEO_RANK_INDEX_URL' => '/phb-index',
|
||||||
|
'VIDEO_SEARCH_LIST_URL' => '/query.html',
|
||||||
|
'VIDEO_HISTORY_LIST_URL' => '/history.html',
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($strKey) {
|
||||||
|
'VIDEO_CATEGORY_INDEX_URL' => $UrlBuilder->categoryHome(),
|
||||||
|
'VIDEO_RANK_INDEX_URL' => $UrlBuilder->rankIndex(),
|
||||||
|
'VIDEO_SEARCH_LIST_URL' => $UrlBuilder->searchEntry(),
|
||||||
|
'VIDEO_HISTORY_LIST_URL' => $UrlBuilder->history(),
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undocumented function
|
* Undocumented function
|
||||||
*
|
*
|
||||||
|
|||||||
18
code/app/model/ServerNodeModel.php
Normal file
18
code/app/model/ServerNodeModel.php
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace app\model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前端服务器节点模型
|
||||||
|
*
|
||||||
|
* @mixin \think\Model
|
||||||
|
*/
|
||||||
|
class ServerNodeModel extends BaseModel
|
||||||
|
{
|
||||||
|
protected $name = 'server_node';
|
||||||
|
protected $pk = 'sn_id';
|
||||||
|
protected $createTime = 'created_at';
|
||||||
|
protected $updateTime = 'updated_at';
|
||||||
|
}
|
||||||
@@ -172,6 +172,53 @@ class VideoModel extends MongoModel
|
|||||||
return $this->findManyWithCache($arrFilter, $intCount, $arrSort, $arrOptions, $strKey, $intLifeTime);
|
return $this->findManyWithCache($arrFilter, $intCount, $arrSort, $arrOptions, $strKey, $intLifeTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 轻量级 sitemap / rss 列表,只取生成 URL 需要的字段,避免大对象缓存撑爆内存。
|
||||||
|
*/
|
||||||
|
public function findSitemapItemsWithCache(
|
||||||
|
array $arrFilter,
|
||||||
|
int $intCount = 1000,
|
||||||
|
array $arrSort = [],
|
||||||
|
string $strKey = '',
|
||||||
|
int $intLifeTime = 24 * 3600
|
||||||
|
): array {
|
||||||
|
try {
|
||||||
|
$arrResult = $this->checkCacheByKey($strKey);
|
||||||
|
if ($arrResult !== NULL) {
|
||||||
|
return is_array($arrResult) ? $arrResult : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrOptions = self::$arrOptions;
|
||||||
|
$arrOptions['projection'] = [
|
||||||
|
'_id' => 0,
|
||||||
|
'v_id' => 1,
|
||||||
|
'v_name_en' => 1,
|
||||||
|
'v_publish_date' => 1,
|
||||||
|
'created_at' => 1,
|
||||||
|
'updated_at' => 1,
|
||||||
|
];
|
||||||
|
$arrOptions['limit'] = max(1, $intCount);
|
||||||
|
|
||||||
|
if (!empty($arrSort)) {
|
||||||
|
$arrOptions['sort'] = $arrSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Cursor = $this->getCol()->find($arrFilter, $arrOptions);
|
||||||
|
$arrResult = iterator_to_array($Cursor);
|
||||||
|
|
||||||
|
foreach ($arrResult as &$arrItem) {
|
||||||
|
applyToKeys($arrItem, ['created_at', 'updated_at'], 'formatMongoDate');
|
||||||
|
}
|
||||||
|
unset($arrItem);
|
||||||
|
|
||||||
|
$this->setCacheByKey($strKey, $arrResult, $intLifeTime);
|
||||||
|
|
||||||
|
return $arrResult;
|
||||||
|
} catch (\Throwable $Throwable) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find one Video
|
* find one Video
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use app\model\ChapterModel;
|
|||||||
use app\model\SystemConfigModel;
|
use app\model\SystemConfigModel;
|
||||||
use app\model\NovelClicksModel;
|
use app\model\NovelClicksModel;
|
||||||
use app\model\NovelModel;
|
use app\model\NovelModel;
|
||||||
|
use app\model\VideoModel;
|
||||||
use app\common\helper\SiteStyle;
|
use app\common\helper\SiteStyle;
|
||||||
use app\common\helper\CssBuilder;
|
use app\common\helper\CssBuilder;
|
||||||
use app\common\helper\JsBuilder;
|
use app\common\helper\JsBuilder;
|
||||||
@@ -515,7 +516,10 @@ class SiteContext
|
|||||||
|
|
||||||
public function getSiteMapByCode(string $strCode): Response
|
public function getSiteMapByCode(string $strCode): Response
|
||||||
{
|
{
|
||||||
$strFile = root_path('storage/SiteMap') . $this->DomainModel->d_domain . '/';
|
$strFile = rtrim((string)root_path('storage/SiteMap'), DIRECTORY_SEPARATOR)
|
||||||
|
. DIRECTORY_SEPARATOR
|
||||||
|
. $this->DomainModel->d_domain
|
||||||
|
. DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
$intPage = $this->Request->route('page', 1);
|
$intPage = $this->Request->route('page', 1);
|
||||||
|
|
||||||
@@ -566,6 +570,72 @@ class SiteContext
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容旧站的 /rss/so.xml。
|
||||||
|
* 避免走模板标签 video:list 一次性读取/缓存大量完整视频文档导致内存溢出。
|
||||||
|
*/
|
||||||
|
public function getSoSitemapResponse(): Response
|
||||||
|
{
|
||||||
|
$strDomain = trim((string)($this->DomainModel->d_domain ?? ''));
|
||||||
|
$strHost = $strDomain === '' ? trim((string)$this->Request->host()) : $strDomain;
|
||||||
|
$strCacheKey = sprintf('SiteContext:getSoSitemapResponse:%s', $strHost);
|
||||||
|
|
||||||
|
$arrRows = VideoModel::getInstance()->findSitemapItemsWithCache(
|
||||||
|
[],
|
||||||
|
1000,
|
||||||
|
['created_at' => -1, 'v_id' => -1],
|
||||||
|
$strCacheKey,
|
||||||
|
86400
|
||||||
|
);
|
||||||
|
|
||||||
|
$arrXml = [
|
||||||
|
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||||
|
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
||||||
|
];
|
||||||
|
|
||||||
|
$VideoService = app(VideoService::class);
|
||||||
|
foreach ($arrRows as $arrVideo) {
|
||||||
|
$intVId = (int)($arrVideo['v_id'] ?? 0);
|
||||||
|
$strSlug = trim((string)($arrVideo['v_name_en'] ?? ''));
|
||||||
|
if ($intVId <= 0 || $strSlug === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$strPath = $VideoService->getVideoInfoUrl($intVId, $strSlug);
|
||||||
|
if ($strPath === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$strLoc = 'https://' . $strHost . $strPath;
|
||||||
|
$strLastmod = trim((string)($arrVideo['v_publish_date'] ?? ''));
|
||||||
|
if ($strLastmod === '') {
|
||||||
|
$strLastmod = trim((string)($arrVideo['updated_at'] ?? ''));
|
||||||
|
}
|
||||||
|
if ($strLastmod === '') {
|
||||||
|
$strLastmod = trim((string)($arrVideo['created_at'] ?? ''));
|
||||||
|
}
|
||||||
|
if ($strLastmod !== '') {
|
||||||
|
$intTs = strtotime($strLastmod);
|
||||||
|
if ($intTs !== false) {
|
||||||
|
$strLastmod = date('Y-m-d', $intTs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrXml[] = '<url>';
|
||||||
|
$arrXml[] = '<loc>' . htmlspecialchars($strLoc, ENT_QUOTES | ENT_XML1, 'UTF-8') . '</loc>';
|
||||||
|
if ($strLastmod !== '') {
|
||||||
|
$arrXml[] = '<lastmod>' . htmlspecialchars($strLastmod, ENT_QUOTES | ENT_XML1, 'UTF-8') . '</lastmod>';
|
||||||
|
}
|
||||||
|
$arrXml[] = '</url>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrXml[] = '</urlset>';
|
||||||
|
|
||||||
|
return response(implode("\n", $arrXml), 200, [
|
||||||
|
'Content-Type' => 'application/xml; charset=UTF-8',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 限速访问
|
* 限速访问
|
||||||
*
|
*
|
||||||
@@ -817,6 +887,11 @@ class SiteContext
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$arrTemplateCfg = is_array($this->DomainModel->t_cfg ?? null) ? $this->DomainModel->t_cfg : [];
|
||||||
|
if (!array_key_exists($strLegacyKey, $arrTemplateCfg)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $this->normalizeSeoText($this->converterTemplate($strLegacyKey));
|
return $this->normalizeSeoText($this->converterTemplate($strLegacyKey));
|
||||||
} catch (\Throwable $Throwable) {
|
} catch (\Throwable $Throwable) {
|
||||||
|
|||||||
@@ -1293,7 +1293,9 @@ class VideoService
|
|||||||
$arrData = SeoCopyFallbackBuilder::build($strScene, $this->buildSeoCopyFacts($strScene, $arrOptions));
|
$arrData = SeoCopyFallbackBuilder::build($strScene, $this->buildSeoCopyFacts($strScene, $arrOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->normalizeSeoCopyBlock($strScene, $arrData);
|
$arrData = $this->normalizeSeoCopyBlock($strScene, $arrData);
|
||||||
|
|
||||||
|
return $this->enrichSeoCopyBlockWithKeywordFeedback($strScene, $arrData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function mergeLegacySeoCopyWithDefault(string $strHost, string $strScene, array $arrPageKeys, array $arrData): array
|
private function mergeLegacySeoCopyWithDefault(string $strHost, string $strScene, array $arrPageKeys, array $arrData): array
|
||||||
@@ -1560,6 +1562,134 @@ class VideoService
|
|||||||
return $arrMerged;
|
return $arrMerged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function enrichSeoCopyBlockWithKeywordFeedback(string $strScene, array $arrData): array
|
||||||
|
{
|
||||||
|
if (!in_array($strScene, ['home', 'category_index', 'category_list', 'search'], true)) {
|
||||||
|
return $arrData;
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrFeedback = $this->getSeoResourceKeywordFeedback();
|
||||||
|
$arrKeywords = (array)($arrFeedback['keywords'] ?? []);
|
||||||
|
if (empty($arrKeywords)) {
|
||||||
|
return $arrData;
|
||||||
|
}
|
||||||
|
|
||||||
|
$strKeywordText = implode('、', array_slice($arrKeywords, 0, 3));
|
||||||
|
if ($strKeywordText === '') {
|
||||||
|
return $arrData;
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrData['_keyword_feedback'] = [
|
||||||
|
'source' => (string)($arrFeedback['source'] ?? 'seo_resource_keyword_feedback'),
|
||||||
|
'latest_metric_date' => (string)($arrFeedback['latest_metric_date'] ?? ''),
|
||||||
|
'indexed_like' => (bool)($arrFeedback['indexed_like'] ?? false),
|
||||||
|
'keyword_count' => count($arrKeywords),
|
||||||
|
'keywords' => $arrKeywords,
|
||||||
|
];
|
||||||
|
|
||||||
|
$strIntroMeta = trim((string)($arrData['intro_meta'] ?? ''));
|
||||||
|
if ($strIntroMeta !== '' && mb_strpos($strIntroMeta, $arrKeywords[0]) === false) {
|
||||||
|
$strIntroMeta = preg_replace('/[。;;]+$/u', '', $strIntroMeta) ?? $strIntroMeta;
|
||||||
|
$arrData['intro_meta'] = $strIntroMeta . ',近期重点承接:' . $strKeywordText . '。';
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrCards = (array)($arrData['guide_cards'] ?? []);
|
||||||
|
foreach ($arrCards as $arrCard) {
|
||||||
|
if (is_array($arrCard) && mb_strpos((string)($arrCard['text'] ?? ''), $arrKeywords[0]) !== false) {
|
||||||
|
return $arrData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrCards[] = [
|
||||||
|
'title' => '近期检索方向',
|
||||||
|
'text' => '外部反馈更集中在' . $strKeywordText . '等方向,本页优先承接相关分类、搜索、详情和播放入口。',
|
||||||
|
];
|
||||||
|
$arrData['guide_cards'] = array_slice($arrCards, 0, 5);
|
||||||
|
|
||||||
|
return $arrData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSeoResourceKeywordFeedback(): array
|
||||||
|
{
|
||||||
|
$strHost = trim((string)($this->SiteContext->DomainModel->d_domain ?? ''));
|
||||||
|
if ($strHost === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$strHostKey = strtolower($strHost);
|
||||||
|
$strHostKey = preg_replace('/^www\./', '', $strHostKey) ?? $strHostKey;
|
||||||
|
$strHostKey = preg_replace('/[^a-z0-9]+/', '-', $strHostKey) ?? $strHostKey;
|
||||||
|
$strHostKey = trim($strHostKey, '-');
|
||||||
|
if ($strHostKey === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$strPath = dirname(__DIR__, 2) . '/data/seo_resource/keyword_feedback/by_host/' . $strHostKey . '.json';
|
||||||
|
if (!is_file($strPath)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$strJson = @file_get_contents($strPath);
|
||||||
|
if ($strJson === false || trim($strJson) === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrPayload = json_decode($strJson, true);
|
||||||
|
if (!is_array($arrPayload)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$arrSummary = (array)($arrPayload['summary'] ?? []);
|
||||||
|
$arrKeywords = [];
|
||||||
|
foreach ((array)($arrPayload['keywords'] ?? []) as $arrKeyword) {
|
||||||
|
if (!is_array($arrKeyword)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$strKeyword = $this->normalizeSeoFeedbackKeyword((string)($arrKeyword['keyword'] ?? ''));
|
||||||
|
if ($strKeyword === '' || in_array($strKeyword, $arrKeywords, true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$arrKeywords[] = $strKeyword;
|
||||||
|
if (count($arrKeywords) >= 3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($arrKeywords)) {
|
||||||
|
$strDomainKeyword = $this->normalizeSeoFeedbackKeyword((string)($arrPayload['domain_keyword'] ?? ''));
|
||||||
|
if ($strDomainKeyword !== '') {
|
||||||
|
$arrKeywords[] = $strDomainKeyword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($arrKeywords)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'source' => (string)($arrPayload['generated_by'] ?? 'seo_resource_keyword_feedback'),
|
||||||
|
'latest_metric_date' => (string)($arrSummary['latest_metric_date'] ?? ''),
|
||||||
|
'indexed_like' => (bool)($arrSummary['indexed_like'] ?? false),
|
||||||
|
'keywords' => $arrKeywords,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeSeoFeedbackKeyword(string $strKeyword): string
|
||||||
|
{
|
||||||
|
$strKeyword = trim($strKeyword);
|
||||||
|
if ($strKeyword === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$strKeyword = preg_replace('/\s+/u', '', $strKeyword) ?? $strKeyword;
|
||||||
|
$strKeyword = trim($strKeyword, " \t\n\r\0\x0B,,、。;;||");
|
||||||
|
if ($strKeyword === '' || mb_strlen($strKeyword) > 48) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $strKeyword;
|
||||||
|
}
|
||||||
|
|
||||||
private function interpolateSeoCopyData(array $arrData, array $arrTokens): array
|
private function interpolateSeoCopyData(array $arrData, array $arrTokens): array
|
||||||
{
|
{
|
||||||
foreach ($arrData as $strKey => $mValue) {
|
foreach ($arrData as $strKey => $mValue) {
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ class BaiduPushVideoUrlLogic
|
|||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
$strApi = 'http://data.zz.baidu.com/urls?site=https://www.' . $domain . '&token=' . $strBaiduToken;
|
$strApi = 'http://data.zz.baidu.com/urls?site=https://' . $domain . '&token=' . $strBaiduToken;
|
||||||
// $strApi = 'http://data.zz.baidu.com/urls?site=https://www.aaggc.com&token=B4bzeDDBHhnoBnov';
|
// $strApi = 'http://data.zz.baidu.com/urls?site=https://aaggc.com&token=B4bzeDDBHhnoBnov';
|
||||||
|
|
||||||
// 1️⃣ 读取 txt 文件
|
// 1️⃣ 读取 txt 文件
|
||||||
$txtFiles = glob($domainDir . '/*.txt');
|
$txtFiles = glob($domainDir . '/*.txt');
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class SiteMapLogic
|
|||||||
$this->arrNovelStatus = StaticConfig::$arrNovelStatus;
|
$this->arrNovelStatus = StaticConfig::$arrNovelStatus;
|
||||||
|
|
||||||
$this->strDate = date('Y-m-d');
|
$this->strDate = date('Y-m-d');
|
||||||
$this->strSiteMapPath = root_path('storage/SiteMap');
|
$this->strSiteMapPath = rtrim((string)root_path('storage/SiteMap'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
$this->NovelModel = NovelModel::getInstance();
|
$this->NovelModel = NovelModel::getInstance();
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class VideoSiteMapLogic
|
|||||||
$this->arrVideoYear = StaticConfig::$arrVideoYear;
|
$this->arrVideoYear = StaticConfig::$arrVideoYear;
|
||||||
|
|
||||||
$this->strDate = date('Y-m-d');
|
$this->strDate = date('Y-m-d');
|
||||||
$this->strSiteMapPath = root_path('storage/SiteMap');
|
$this->strSiteMapPath = rtrim((string)root_path('storage/SiteMap'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
$this->VideoModel = VideoModel::getInstance();
|
$this->VideoModel = VideoModel::getInstance();
|
||||||
|
|
||||||
@@ -213,6 +213,7 @@ EOF;
|
|||||||
$strMapVideosFileTxt = sprintf('%s/sitemap-videos-%s.txt', $strDomainDir, $intPage);
|
$strMapVideosFileTxt = sprintf('%s/sitemap-videos-%s.txt', $strDomainDir, $intPage);
|
||||||
|
|
||||||
file_put_contents($strMapVideosFile, $strHead);
|
file_put_contents($strMapVideosFile, $strHead);
|
||||||
|
file_put_contents($strMapVideosFileTxt, '');
|
||||||
|
|
||||||
|
|
||||||
# 取 intpage * limit ~ intpage * (limit+1) 写入以上文件
|
# 取 intpage * limit ~ intpage * (limit+1) 写入以上文件
|
||||||
@@ -238,7 +239,7 @@ EOF;
|
|||||||
} else {
|
} else {
|
||||||
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
||||||
}
|
}
|
||||||
$strUrl = sprintf("https://www.%s%s", $DomainModel->d_domain, $strUri);
|
$strUrl = sprintf("https://%s%s", $DomainModel->d_domain, $strUri);
|
||||||
$strPriority = '0.8';
|
$strPriority = '0.8';
|
||||||
$strContent = sprintf($strTemplate, $strUrl, $strPriority);
|
$strContent = sprintf($strTemplate, $strUrl, $strPriority);
|
||||||
file_put_contents($strMapVideosFile, $strContent, FILE_APPEND);
|
file_put_contents($strMapVideosFile, $strContent, FILE_APPEND);
|
||||||
@@ -323,13 +324,13 @@ $arrUrlPool = [];
|
|||||||
} else {
|
} else {
|
||||||
$strRankIndexUri = $DomainModel->getFomartUrlEx("VIDEO_RANK_INDEX_URL", $DomainModel->d_domain, "", "", []);
|
$strRankIndexUri = $DomainModel->getFomartUrlEx("VIDEO_RANK_INDEX_URL", $DomainModel->d_domain, "", "", []);
|
||||||
}
|
}
|
||||||
$strRankIndexUrl = sprintf("https://www.%s%s", $DomainModel->d_domain, $strRankIndexUri);
|
$strRankIndexUrl = sprintf("https://%s%s", $DomainModel->d_domain, $strRankIndexUri);
|
||||||
|
|
||||||
$strContent = <<<EOF
|
$strContent = <<<EOF
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url>
|
<url>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/</loc>
|
<loc>https://{$DomainModel->d_domain}/</loc>
|
||||||
<lastmod>{$this->strDate}</lastmod>
|
<lastmod>{$this->strDate}</lastmod>
|
||||||
<changefreq>daily</changefreq>
|
<changefreq>daily</changefreq>
|
||||||
<priority>1.0</priority>
|
<priority>1.0</priority>
|
||||||
@@ -344,7 +345,7 @@ EOF;
|
|||||||
|
|
||||||
|
|
||||||
//file_put_contents($strMapIndexFile, $strContent);
|
//file_put_contents($strMapIndexFile, $strContent);
|
||||||
$arrUrlPool["https://www.{$DomainModel->d_domain}/"] = [
|
$arrUrlPool["https://{$DomainModel->d_domain}/"] = [
|
||||||
'lastmod' => $this->strDate,
|
'lastmod' => $this->strDate,
|
||||||
'changefreq' => 'daily',
|
'changefreq' => 'daily',
|
||||||
'priority' => '1.0',
|
'priority' => '1.0',
|
||||||
@@ -371,7 +372,7 @@ EOF;
|
|||||||
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
$strUrl = sprintf("https://www.%s%s", $DomainModel->d_domain, $strUri);
|
$strUrl = sprintf("https://%s%s", $DomainModel->d_domain, $strUri);
|
||||||
|
|
||||||
$strContent = <<<EOF
|
$strContent = <<<EOF
|
||||||
<url>
|
<url>
|
||||||
@@ -419,7 +420,7 @@ EOF;
|
|||||||
} else {
|
} else {
|
||||||
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
||||||
}
|
}
|
||||||
$strUrl = sprintf("https://www.%s%s", $DomainModel->d_domain, $strUri);
|
$strUrl = sprintf("https://%s%s", $DomainModel->d_domain, $strUri);
|
||||||
$strContent = <<<EOF
|
$strContent = <<<EOF
|
||||||
<url>
|
<url>
|
||||||
<loc>{$strUrl}</loc>
|
<loc>{$strUrl}</loc>
|
||||||
@@ -464,7 +465,7 @@ EOF;
|
|||||||
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
$strUri = $DomainModel->getFomartUrlEx($strKey, $strDomain, $strController, $strAction, $arrArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
$strUrl = sprintf("https://www.%s%s", $DomainModel->d_domain, $strUri);
|
$strUrl = sprintf("https://%s%s", $DomainModel->d_domain, $strUri);
|
||||||
|
|
||||||
$strContent = <<<EOF
|
$strContent = <<<EOF
|
||||||
<url>
|
<url>
|
||||||
@@ -546,7 +547,7 @@ file_put_contents($strTxtFile, $strTxt);
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/sitemap-main.xml</loc>
|
<loc>https://{$DomainModel->d_domain}/sitemap-main.xml</loc>
|
||||||
<lastmod>{$this->strDate}</lastmod>
|
<lastmod>{$this->strDate}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
EOF;
|
EOF;
|
||||||
@@ -555,7 +556,7 @@ EOF;
|
|||||||
for ($intPage = 1; $intPage <= $intTotalPage; $intPage++) {
|
for ($intPage = 1; $intPage <= $intTotalPage; $intPage++) {
|
||||||
$strContent = <<<EOF
|
$strContent = <<<EOF
|
||||||
<sitemap>
|
<sitemap>
|
||||||
<loc>https://www.{$DomainModel->d_domain}/sitemap-videos-{$intPage}.xml</loc>
|
<loc>https://{$DomainModel->d_domain}/sitemap-videos-{$intPage}.xml</loc>
|
||||||
<lastmod>{$this->strDate}</lastmod>
|
<lastmod>{$this->strDate}</lastmod>
|
||||||
</sitemap>
|
</sitemap>
|
||||||
EOF;
|
EOF;
|
||||||
@@ -602,7 +603,7 @@ EOF;
|
|||||||
* {
|
* {
|
||||||
* "keyword": "...",
|
* "keyword": "...",
|
||||||
* "site": "...",
|
* "site": "...",
|
||||||
* "href": "https://www.xxx.com/...",
|
* "href": "https://xxx.com/...",
|
||||||
* "url": "#"
|
* "url": "#"
|
||||||
* }
|
* }
|
||||||
* ]
|
* ]
|
||||||
@@ -658,7 +659,7 @@ EOF;
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$fullUrl = 'https://www.' . $DomainModel->d_domain . $strUri;
|
$fullUrl = 'https://' . $DomainModel->d_domain . $strUri;
|
||||||
|
|
||||||
$row = [
|
$row = [
|
||||||
'keyword' => (string)$Video->v_name,
|
'keyword' => (string)$Video->v_name,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use app\task\logic\VideoSeoLogic;
|
|||||||
|
|
||||||
class PlanTask
|
class PlanTask
|
||||||
{
|
{
|
||||||
public static function scanPlanTask($arrData)
|
public static function scanPlanTask($arrData = [])
|
||||||
{
|
{
|
||||||
ProcessSanitizer::destructConnectSource();
|
ProcessSanitizer::destructConnectSource();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use think\migration\Migrator;
|
||||||
|
use think\migration\db\Column;
|
||||||
|
|
||||||
|
class CreateServerNodeTable extends Migrator
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
if (!$this->hasTable('server_node')) {
|
||||||
|
$this->table('server_node', ['id' => false])
|
||||||
|
->addColumn(Column::integer('sn_id')->setUnsigned()->setIdentity(true)->setComment('节点ID'))
|
||||||
|
->addColumn(Column::string('sn_name', 255)->setDefault('')->setComment('节点名称'))
|
||||||
|
->addColumn(Column::string('sn_code', 100)->setNullable(true)->setComment('节点编码'))
|
||||||
|
->addColumn(Column::string('sn_host', 255)->setDefault('')->setComment('SSH 主机/IP'))
|
||||||
|
->addColumn(Column::smallInteger('sn_port')->setUnsigned()->setDefault(22)->setComment('SSH 端口'))
|
||||||
|
->addColumn(Column::string('sn_username', 100)->setDefault('')->setComment('SSH 用户名'))
|
||||||
|
->addColumn(Column::string('sn_auth_type', 20)->setDefault('password')->setComment('认证方式: password/private_key'))
|
||||||
|
->addColumn(Column::text('sn_password')->setNullable(true)->setComment('SSH 密码'))
|
||||||
|
->addColumn(Column::mediumText('sn_private_key')->setNullable(true)->setComment('SSH 私钥'))
|
||||||
|
->addColumn(Column::text('sn_passphrase')->setNullable(true)->setComment('私钥口令'))
|
||||||
|
->addColumn(Column::string('sn_region', 100)->setNullable(true)->setComment('区域/环境'))
|
||||||
|
->addColumn(Column::string('sn_purpose', 255)->setNullable(true)->setComment('机器用途'))
|
||||||
|
->addColumn(Column::string('sn_project_dir', 500)->setNullable(true)->setComment('项目目录'))
|
||||||
|
->addColumn(Column::string('sn_log_dir', 500)->setNullable(true)->setComment('日志目录'))
|
||||||
|
->addColumn(Column::string('sn_nginx_dir', 500)->setNullable(true)->setComment('Nginx 配置目录'))
|
||||||
|
->addColumn(Column::text('sn_note')->setNullable(true)->setComment('备注'))
|
||||||
|
->addColumn(Column::tinyInteger('sn_status')->setUnsigned()->setDefault(1)->setComment('状态:1启用,0禁用'))
|
||||||
|
->addTimestamps('created_at', 'updated_at')
|
||||||
|
->addIndex(['sn_id'], ['type' => 'primary'])
|
||||||
|
->addIndex(['sn_code'], ['unique' => true])
|
||||||
|
->addIndex(['sn_status'])
|
||||||
|
->addIndex(['sn_host'])
|
||||||
|
->setComment('前端服务器节点')
|
||||||
|
->create();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$Table = $this->table('server_node');
|
||||||
|
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_name', Column::string('sn_name', 255)->setDefault('')->setComment('节点名称'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_code', Column::string('sn_code', 100)->setNullable(true)->setComment('节点编码'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_host', Column::string('sn_host', 255)->setDefault('')->setComment('SSH 主机/IP'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_port', Column::smallInteger('sn_port')->setUnsigned()->setDefault(22)->setComment('SSH 端口'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_username', Column::string('sn_username', 100)->setDefault('')->setComment('SSH 用户名'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_auth_type', Column::string('sn_auth_type', 20)->setDefault('password')->setComment('认证方式: password/private_key'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_password', Column::text('sn_password')->setNullable(true)->setComment('SSH 密码'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_private_key', Column::mediumText('sn_private_key')->setNullable(true)->setComment('SSH 私钥'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_passphrase', Column::text('sn_passphrase')->setNullable(true)->setComment('私钥口令'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_region', Column::string('sn_region', 100)->setNullable(true)->setComment('区域/环境'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_purpose', Column::string('sn_purpose', 255)->setNullable(true)->setComment('机器用途'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_project_dir', Column::string('sn_project_dir', 500)->setNullable(true)->setComment('项目目录'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_log_dir', Column::string('sn_log_dir', 500)->setNullable(true)->setComment('日志目录'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_nginx_dir', Column::string('sn_nginx_dir', 500)->setNullable(true)->setComment('Nginx 配置目录'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_note', Column::text('sn_note')->setNullable(true)->setComment('备注'));
|
||||||
|
$this->addColumnIfMissing($Table, 'sn_status', Column::tinyInteger('sn_status')->setUnsigned()->setDefault(1)->setComment('状态:1启用,0禁用'));
|
||||||
|
$this->addColumnIfMissing($Table, 'created_at', Column::timestamp('created_at')->setDefault('CURRENT_TIMESTAMP'));
|
||||||
|
$this->addColumnIfMissing($Table, 'updated_at', Column::timestamp('updated_at')->setDefault('CURRENT_TIMESTAMP')->setUpdate('CURRENT_TIMESTAMP'));
|
||||||
|
|
||||||
|
$this->addIndexIfMissing($Table, ['sn_code'], ['unique' => true]);
|
||||||
|
$this->addIndexIfMissing($Table, ['sn_status']);
|
||||||
|
$this->addIndexIfMissing($Table, ['sn_host']);
|
||||||
|
|
||||||
|
$Table->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
if ($this->hasTable('server_node')) {
|
||||||
|
$this->table('server_node')->drop()->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addColumnIfMissing($table, string $columnName, Column $column): void
|
||||||
|
{
|
||||||
|
if (!$table->hasColumn($columnName)) {
|
||||||
|
$table->addColumn($column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addIndexIfMissing($table, array $columns, array $options = []): void
|
||||||
|
{
|
||||||
|
if (!$table->hasIndex($columns)) {
|
||||||
|
$table->addIndex($columns, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -179,6 +179,40 @@ CREATE TABLE `plan_task` (
|
|||||||
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
|
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `server_node`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `server_node`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!50503 SET character_set_client = utf8mb4 */;
|
||||||
|
CREATE TABLE `server_node` (
|
||||||
|
`sn_id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`sn_name` varchar(255) NOT NULL DEFAULT '' COMMENT '节点名称',
|
||||||
|
`sn_code` varchar(100) DEFAULT NULL COMMENT '节点编码',
|
||||||
|
`sn_host` varchar(255) NOT NULL DEFAULT '' COMMENT 'SSH 主机/IP',
|
||||||
|
`sn_port` smallint unsigned NOT NULL DEFAULT '22' COMMENT 'SSH 端口',
|
||||||
|
`sn_username` varchar(100) NOT NULL DEFAULT '' COMMENT 'SSH 用户名',
|
||||||
|
`sn_auth_type` varchar(20) NOT NULL DEFAULT 'password' COMMENT '认证方式: password/private_key',
|
||||||
|
`sn_password` text COMMENT 'SSH 密码',
|
||||||
|
`sn_private_key` mediumtext COMMENT 'SSH 私钥',
|
||||||
|
`sn_passphrase` text COMMENT '私钥口令',
|
||||||
|
`sn_region` varchar(100) DEFAULT NULL COMMENT '区域/环境',
|
||||||
|
`sn_purpose` varchar(255) DEFAULT NULL COMMENT '机器用途',
|
||||||
|
`sn_project_dir` varchar(500) DEFAULT NULL COMMENT '项目目录',
|
||||||
|
`sn_log_dir` varchar(500) DEFAULT NULL COMMENT '日志目录',
|
||||||
|
`sn_nginx_dir` varchar(500) DEFAULT NULL COMMENT 'Nginx 配置目录',
|
||||||
|
`sn_note` text COMMENT '备注',
|
||||||
|
`sn_status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '状态:1启用,0禁用',
|
||||||
|
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`sn_id`) USING BTREE,
|
||||||
|
UNIQUE KEY `sn_code` (`sn_code`) USING BTREE,
|
||||||
|
KEY `sn_status` (`sn_status`) USING BTREE,
|
||||||
|
KEY `sn_host` (`sn_host`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='前端服务器节点';
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `subject_fomart`
|
-- Table structure for table `subject_fomart`
|
||||||
--
|
--
|
||||||
|
|||||||
13
code/extend/copyright/Auth.php
Normal file
13
code/extend/copyright/Auth.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace copyright;
|
||||||
|
|
||||||
|
class Auth
|
||||||
|
{
|
||||||
|
public static function checkCopyright(): null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
102
code/extend/db/DatabaseManage.php
Normal file
102
code/extend/db/DatabaseManage.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace db;
|
||||||
|
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Argument;
|
||||||
|
use think\console\Output;
|
||||||
|
|
||||||
|
class DatabaseManage extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('db:manage')
|
||||||
|
->setDescription('Manage the database: backup or initialize')
|
||||||
|
->addArgument('action', Argument::OPTIONAL, 'The action to perform: backup or init or seed');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output): int
|
||||||
|
{
|
||||||
|
$strAction = strtolower((string) $input->getArgument('action'));
|
||||||
|
return match ($strAction) {
|
||||||
|
'backup' => $this->runBackupDatabase($output),
|
||||||
|
'init' => $this->runCommand($output, 'migrate:run') | $this->runCommand($output, 'seed:run'),
|
||||||
|
'seed' => $this->runCommand($output, 'seed:run'),
|
||||||
|
default => $this->invalidAction($output),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function seed(): int
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function backupDatabase(): int
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initializeDatabase(): int
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function invalidAction(Output $output): int
|
||||||
|
{
|
||||||
|
$output->writeln("Invalid action. Use 'backup' or 'init'. or 'seed'");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function runBackupDatabase(Output $output): int
|
||||||
|
{
|
||||||
|
$arrConfig = (array) config('database.connections.mysql', []);
|
||||||
|
$strDir = runtime_path() . 'db-backup';
|
||||||
|
if (!is_dir($strDir)) {
|
||||||
|
@mkdir($strDir, 0777, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$strFile = $strDir . '/' . date('Ymd-His') . '.sql';
|
||||||
|
$arrParts = [
|
||||||
|
'mysqldump',
|
||||||
|
'-h' . escapeshellarg((string) ($arrConfig['hostname'] ?? '127.0.0.1')),
|
||||||
|
'-P' . escapeshellarg((string) ($arrConfig['hostport'] ?? '3306')),
|
||||||
|
'-u' . escapeshellarg((string) ($arrConfig['username'] ?? 'root')),
|
||||||
|
];
|
||||||
|
$strPassword = (string) ($arrConfig['password'] ?? '');
|
||||||
|
if ($strPassword !== '') {
|
||||||
|
$arrParts[] = '-p' . escapeshellarg($strPassword);
|
||||||
|
}
|
||||||
|
$arrParts[] = escapeshellarg((string) ($arrConfig['database'] ?? ''));
|
||||||
|
$strCommand = implode(' ', $arrParts) . ' > ' . escapeshellarg($strFile) . ' 2>&1';
|
||||||
|
|
||||||
|
exec($strCommand, $arrOutput, $intCode);
|
||||||
|
if ($intCode !== 0) {
|
||||||
|
$output->writeln('Database backup failed.');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('Database backup written to: ' . $strFile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function runCommand(Output $output, string $strCommand): int
|
||||||
|
{
|
||||||
|
$strRoot = rtrim(root_path(), '/');
|
||||||
|
$strExec = sprintf(
|
||||||
|
'cd %s && %s think %s 2>&1',
|
||||||
|
escapeshellarg($strRoot),
|
||||||
|
escapeshellarg(PHP_BINARY),
|
||||||
|
escapeshellarg($strCommand)
|
||||||
|
);
|
||||||
|
|
||||||
|
exec($strExec, $arrOutput, $intCode);
|
||||||
|
foreach ($arrOutput as $strLine) {
|
||||||
|
$output->writeln($strLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $intCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
88
code/extend/db/MongoMigrate.php
Normal file
88
code/extend/db/MongoMigrate.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace db;
|
||||||
|
|
||||||
|
use MongoDB\Client;
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Argument;
|
||||||
|
use think\console\Output;
|
||||||
|
|
||||||
|
class MongoMigrate extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('mongo:manage')
|
||||||
|
->setDescription('Manage the mongo, migarte index or drop all index')
|
||||||
|
->addArgument('action', Argument::OPTIONAL, 'The action to perform: migrate');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output): int
|
||||||
|
{
|
||||||
|
$strAction = strtolower((string) $input->getArgument('action'));
|
||||||
|
return match ($strAction) {
|
||||||
|
'migrate' => $this->migrate($output),
|
||||||
|
'drop' => $this->dropAllIndexes($output),
|
||||||
|
default => $this->invalidAction($output),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dropAllIndexes(Output $output): int
|
||||||
|
{
|
||||||
|
$db = $this->getMongoDatabase();
|
||||||
|
foreach ($db->listCollections() as $CollectionInfo) {
|
||||||
|
$Collection = $db->selectCollection($CollectionInfo->getName());
|
||||||
|
foreach ($Collection->listIndexes() as $IndexInfo) {
|
||||||
|
$strIndexName = (string) $IndexInfo->getName();
|
||||||
|
if ($strIndexName === '_id_') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$Collection->dropIndex($strIndexName);
|
||||||
|
$output->writeln(sprintf('Dropped index %s on %s', $strIndexName, $CollectionInfo->getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function migrate(Output $output): int
|
||||||
|
{
|
||||||
|
$db = $this->getMongoDatabase();
|
||||||
|
$intCount = 0;
|
||||||
|
foreach ($db->listCollections() as $CollectionInfo) {
|
||||||
|
$intCount++;
|
||||||
|
$output->writeln('Checked collection: ' . $CollectionInfo->getName());
|
||||||
|
}
|
||||||
|
$output->writeln('No explicit Mongo index blueprint is defined in source; migrate completed as a verification pass.');
|
||||||
|
return $intCount >= 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function invalidAction(Output $output): int
|
||||||
|
{
|
||||||
|
$output->writeln("Invalid action. Use 'migrate' or 'drop'");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMongoDatabase(): \MongoDB\Database
|
||||||
|
{
|
||||||
|
$arrConfig = (array) config('mongodb', []);
|
||||||
|
$uri = sprintf(
|
||||||
|
'mongodb://%s:%s',
|
||||||
|
(string) ($arrConfig['hostname'] ?? '127.0.0.1'),
|
||||||
|
(string) ($arrConfig['hostport'] ?? '27017')
|
||||||
|
);
|
||||||
|
|
||||||
|
$arrOptions = [];
|
||||||
|
$strUsername = (string) ($arrConfig['username'] ?? '');
|
||||||
|
if ($strUsername !== '') {
|
||||||
|
$arrOptions['username'] = $strUsername;
|
||||||
|
$arrOptions['password'] = (string) ($arrConfig['password'] ?? '');
|
||||||
|
$arrOptions['authSource'] = (string) env('MONGO_AUTH_DB', 'admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
$Client = new Client($uri, $arrOptions);
|
||||||
|
return $Client->selectDatabase((string) ($arrConfig['database'] ?? ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
47
code/extend/db/NovelManage.php
Normal file
47
code/extend/db/NovelManage.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace db;
|
||||||
|
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Argument;
|
||||||
|
use think\console\Output;
|
||||||
|
use think\facade\Cache;
|
||||||
|
|
||||||
|
class NovelManage extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('novel:manage')
|
||||||
|
->setDescription('Manage the novel data: reset or ...')
|
||||||
|
->addArgument('action', Argument::OPTIONAL, 'The action to perform: reset');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output): int
|
||||||
|
{
|
||||||
|
$strAction = strtolower((string) $input->getArgument('action'));
|
||||||
|
return match ($strAction) {
|
||||||
|
'reset' => $this->resetData($output),
|
||||||
|
default => $this->invalidAction($output),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resetData(Output $output): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Cache::clear();
|
||||||
|
} catch (\Throwable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('Novel-related caches have been cleared.');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function invalidAction(Output $output): int
|
||||||
|
{
|
||||||
|
$output->writeln("Invalid action. Use 'reset' ");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
187
code/extend/db/mongo/MongoBase.php
Normal file
187
code/extend/db/mongo/MongoBase.php
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace db\mongo;
|
||||||
|
|
||||||
|
use MongoDB\Client;
|
||||||
|
use MongoDB\Collection;
|
||||||
|
use MongoDB\Database;
|
||||||
|
use MongoDB\Driver\Exception\Exception as MongoDriverException;
|
||||||
|
use MongoDB\Operation\FindOneAndUpdate;
|
||||||
|
|
||||||
|
class MongoBase
|
||||||
|
{
|
||||||
|
private static ?self $instance = null;
|
||||||
|
|
||||||
|
private Client $client;
|
||||||
|
|
||||||
|
private Database $db;
|
||||||
|
|
||||||
|
public static function getInstance(): self
|
||||||
|
{
|
||||||
|
if (self::$instance === null) {
|
||||||
|
self::$instance = new self();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$config = $this->getMongoConfig();
|
||||||
|
$this->client = $this->buildClient($config);
|
||||||
|
$this->db = $this->client->selectDatabase((string) $config['database']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDb(): Database
|
||||||
|
{
|
||||||
|
return $this->db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNextSequence(string $strCollection, string $strSequenceName): int
|
||||||
|
{
|
||||||
|
$result = $this->getCollection($strCollection)->findOneAndUpdate(
|
||||||
|
['_id' => $strSequenceName],
|
||||||
|
['$inc' => ['sequence_value' => 1]],
|
||||||
|
[
|
||||||
|
'upsert' => true,
|
||||||
|
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
|
||||||
|
] + $this->getTypeMapOptions()
|
||||||
|
);
|
||||||
|
|
||||||
|
return (int) ($result['sequence_value'] ?? 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertOne(string $strCollection, array $arrData, array $arrOptions = []): mixed
|
||||||
|
{
|
||||||
|
$result = $this->getCollection($strCollection)->insertOne($arrData, $arrOptions);
|
||||||
|
return $result->getInsertedId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function insertMany(string $strCollection, array $arrData, array $arrOptions = []): int
|
||||||
|
{
|
||||||
|
$result = $this->getCollection($strCollection)->insertMany($arrData, $arrOptions);
|
||||||
|
return $result->getInsertedCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOne(string $strCollection, array $arrFilter = [], array $arrOptions = []): ?array
|
||||||
|
{
|
||||||
|
$result = $this->getCollection($strCollection)->findOne(
|
||||||
|
$arrFilter,
|
||||||
|
$arrOptions + $this->getTypeMapOptions()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $result === null ? null : (array) $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findMany(
|
||||||
|
string $strCollection,
|
||||||
|
array $arrFilter = [],
|
||||||
|
int $intCount = 0,
|
||||||
|
array $arrSort = [],
|
||||||
|
array $arrOptions = []
|
||||||
|
): array {
|
||||||
|
$options = $arrOptions + $this->getTypeMapOptions();
|
||||||
|
if ($intCount > 0 && !isset($options['limit'])) {
|
||||||
|
$options['limit'] = $intCount;
|
||||||
|
}
|
||||||
|
if ($arrSort !== [] && !isset($options['sort'])) {
|
||||||
|
$options['sort'] = $arrSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cursor = $this->getCollection($strCollection)->find($arrFilter, $options);
|
||||||
|
$arrResult = [];
|
||||||
|
foreach ($cursor as $item) {
|
||||||
|
$arrResult[] = (array) $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $arrResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateOne(string $strCollection, array $arrFilter, array $arrUpdate, array $arrOptions = []): int
|
||||||
|
{
|
||||||
|
$result = $this->getCollection($strCollection)->updateOne($arrFilter, $arrUpdate, $arrOptions);
|
||||||
|
return $result->getModifiedCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $strCollection, array $arrFilter, array $arrOptions = []): int
|
||||||
|
{
|
||||||
|
$result = $this->getCollection($strCollection)->deleteMany($arrFilter, $arrOptions);
|
||||||
|
return $result->getDeletedCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCollection(string $strCollection): Collection
|
||||||
|
{
|
||||||
|
return $this->db->selectCollection($strCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMongoConfig(): array
|
||||||
|
{
|
||||||
|
$config = \config('mongodb');
|
||||||
|
if (!is_array($config)) {
|
||||||
|
throw new \RuntimeException('MongoDB config is missing.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$config['hostname'] = (string) ($config['hostname'] ?? '127.0.0.1');
|
||||||
|
$config['hostport'] = (string) ($config['hostport'] ?? '27017');
|
||||||
|
$config['username'] = (string) ($config['username'] ?? '');
|
||||||
|
$config['password'] = (string) ($config['password'] ?? '');
|
||||||
|
$config['database'] = (string) ($config['database'] ?? '');
|
||||||
|
|
||||||
|
if ($config['database'] === '') {
|
||||||
|
throw new \RuntimeException('MongoDB database is not configured.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildClient(array $config): Client
|
||||||
|
{
|
||||||
|
$uri = sprintf('mongodb://%s:%s', $config['hostname'], $config['hostport']);
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
if ($config['username'] !== '') {
|
||||||
|
$options['username'] = $config['username'];
|
||||||
|
$options['password'] = $config['password'];
|
||||||
|
foreach ($this->getAuthSources($config['database']) as $authSource) {
|
||||||
|
try {
|
||||||
|
$client = new Client($uri, $options + ['authSource' => $authSource]);
|
||||||
|
foreach ($client->selectDatabase($config['database'])->listCollections([], ['maxTimeMS' => 3000]) as $_) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $client;
|
||||||
|
} catch (MongoDriverException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException('MongoDB authentication failed for all configured authSource values.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Client($uri, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAuthSources(string $database): array
|
||||||
|
{
|
||||||
|
$sources = [];
|
||||||
|
$envSource = \env('MONGO_AUTH_DB', '');
|
||||||
|
if (is_string($envSource) && $envSource !== '') {
|
||||||
|
$sources[] = $envSource;
|
||||||
|
}
|
||||||
|
$sources[] = 'admin';
|
||||||
|
$sources[] = $database;
|
||||||
|
|
||||||
|
return array_values(array_unique($sources));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTypeMapOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'typeMap' => [
|
||||||
|
'root' => 'array',
|
||||||
|
'document' => 'array',
|
||||||
|
'array' => 'array',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,21 @@ use ReflectionException;
|
|||||||
|
|
||||||
class Init
|
class Init
|
||||||
{
|
{
|
||||||
|
private const REPLACED_DDL_MAP = [
|
||||||
|
'1.ddl' => \copyright\Auth::class,
|
||||||
|
'2.ddl' => \microserver\ProcessSanitizer::class,
|
||||||
|
'3.ddl' => \microserver\QueueManage::class,
|
||||||
|
'4.ddl' => \microserver\Rout::class,
|
||||||
|
'5.ddl' => \microserver\ScheduledTasks::class,
|
||||||
|
'6.ddl' => \microserver\ServerConsole::class,
|
||||||
|
'7.ddl' => \microserver\ServerCore::class,
|
||||||
|
'8.ddl' => \microserver\ServerManage::class,
|
||||||
|
'9.ddl' => \db\DatabaseManage::class,
|
||||||
|
'10.ddl' => \db\mongo\MongoBase::class,
|
||||||
|
'11.ddl' => \db\MongoMigrate::class,
|
||||||
|
'12.ddl' => \db\NovelManage::class,
|
||||||
|
];
|
||||||
|
|
||||||
public static function run()
|
public static function run()
|
||||||
{
|
{
|
||||||
self::loadDDL(__DIR__ . '/ext');
|
self::loadDDL(__DIR__ . '/ext');
|
||||||
@@ -17,6 +32,10 @@ class Init
|
|||||||
public static function loadDDL($strDir)
|
public static function loadDDL($strDir)
|
||||||
{
|
{
|
||||||
foreach (self::scanDdlFiles($strDir) as $strDDL) {
|
foreach (self::scanDdlFiles($strDir) as $strDDL) {
|
||||||
|
$strFilename = basename($strDDL);
|
||||||
|
if (isset(self::REPLACED_DDL_MAP[$strFilename]) && class_exists(self::REPLACED_DDL_MAP[$strFilename])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
load_module_file($strDDL);
|
load_module_file($strDDL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
code/extend/microserver/ProcessSanitizer.php
Normal file
36
code/extend/microserver/ProcessSanitizer.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace microserver;
|
||||||
|
|
||||||
|
use think\facade\Cache;
|
||||||
|
use think\facade\Db;
|
||||||
|
|
||||||
|
class ProcessSanitizer
|
||||||
|
{
|
||||||
|
public static function reloadRedis(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$redis = Cache::store('redis')->handler();
|
||||||
|
if ($redis instanceof \Redis) {
|
||||||
|
$redis->close();
|
||||||
|
}
|
||||||
|
} catch (\Throwable) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function reloadDb(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Db::disconnect();
|
||||||
|
} catch (\Throwable) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function destructConnectSource(): void
|
||||||
|
{
|
||||||
|
self::reloadRedis();
|
||||||
|
self::reloadDb();
|
||||||
|
}
|
||||||
|
}
|
||||||
58
code/extend/microserver/QueueManage.php
Normal file
58
code/extend/microserver/QueueManage.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace microserver;
|
||||||
|
|
||||||
|
use think\facade\Cache;
|
||||||
|
|
||||||
|
class QueueManage
|
||||||
|
{
|
||||||
|
private static array $instances = [];
|
||||||
|
|
||||||
|
private int $index;
|
||||||
|
|
||||||
|
private string $queueName;
|
||||||
|
|
||||||
|
public static function getInstance(int $intIndex = 1): self
|
||||||
|
{
|
||||||
|
if (!isset(self::$instances[$intIndex])) {
|
||||||
|
self::$instances[$intIndex] = new self($intIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instances[$intIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(int $intIndex = 1)
|
||||||
|
{
|
||||||
|
$this->index = $intIndex;
|
||||||
|
$this->queueName = (string) config("task.queue.{$intIndex}.name", 'QueueKey01');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(): string
|
||||||
|
{
|
||||||
|
$result = $this->getRedis()->lPop($this->queueName);
|
||||||
|
if ($result === false || $result === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_string($result) ? $result : (string) $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(array|string $mData): int
|
||||||
|
{
|
||||||
|
$payload = is_array($mData) ? json_encode($mData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : (string) $mData;
|
||||||
|
if ($payload === false || $payload === '') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $this->getRedis()->rPush($this->queueName, $payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRedis(): \Redis
|
||||||
|
{
|
||||||
|
/** @var \Redis $redis */
|
||||||
|
$redis = Cache::store('redis')->handler();
|
||||||
|
return $redis;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
code/extend/microserver/Rout.php
Normal file
16
code/extend/microserver/Rout.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace microserver;
|
||||||
|
|
||||||
|
class Rout
|
||||||
|
{
|
||||||
|
public static function httpDispense(...$args): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tcpDispense(...$args): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
29
code/extend/microserver/ScheduledTasks.php
Normal file
29
code/extend/microserver/ScheduledTasks.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace microserver;
|
||||||
|
|
||||||
|
class ScheduledTasks
|
||||||
|
{
|
||||||
|
public static function hander(array $arrTask): void
|
||||||
|
{
|
||||||
|
$arrCallback = $arrTask['callback'] ?? null;
|
||||||
|
if (!is_array($arrCallback) || count($arrCallback) < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
call_user_func($arrCallback, $arrTask['param'] ?? []);
|
||||||
|
} catch (\Throwable $Throwable) {
|
||||||
|
ServerManage::appendLog(
|
||||||
|
sprintf(
|
||||||
|
'Scheduled task failed: %s in %s:%d',
|
||||||
|
$Throwable->getMessage(),
|
||||||
|
$Throwable->getFile(),
|
||||||
|
$Throwable->getLine()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
code/extend/microserver/ServerConsole.php
Normal file
47
code/extend/microserver/ServerConsole.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace microserver;
|
||||||
|
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Argument;
|
||||||
|
use think\console\input\Option;
|
||||||
|
use think\console\Output;
|
||||||
|
|
||||||
|
class ServerConsole extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('task')
|
||||||
|
->setDescription('run task service')
|
||||||
|
->setHelp('php think task <action> [-d] [-f] run server')
|
||||||
|
->addArgument('action', Argument::REQUIRED, 'action: (start|stop|restart|status)')
|
||||||
|
->addOption('daemonize', 'd', Option::VALUE_NONE, 'daemonize start service')
|
||||||
|
->addOption('forcibly', 'f', Option::VALUE_NONE, 'ignore user forcibly start service');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output): int
|
||||||
|
{
|
||||||
|
$strAction = strtolower((string) $input->getArgument('action'));
|
||||||
|
if (!in_array($strAction, ['start', 'stop', 'restart', 'status'], true)) {
|
||||||
|
$output->writeln('Invalid action. Use start|stop|restart|status');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ServerManage = (new ServerManage())
|
||||||
|
->__init((array) config('task'))
|
||||||
|
->setConfigDaemonize((bool) $input->getOption('daemonize'))
|
||||||
|
->addProcessList((array) config('task.process_pool', []))
|
||||||
|
->addScheduledTasks((array) config('task.scheduled_tasks_pool', []))
|
||||||
|
->createService();
|
||||||
|
|
||||||
|
return match ($strAction) {
|
||||||
|
'start' => $ServerManage->start(),
|
||||||
|
'stop' => $ServerManage->stop(),
|
||||||
|
'restart' => $ServerManage->restart(),
|
||||||
|
'status' => $ServerManage->status(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
59
code/extend/microserver/ServerCore.php
Normal file
59
code/extend/microserver/ServerCore.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace microserver;
|
||||||
|
|
||||||
|
class ServerCore
|
||||||
|
{
|
||||||
|
private static ?self $obj = null;
|
||||||
|
|
||||||
|
private array $arrConfig = [];
|
||||||
|
|
||||||
|
public static function instance(array $arrConfig = []): self
|
||||||
|
{
|
||||||
|
if (self::$obj === null) {
|
||||||
|
self::$obj = new self($arrConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(array $arrConfig = [])
|
||||||
|
{
|
||||||
|
$this->arrConfig = $arrConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serHttpConfig(): array
|
||||||
|
{
|
||||||
|
return $this->arrConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filterConfig(array $arrConfig = []): array
|
||||||
|
{
|
||||||
|
return $arrConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serTcpConfig(): array
|
||||||
|
{
|
||||||
|
return $this->arrConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createServer(): null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getServer(): null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onTask(...$args): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onFinish(...$args): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
353
code/extend/microserver/ServerManage.php
Normal file
353
code/extend/microserver/ServerManage.php
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace microserver;
|
||||||
|
|
||||||
|
use Swoole\Process;
|
||||||
|
|
||||||
|
class ServerManage
|
||||||
|
{
|
||||||
|
private array $arrDynamicConfig = [];
|
||||||
|
|
||||||
|
private array $processPool = [];
|
||||||
|
|
||||||
|
private array $scheduledTasks = [];
|
||||||
|
|
||||||
|
private bool $daemonize = false;
|
||||||
|
|
||||||
|
private bool $running = true;
|
||||||
|
|
||||||
|
private array $childDefinitions = [];
|
||||||
|
|
||||||
|
private array $childPids = [];
|
||||||
|
|
||||||
|
public function __init(array $arrDynamicConfig = []): self
|
||||||
|
{
|
||||||
|
$this->arrDynamicConfig = $arrDynamicConfig;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConfigDaemonize(bool $boolDaemonize): self
|
||||||
|
{
|
||||||
|
$this->daemonize = $boolDaemonize;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPid(): int
|
||||||
|
{
|
||||||
|
$strPidFile = (string) ($this->arrDynamicConfig['service']['pid_file'] ?? '');
|
||||||
|
if ($strPidFile === '' || !is_file($strPidFile)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) trim((string) file_get_contents($strPidFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addScheduledTasks(array $arrTasks): self
|
||||||
|
{
|
||||||
|
$this->scheduledTasks = $arrTasks;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addProcessList(array $arrProcessPool): self
|
||||||
|
{
|
||||||
|
$this->processPool = $arrProcessPool;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createService(): self
|
||||||
|
{
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start(): int
|
||||||
|
{
|
||||||
|
$intCurrentPid = $this->getPid();
|
||||||
|
if ($intCurrentPid > 0 && $this->isProcessAlive($intCurrentPid)) {
|
||||||
|
echo " Service is \033[0;32mRunning\033[0m ! " . PHP_EOL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->daemonize) {
|
||||||
|
$intPid = pcntl_fork();
|
||||||
|
if ($intPid < 0) {
|
||||||
|
echo " Service start failed! " . PHP_EOL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ($intPid > 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
posix_setsid();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->bootMaster();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stop(): int
|
||||||
|
{
|
||||||
|
$intPid = $this->getPid();
|
||||||
|
if ($intPid <= 0 || !$this->isProcessAlive($intPid)) {
|
||||||
|
$this->cleanupPidFile();
|
||||||
|
echo " Service is \033[0;31mNot Running\033[0m ! " . PHP_EOL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
posix_kill($intPid, SIGTERM);
|
||||||
|
$intDeadline = time() + 15;
|
||||||
|
while ($this->isProcessAlive($intPid) && time() < $intDeadline) {
|
||||||
|
usleep(200000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isProcessAlive($intPid)) {
|
||||||
|
posix_kill($intPid, SIGKILL);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cleanupPidFile();
|
||||||
|
echo " Service stop \033[0;32mDone\033[0m ! " . PHP_EOL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function status(): int
|
||||||
|
{
|
||||||
|
$intPid = $this->getPid();
|
||||||
|
if ($intPid > 0 && $this->isProcessAlive($intPid)) {
|
||||||
|
echo " Service is \033[0;32mRunning\033[0m ! " . PHP_EOL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo " Service is \033[0;31mNot Running\033[0m ! " . PHP_EOL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function restart(): int
|
||||||
|
{
|
||||||
|
$this->stop();
|
||||||
|
return $this->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function appendLog(string $strMessage): void
|
||||||
|
{
|
||||||
|
$strLogFile = (string) config('task.service.log_file', runtime_path() . 'task.log');
|
||||||
|
$strDir = dirname($strLogFile);
|
||||||
|
if (!is_dir($strDir)) {
|
||||||
|
@mkdir($strDir, 0777, true);
|
||||||
|
}
|
||||||
|
@file_put_contents($strLogFile, '[' . date('Y-m-d H:i:s') . '] ' . $strMessage . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function bootMaster(): void
|
||||||
|
{
|
||||||
|
$this->writePidFile();
|
||||||
|
$this->registerMasterSignals();
|
||||||
|
$this->buildChildDefinitions();
|
||||||
|
$this->spawnAllChildren();
|
||||||
|
self::appendLog('Task master started. pid=' . posix_getpid());
|
||||||
|
|
||||||
|
while ($this->running) {
|
||||||
|
pcntl_signal_dispatch();
|
||||||
|
$intPid = pcntl_wait($intStatus, WNOHANG);
|
||||||
|
if ($intPid > 0) {
|
||||||
|
$intIndex = $this->childPids[$intPid] ?? null;
|
||||||
|
unset($this->childPids[$intPid]);
|
||||||
|
if ($this->running && $intIndex !== null) {
|
||||||
|
$this->spawnChild($intIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usleep(500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->shutdownChildren();
|
||||||
|
$this->cleanupPidFile();
|
||||||
|
self::appendLog('Task master stopped. pid=' . posix_getpid());
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildChildDefinitions(): void
|
||||||
|
{
|
||||||
|
foreach ($this->processPool as $arrProcessConfig) {
|
||||||
|
$intNum = max(0, (int) ($arrProcessConfig['Num'] ?? 0));
|
||||||
|
for ($i = 0; $i < $intNum; $i++) {
|
||||||
|
$this->childDefinitions[] = [
|
||||||
|
'type' => 'worker',
|
||||||
|
'config' => $arrProcessConfig,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->scheduledTasks)) {
|
||||||
|
$this->childDefinitions[] = [
|
||||||
|
'type' => 'scheduler',
|
||||||
|
'config' => $this->scheduledTasks,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function spawnAllChildren(): void
|
||||||
|
{
|
||||||
|
foreach (array_keys($this->childDefinitions) as $intIndex) {
|
||||||
|
$this->spawnChild($intIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function spawnChild(int $intIndex): void
|
||||||
|
{
|
||||||
|
$arrDefinition = $this->childDefinitions[$intIndex] ?? null;
|
||||||
|
if (!is_array($arrDefinition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$intPid = pcntl_fork();
|
||||||
|
if ($intPid < 0) {
|
||||||
|
self::appendLog('Failed to fork child for index ' . $intIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($intPid > 0) {
|
||||||
|
$this->childPids[$intPid] = $intIndex;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->runChild($arrDefinition);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function runChild(array $arrDefinition): void
|
||||||
|
{
|
||||||
|
$boolRunning = true;
|
||||||
|
pcntl_signal(SIGTERM, function () use (&$boolRunning) {
|
||||||
|
$boolRunning = false;
|
||||||
|
});
|
||||||
|
pcntl_signal(SIGINT, function () use (&$boolRunning) {
|
||||||
|
$boolRunning = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (($arrDefinition['type'] ?? '') === 'scheduler') {
|
||||||
|
$this->runSchedulerLoop($arrDefinition['config'], $boolRunning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->runWorkerLoop($arrDefinition['config'], $boolRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function runWorkerLoop(array $arrProcessConfig, bool &$boolRunning): void
|
||||||
|
{
|
||||||
|
$arrCallback = $arrProcessConfig['callback'] ?? null;
|
||||||
|
if (!is_array($arrCallback) || count($arrCallback) < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($boolRunning) {
|
||||||
|
try {
|
||||||
|
call_user_func($arrCallback, new Process(static function () {
|
||||||
|
}, false, SOCK_STREAM, false));
|
||||||
|
} catch (\Throwable $Throwable) {
|
||||||
|
self::appendLog(
|
||||||
|
sprintf(
|
||||||
|
'Worker failed: %s in %s:%d',
|
||||||
|
$Throwable->getMessage(),
|
||||||
|
$Throwable->getFile(),
|
||||||
|
$Throwable->getLine()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
usleep(500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
pcntl_signal_dispatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function runSchedulerLoop(array $arrTasks, bool &$boolRunning): void
|
||||||
|
{
|
||||||
|
$arrNextRun = [];
|
||||||
|
while ($boolRunning) {
|
||||||
|
$intNow = time();
|
||||||
|
foreach ($arrTasks as $intIndex => $arrTask) {
|
||||||
|
if (empty($arrTask['status'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$intInterval = max(1, (int) ($arrTask['execution_interval'] ?? 1));
|
||||||
|
$intDueTime = $arrNextRun[$intIndex] ?? 0;
|
||||||
|
if ($intDueTime > $intNow) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScheduledTasks::hander($arrTask);
|
||||||
|
$arrNextRun[$intIndex] = $intNow + $intInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
pcntl_signal_dispatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shutdownChildren(): void
|
||||||
|
{
|
||||||
|
foreach (array_keys($this->childPids) as $intChildPid) {
|
||||||
|
@posix_kill($intChildPid, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
$intDeadline = time() + 10;
|
||||||
|
while (!empty($this->childPids) && time() < $intDeadline) {
|
||||||
|
$intPid = pcntl_wait($intStatus, WNOHANG);
|
||||||
|
if ($intPid > 0) {
|
||||||
|
unset($this->childPids[$intPid]);
|
||||||
|
} else {
|
||||||
|
usleep(200000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (array_keys($this->childPids) as $intChildPid) {
|
||||||
|
@posix_kill($intChildPid, SIGKILL);
|
||||||
|
}
|
||||||
|
$this->childPids = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerMasterSignals(): void
|
||||||
|
{
|
||||||
|
pcntl_signal(SIGTERM, function () {
|
||||||
|
$this->running = false;
|
||||||
|
});
|
||||||
|
pcntl_signal(SIGINT, function () {
|
||||||
|
$this->running = false;
|
||||||
|
});
|
||||||
|
pcntl_signal(SIGCHLD, function () {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function writePidFile(): void
|
||||||
|
{
|
||||||
|
$strPidFile = (string) ($this->arrDynamicConfig['service']['pid_file'] ?? '');
|
||||||
|
if ($strPidFile === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$strDir = dirname($strPidFile);
|
||||||
|
if (!is_dir($strDir)) {
|
||||||
|
@mkdir($strDir, 0777, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($strPidFile, (string) posix_getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanupPidFile(): void
|
||||||
|
{
|
||||||
|
$strPidFile = (string) ($this->arrDynamicConfig['service']['pid_file'] ?? '');
|
||||||
|
if ($strPidFile === '' || !is_file($strPidFile)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$intPid = (int) trim((string) @file_get_contents($strPidFile));
|
||||||
|
if ($intPid === posix_getpid()) {
|
||||||
|
@unlink($strPidFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isProcessAlive(int $intPid): bool
|
||||||
|
{
|
||||||
|
return $intPid > 0 && @posix_kill($intPid, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -446,8 +446,35 @@ async function reportStats(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveDPlayerContainer() {
|
||||||
|
return document.getElementById('dplayer') || document.querySelector('.dplayer');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDPlayerMaxHeight(maxHeight) {
|
||||||
|
const videoElement = document.querySelector("video");
|
||||||
|
const videoWrap = document.querySelector(".video-play-page .dplayer-video-wrap");
|
||||||
|
|
||||||
|
if (videoElement) {
|
||||||
|
videoElement.style.maxHeight = maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoWrap) {
|
||||||
|
videoWrap.style.maxHeight = maxHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initDPlayer(strPlayUrl) {
|
function initDPlayer(strPlayUrl) {
|
||||||
let DomDPlayer = document.getElementById('dplayer')
|
let DomDPlayer = resolveDPlayerContainer();
|
||||||
|
if (!DomDPlayer) {
|
||||||
|
console.warn('DPlayer 容器不存在');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strPlayUrl) {
|
||||||
|
console.warn('DPlayer 播放地址为空');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
videoPlayer = new DPlayer({
|
videoPlayer = new DPlayer({
|
||||||
container: DomDPlayer,
|
container: DomDPlayer,
|
||||||
autoplay: true,
|
autoplay: true,
|
||||||
@@ -468,25 +495,22 @@ function initDPlayer(strPlayUrl) {
|
|||||||
|
|
||||||
// 监听全屏进入事件
|
// 监听全屏进入事件
|
||||||
videoPlayer.on('fullscreen', function () {
|
videoPlayer.on('fullscreen', function () {
|
||||||
|
if (DomDPlayer.classList) {
|
||||||
DomDPlayer.classList.add("dp-fullscreen");
|
DomDPlayer.classList.add("dp-fullscreen");
|
||||||
// 设置视频元素的样式,取消 max-height
|
}
|
||||||
document.querySelector("video").style.maxHeight = "none";
|
updateDPlayerMaxHeight("none");
|
||||||
document.querySelector(".video-play-page .dplayer-video-wrap").style.maxHeight = "none";
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听全屏退出事件
|
// 监听全屏退出事件
|
||||||
videoPlayer.on('fullscreen_cancel', function () {
|
videoPlayer.on('fullscreen_cancel', function () {
|
||||||
|
if (DomDPlayer.classList) {
|
||||||
DomDPlayer.classList.remove("dp-fullscreen");
|
DomDPlayer.classList.remove("dp-fullscreen");
|
||||||
// 恢复 max-height 为 480px
|
|
||||||
if (isMobile()) {
|
|
||||||
document.querySelector("video").style.maxHeight = "218px";
|
|
||||||
document.querySelector(".video-play-page .dplayer-video-wrap").style.maxHeight = "218px";
|
|
||||||
} else {
|
|
||||||
document.querySelector("video").style.maxHeight = strMaxPlayHeight ?? '480px';
|
|
||||||
document.querySelector(".video-play-page .dplayer-video-wrap").style.maxHeight = strMaxPlayHeight ?? '480px';
|
|
||||||
}
|
}
|
||||||
|
if (isMobile()) {
|
||||||
|
updateDPlayerMaxHeight("218px");
|
||||||
|
} else {
|
||||||
|
updateDPlayerMaxHeight(strMaxPlayHeight ?? '480px');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
videoPlayer.on('error', function () {
|
videoPlayer.on('error', function () {
|
||||||
@@ -499,6 +523,8 @@ function initDPlayer(strPlayUrl) {
|
|||||||
videoPlayer.on('timeupdate', function () {
|
videoPlayer.on('timeupdate', function () {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return videoPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findFirstUrl(obj) {
|
function findFirstUrl(obj) {
|
||||||
@@ -656,4 +682,3 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* -----------------------------------------------------
|
* -----------------------------------------------------
|
||||||
* - 不使用全局变量
|
* - 不使用全局变量
|
||||||
* - 支持一个页面多个播放器
|
* - 支持一个页面多个播放器
|
||||||
* - 只初始化 data-engine="dplayer" 的模块
|
* - 优先初始化 data-engine="dplayer" 的模块,兼容旧模板里的 #dplayer
|
||||||
* =====================================================
|
* =====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -22,8 +22,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveContainer(root) {
|
function resolveContainer(root) {
|
||||||
if (root && root.querySelector) {
|
if (root) {
|
||||||
return root.querySelector('.dplayer, [id="dplayer"]');
|
if (root.matches && (root.matches('.dplayer') || root.id === 'dplayer')) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
if (root.querySelector) {
|
||||||
|
var scoped = root.querySelector('.dplayer, [id="dplayer"]');
|
||||||
|
if (scoped) {
|
||||||
|
return scoped;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return document.getElementById('dplayer') || document.querySelector('.dplayer');
|
return document.getElementById('dplayer') || document.querySelector('.dplayer');
|
||||||
@@ -35,6 +43,18 @@
|
|||||||
showError(root, '播放器容器不存在');
|
showError(root, '播放器容器不存在');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (!strPlayUrl) {
|
||||||
|
showError(root, '播放地址不存在');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (typeof DPlayer === "undefined") {
|
||||||
|
showError(root, '播放器脚本加载失败');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (DomDPlayer.dataset.dplayerReady === '1') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DomDPlayer.dataset.dplayerReady = '1';
|
||||||
|
|
||||||
// ---- 创建 DPlayer 实例 ----
|
// ---- 创建 DPlayer 实例 ----
|
||||||
try {
|
try {
|
||||||
@@ -54,7 +74,11 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
videoPlayer.play()
|
window.videoPlayer = videoPlayer;
|
||||||
|
var playResult = videoPlayer.play()
|
||||||
|
if (playResult && playResult.catch) {
|
||||||
|
playResult.catch(function () {});
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 错误处理(兜底)----
|
// ---- 错误处理(兜底)----
|
||||||
videoPlayer.on('error', function () {
|
videoPlayer.on('error', function () {
|
||||||
@@ -64,7 +88,8 @@
|
|||||||
return videoPlayer;
|
return videoPlayer;
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.warn(e);
|
||||||
|
DomDPlayer.dataset.dplayerReady = '0';
|
||||||
showError(root, '播放器初始化失败');
|
showError(root, '播放器初始化失败');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -77,10 +102,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
ensurePrefix(root);
|
ensurePrefix(root);
|
||||||
var err = root.querySelector('.' + root.dataset.prefix + '-player-status');
|
var errClass = root.dataset.prefix ? root.dataset.prefix + '-player-status' : 'player-status';
|
||||||
|
var err = root.querySelector('.' + errClass);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
err = document.createElement('div');
|
err = document.createElement('div');
|
||||||
err.className = root.dataset.prefix + '-player-status is-error';
|
err.className = errClass + ' is-error';
|
||||||
root.appendChild(err);
|
root.appendChild(err);
|
||||||
}
|
}
|
||||||
err.innerText = msg;
|
err.innerText = msg;
|
||||||
@@ -95,6 +121,20 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveRoot() {
|
||||||
|
var root = document.querySelector('[data-engine="dplayer"]');
|
||||||
|
if (root) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = document.getElementById('dplayer') || document.querySelector('.dplayer');
|
||||||
|
if (!container) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return container.closest ? (container.closest('[data-engine="dplayer"]') || container) : container;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取第一个线路 key(带容错)
|
// 获取第一个线路 key(带容错)
|
||||||
function getDefaultLine() {
|
function getDefaultLine() {
|
||||||
if (typeof arrPlayUrl === "undefined" || !arrPlayUrl || typeof arrPlayUrl !== "object") {
|
if (typeof arrPlayUrl === "undefined" || !arrPlayUrl || typeof arrPlayUrl !== "object") {
|
||||||
@@ -120,23 +160,36 @@
|
|||||||
return arrPlayUrl[playLine][0].url || null;
|
return arrPlayUrl[playLine][0].url || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getIndexedPlayUrl(playLine, playIndex) {
|
||||||
|
if (!arrPlayUrl || !arrPlayUrl[playLine]) {
|
||||||
|
console.warn("播放线路不存在:", playLine, arrPlayUrl);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var intIndex = Math.max(1, parseInt(playIndex, 10) || 1);
|
||||||
|
var activeUrl = arrPlayUrl[playLine][intIndex - 1] || arrPlayUrl[playLine][0];
|
||||||
|
return activeUrl ? (activeUrl.url || null) : null;
|
||||||
|
}
|
||||||
|
|
||||||
// DOM Ready
|
// DOM Ready
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
try {
|
try {
|
||||||
if (typeof strVideoId == "undefined") return;
|
if (typeof strVideoId == "undefined") return;
|
||||||
var root = document.querySelector('[data-engine="dplayer"]');
|
var root = resolveRoot();
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
|
||||||
|
boot();
|
||||||
ensurePrefix(root);
|
ensurePrefix(root);
|
||||||
|
|
||||||
console.log(strPlayType)
|
|
||||||
console.log(boolIsPlayPage)
|
|
||||||
if (typeof strPlayType !== "undefined" && boolIsPlayPage) {
|
if (typeof strPlayType !== "undefined" && boolIsPlayPage) {
|
||||||
|
|
||||||
// 用户指定线路
|
// 用户指定线路
|
||||||
if (strPlayType !== "default") {
|
if (strPlayType !== "default") {
|
||||||
const activeUrl = arrPlayUrl[strPlayType][intPlayUrlIndex - 1];
|
strPlayUrl = getIndexedPlayUrl(strPlayType, intPlayUrlIndex);
|
||||||
strPlayUrl = activeUrl.url;
|
if (!strPlayUrl) {
|
||||||
|
const defaultLine = getDefaultLine();
|
||||||
|
strPlayUrl = getFirstPlayUrl(defaultLine);
|
||||||
|
}
|
||||||
// checkLine(strPlayType);
|
// checkLine(strPlayType);
|
||||||
|
|
||||||
// 默认播放第一个线路的第一个 URL
|
// 默认播放第一个线路的第一个 URL
|
||||||
@@ -145,7 +198,6 @@
|
|||||||
strPlayUrl = getFirstPlayUrl(defaultLine);
|
strPlayUrl = getFirstPlayUrl(defaultLine);
|
||||||
// checkLine(defaultLine);
|
// checkLine(defaultLine);
|
||||||
}
|
}
|
||||||
console.log('strPlayUrlstrPlayUrl')
|
|
||||||
initDPlayer(root, strPlayUrl);
|
initDPlayer(root, strPlayUrl);
|
||||||
|
|
||||||
} else if (strPlayType == "default" && !boolIsPlayPage) {
|
} else if (strPlayType == "default" && !boolIsPlayPage) {
|
||||||
@@ -157,9 +209,7 @@
|
|||||||
initDPlayer(root, strPlayUrl);
|
initDPlayer(root, strPlayUrl);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.warn(error);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -253,7 +253,15 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
},
|
},
|
||||||
|
|
||||||
initDPlayer(strPlayUrl) {
|
initDPlayer(strPlayUrl) {
|
||||||
let DomDPlayer = document.getElementById('dplayer')
|
let DomDPlayer = document.getElementById('dplayer') || document.querySelector('.dplayer')
|
||||||
|
if (!DomDPlayer) {
|
||||||
|
console.warn('DPlayer 容器不存在')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (!strPlayUrl) {
|
||||||
|
console.warn('DPlayer 播放地址为空')
|
||||||
|
return null
|
||||||
|
}
|
||||||
videoPlayer = new DPlayer({
|
videoPlayer = new DPlayer({
|
||||||
container: DomDPlayer,
|
container: DomDPlayer,
|
||||||
autoplay: true,
|
autoplay: true,
|
||||||
@@ -275,11 +283,15 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
|
|
||||||
// 监听全屏进入事件
|
// 监听全屏进入事件
|
||||||
videoPlayer.on('fullscreen', function () {
|
videoPlayer.on('fullscreen', function () {
|
||||||
|
if (DomDPlayer.classList) {
|
||||||
DomDPlayer.classList.add("dp-fullscreen");
|
DomDPlayer.classList.add("dp-fullscreen");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// 监听全屏退出事件
|
// 监听全屏退出事件
|
||||||
videoPlayer.on('fullscreen_cancel', function () {
|
videoPlayer.on('fullscreen_cancel', function () {
|
||||||
|
if (DomDPlayer.classList) {
|
||||||
DomDPlayer.classList.remove("dp-fullscreen");
|
DomDPlayer.classList.remove("dp-fullscreen");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
videoPlayer.on('error', function () {
|
videoPlayer.on('error', function () {
|
||||||
|
|
||||||
@@ -300,6 +312,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
videoPlayer.seek(20); // 跳过到 20 秒
|
videoPlayer.seek(20); // 跳过到 20 秒
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return videoPlayer
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@@ -415,7 +428,15 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
* @param {boolean} boolIsFirstPlayCctv 是否首次播放广告
|
* @param {boolean} boolIsFirstPlayCctv 是否首次播放广告
|
||||||
*/
|
*/
|
||||||
initDPlayer264(strPlayUrl, boolIsFirstPlayCctv = false) {
|
initDPlayer264(strPlayUrl, boolIsFirstPlayCctv = false) {
|
||||||
let DomDPlayer = document.getElementById('dplayer')
|
let DomDPlayer = document.getElementById('dplayer') || document.querySelector('.dplayer')
|
||||||
|
if (!DomDPlayer) {
|
||||||
|
console.warn('DPlayer 容器不存在')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (!strPlayUrl) {
|
||||||
|
console.warn('DPlayer 播放地址为空')
|
||||||
|
return null
|
||||||
|
}
|
||||||
if(videoPlayer == null){
|
if(videoPlayer == null){
|
||||||
videoPlayer = new DPlayer({
|
videoPlayer = new DPlayer({
|
||||||
container: DomDPlayer,
|
container: DomDPlayer,
|
||||||
@@ -439,10 +460,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
videoPlayer.play()
|
videoPlayer.play()
|
||||||
|
|
||||||
videoPlayer.on('fullscreen', function () {
|
videoPlayer.on('fullscreen', function () {
|
||||||
|
if (DomDPlayer.classList) {
|
||||||
DomDPlayer.classList.add("dp-fullscreen");
|
DomDPlayer.classList.add("dp-fullscreen");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
videoPlayer.on('fullscreen_cancel', function () {
|
videoPlayer.on('fullscreen_cancel', function () {
|
||||||
|
if (DomDPlayer.classList) {
|
||||||
DomDPlayer.classList.remove("dp-fullscreen");
|
DomDPlayer.classList.remove("dp-fullscreen");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
videoPlayer.on('error', function () {
|
videoPlayer.on('error', function () {
|
||||||
//videoInfoJs.beforePlay(videoInfoJs.checkPlaylineUrl(videoInfoJs.intPlayLine, strPlayUrl));
|
//videoInfoJs.beforePlay(videoInfoJs.checkPlaylineUrl(videoInfoJs.intPlayLine, strPlayUrl));
|
||||||
@@ -455,6 +480,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
// videoInfoJs.countDownFn()
|
// videoInfoJs.countDownFn()
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
return videoPlayer
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@@ -667,4 +693,3 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
// }));
|
// }));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ yum install ImageMagick
|
|||||||
- 3. 关闭服务 `php think task stop`
|
- 3. 关闭服务 `php think task stop`
|
||||||
- 4. 启动服务 `php think task start -d`
|
- 4. 启动服务 `php think task start -d`
|
||||||
|
|
||||||
|
php think migrate:run
|
||||||
|
php think db:manage seed
|
||||||
|
php think task restart
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
383
docs/gpt-template-seo/13-GPT模板下周7日首页词冲量计划-2026-04-29.md
Normal file
383
docs/gpt-template-seo/13-GPT模板下周7日首页词冲量计划-2026-04-29.md
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
# 13 GPT模板下周7日首页词冲量计划 2026-04-29
|
||||||
|
|
||||||
|
## 1. 计划边界
|
||||||
|
|
||||||
|
本计划只服务 `videoGpt1` / `t_id=1007` 的 GPT 模板站群。
|
||||||
|
|
||||||
|
执行窗口:
|
||||||
|
|
||||||
|
- Day1:`2026-04-30`
|
||||||
|
- Day7:`2026-05-06`
|
||||||
|
|
||||||
|
本轮目标从上一轮的“修链路、推收录、看回访”升级为:
|
||||||
|
|
||||||
|
1. 让已出词域名继续扩大首页词。
|
||||||
|
2. 让已收录域名转出首页词。
|
||||||
|
3. 把深抓强但外部结果弱的域名补成第二批正样本。
|
||||||
|
4. 用代理浏览做百度结果核验、收录核验、页面巡检,不做虚假点击量。
|
||||||
|
|
||||||
|
## 2. 当前基线
|
||||||
|
|
||||||
|
统计时间:`2026-04-29`
|
||||||
|
|
||||||
|
### 2.1 GPT 模板域名池
|
||||||
|
|
||||||
|
- `domain.t_id = 1007`
|
||||||
|
- 当前共 `32` 个域名。
|
||||||
|
|
||||||
|
### 2.2 站外结果基线
|
||||||
|
|
||||||
|
最新站外快照:`2026-04-27`
|
||||||
|
|
||||||
|
爱站已出 PC 词:
|
||||||
|
|
||||||
|
| 域名 | PC 词数 | 当前定位 |
|
||||||
|
|---|---:|---|
|
||||||
|
| `zbsv3.com` | 2 | 已出词放大样本 |
|
||||||
|
| `sdxhtgcl.com` | 1 | 已出词但收录核验失败 |
|
||||||
|
| `sdxtwnc.com` | 1 | 已出词但收录核验未知 |
|
||||||
|
|
||||||
|
百度 `site:` 正样本:
|
||||||
|
|
||||||
|
| 域名 | 状态 | 当前定位 |
|
||||||
|
|---|---|---|
|
||||||
|
| `alarmsinstallers.com` | `indexed_like` | 收录转词样本 |
|
||||||
|
| `caosheninan.com` | `indexed_like` | 收录转词样本 |
|
||||||
|
| `jpjdxs.com` | `indexed_like` | 收录转词样本 |
|
||||||
|
| `nblssy.com` | `indexed_like` | 收录转词样本 |
|
||||||
|
| `vikau.com` | `indexed_like` | 收录转词样本 |
|
||||||
|
|
||||||
|
### 2.3 最近 7 天国内蜘蛛信号
|
||||||
|
|
||||||
|
统计口径:
|
||||||
|
|
||||||
|
- `baiduspider`
|
||||||
|
- `bytespider`
|
||||||
|
- `sogou`
|
||||||
|
- 日期范围:`2026-04-23` 到 `2026-04-29`
|
||||||
|
|
||||||
|
高价值深抓样本:
|
||||||
|
|
||||||
|
| 域名 | 国内蜘蛛总量 | 百度量 | 主要页面 | 判断 |
|
||||||
|
|---|---:|---:|---|---|
|
||||||
|
| `sjzyunyang.com` | 210 | 196 | `detail/play/home` | 深页强,适合补收录与首页承接 |
|
||||||
|
| `jingxifa.com` | 188 | 183 | `play/detail/home` | 深页强,仍有首页词潜力 |
|
||||||
|
| `www.codohealth.com` | 182 | 147 | `detail/other/robots` | 有深页,但 403 偏高 |
|
||||||
|
| `www.lgyz.net` | 146 | 77 | `play/detail/robots` | 有深页,但 403/301 偏高 |
|
||||||
|
| `gxhongzhuang.com` | 90 | 90 | `detail/home` | 深页干净,适合二线冲刺 |
|
||||||
|
|
||||||
|
当前最大卡点:
|
||||||
|
|
||||||
|
1. 多域名仍有 `403 / 444`,会吃掉蜘蛛预算。
|
||||||
|
2. 多域名 `301` 仍偏高,首页词承接容易被拆散。
|
||||||
|
3. sitemap 命中弱,不能只靠首页自然回访。
|
||||||
|
4. 已收录域名和已出词域名不是同一批,需要做桥接。
|
||||||
|
|
||||||
|
## 3. 本轮收益目标
|
||||||
|
|
||||||
|
本轮不能只写“继续观察”,要按首页词收益倒排。
|
||||||
|
|
||||||
|
### A 档目标
|
||||||
|
|
||||||
|
满足大部分即可判定强于上一周:
|
||||||
|
|
||||||
|
1. 爱站 PC 词域名从 `3` 个提升到 `5` 个及以上。
|
||||||
|
2. 首页承接词总数从 `4` 个提升到 `8` 个及以上。
|
||||||
|
3. 至少 `3` 个域名出现明确首页词,且词对应 URL 是首页。
|
||||||
|
4. 百度 `indexed_like` 域名从 `5` 个提升到 `8` 个及以上。
|
||||||
|
5. 国内蜘蛛日均总量不低于上一周,同时 `403 + 444` 占比下降。
|
||||||
|
|
||||||
|
### B 档目标
|
||||||
|
|
||||||
|
1. 爱站 PC 词域名提升到 `4` 个。
|
||||||
|
2. 首页承接词总数提升到 `5-7` 个。
|
||||||
|
3. 百度 `indexed_like` 域名提升到 `6-7` 个。
|
||||||
|
4. 已出词 3 站没有掉词。
|
||||||
|
|
||||||
|
### C 档
|
||||||
|
|
||||||
|
1. 已出词站掉词。
|
||||||
|
2. 百度 `indexed_like` 不增加。
|
||||||
|
3. 国内蜘蛛主要停在 `robots/home`,深页和分类没有接力。
|
||||||
|
4. 代理浏览只能看到 captcha / no_result,无法形成可信验收。
|
||||||
|
|
||||||
|
## 4. 域名分组
|
||||||
|
|
||||||
|
### S1:已出词放大组
|
||||||
|
|
||||||
|
目标:保住已有词,并追加首页词。
|
||||||
|
|
||||||
|
| 域名 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| `zbsv3.com` | 作为本轮 1 号样板,首页词不要大改,只做相关词扩展和内链加密 |
|
||||||
|
| `sdxhtgcl.com` | 先解决 `site:` 失败与 `403/301`,再追第二个首页词 |
|
||||||
|
| `sdxtwnc.com` | 保持首页可见信号,把首页词从单点扩成同义词组 |
|
||||||
|
|
||||||
|
执行重点:
|
||||||
|
|
||||||
|
1. 首页 `title / keywords / description` 不大换方向,只做小步增强。
|
||||||
|
2. 首页首屏、专题区、底部锚文本统一指向当前已出词的语义簇。
|
||||||
|
3. 代理浏览每天核验已有词是否仍能搜到首页。
|
||||||
|
4. 避免同时改 canonical、主标题、域名归一三件事。
|
||||||
|
|
||||||
|
### S2:收录转词组
|
||||||
|
|
||||||
|
目标:用已收录作为底座,把首页词做出来。
|
||||||
|
|
||||||
|
| 域名 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| `alarmsinstallers.com` | 轻量首页词承接,先抢品牌 + 影视长尾 |
|
||||||
|
| `caosheninan.com` | 首页词主打当前站名与内容组合词 |
|
||||||
|
| `jpjdxs.com` | 既有收录又有首页回访,优先补首页专题锚文本 |
|
||||||
|
| `nblssy.com` | 收录稳定,适合做品牌词与站名词 |
|
||||||
|
| `vikau.com` | 已收录但 `403/444` 偏高,先降异常再扩词 |
|
||||||
|
|
||||||
|
执行重点:
|
||||||
|
|
||||||
|
1. 每站只锁 `1` 个主首页词和 `2` 个辅助首页词。
|
||||||
|
2. 首页必须有可见文本承接,不只塞 meta。
|
||||||
|
3. 从首页链到 `3-5` 个详情/播放/搜索页,再从这些页回链首页。
|
||||||
|
4. sitemap 每天推一次,代理浏览每天核验一次 `site:`。
|
||||||
|
|
||||||
|
### S3:深抓转收录组
|
||||||
|
|
||||||
|
目标:把强蜘蛛信号变成收录和首页词。
|
||||||
|
|
||||||
|
| 域名 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| `sjzyunyang.com` | 百度深抓强,优先做首页承接与收录快照 |
|
||||||
|
| `jingxifa.com` | 深页强,减少 301 后继续冲首页词 |
|
||||||
|
| `www.codohealth.com` | 先压 robots/403,再把详情页权重回收首页 |
|
||||||
|
| `www.lgyz.net` | play/detail 有量,优先修 403/301 |
|
||||||
|
| `gxhongzhuang.com` | detail 干净,适合补 play 与首页词 |
|
||||||
|
|
||||||
|
执行重点:
|
||||||
|
|
||||||
|
1. 不把深抓强的站直接改成首页堆词站。
|
||||||
|
2. 先让详情/播放形成稳定 200,再把主题词回收到首页。
|
||||||
|
3. 每天看 `detail + play` 是否还在,不能为了首页词把深页信号打断。
|
||||||
|
|
||||||
|
### S4:风险修复组
|
||||||
|
|
||||||
|
目标:不让异常消耗预算。
|
||||||
|
|
||||||
|
重点域名:
|
||||||
|
|
||||||
|
- `cnzhenbang.com`
|
||||||
|
- `oronorent.com`
|
||||||
|
- `gz-yxsw.com`
|
||||||
|
- `visitsumenep.com`
|
||||||
|
- `sdtljq.com`
|
||||||
|
- `stsgf.com`
|
||||||
|
|
||||||
|
处理原则:
|
||||||
|
|
||||||
|
1. `robots.txt`、`/`、`sitemap_index.xml`、`sitemap.xml` 必须先稳定。
|
||||||
|
2. `403 / 444` 未降前,不投入首页词冲刺资源。
|
||||||
|
3. 只做入口修复和缓存复查,不做大规模模板改动。
|
||||||
|
|
||||||
|
## 5. 代理浏览执行口径
|
||||||
|
|
||||||
|
代理浏览只用于核验,不用于刷点击。
|
||||||
|
|
||||||
|
### 5.1 每日核验项目
|
||||||
|
|
||||||
|
每个重点域名每天核验:
|
||||||
|
|
||||||
|
1. 百度 PC:品牌词。
|
||||||
|
2. 百度 PC:首页主词。
|
||||||
|
3. 百度移动:首页主词。
|
||||||
|
4. 百度 `site:域名`。
|
||||||
|
5. 爱站域名页是否更新关键词。
|
||||||
|
|
||||||
|
### 5.2 代理要求
|
||||||
|
|
||||||
|
1. 至少区分 PC 与移动 User-Agent。
|
||||||
|
2. 优先使用大陆住宅或移动出口。
|
||||||
|
3. 同一域名同一关键词每天最多查 `2` 次。
|
||||||
|
4. 遇到 captcha 记录为 `captcha`,不要连续重试。
|
||||||
|
5. 记录最终 URL、是否首页命中、页码、截图或 HTML 摘要。
|
||||||
|
|
||||||
|
### 5.3 验收表字段
|
||||||
|
|
||||||
|
| 日期 | 代理类型 | 域名 | 查询词代号 | 设备 | 引擎 | 状态 | 首页命中 | 页码/位置 | 备注 |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
|
||||||
|
查询词代号建议:
|
||||||
|
|
||||||
|
- `K0`:品牌词
|
||||||
|
- `K1`:主首页词
|
||||||
|
- `K2`:辅助首页词 1
|
||||||
|
- `K3`:辅助首页词 2
|
||||||
|
|
||||||
|
敏感原词不写到公开日报,保存在运营私表或数据库字段里。
|
||||||
|
|
||||||
|
## 6. 7 日执行节奏
|
||||||
|
|
||||||
|
### Day1:2026-04-30,锁词与基线
|
||||||
|
|
||||||
|
目标:把“多个首页词”从愿望变成列表。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 给 S1/S2 每个域名锁 `K0-K3`。
|
||||||
|
2. 用代理浏览跑一轮百度 PC、移动、`site:` 基线。
|
||||||
|
3. 核验 S1 三站现有首页词是否仍指向首页。
|
||||||
|
4. 检查 S2 五站首页标题、首屏文本、canonical、sitemap。
|
||||||
|
5. 输出《Day1 首页词候选矩阵》。
|
||||||
|
|
||||||
|
当天不过线不进入 Day2:
|
||||||
|
|
||||||
|
1. 首页不是 `200`。
|
||||||
|
2. canonical 指向错误 host。
|
||||||
|
3. `robots / sitemap` 为 `403 / 444`。
|
||||||
|
4. 普通访问和 `?__nocache=1` 差异明显。
|
||||||
|
|
||||||
|
### Day2:2026-05-01,首页承接增强
|
||||||
|
|
||||||
|
目标:让首页真的承接关键词。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. S1 三站只做小改,保已有词。
|
||||||
|
2. S2 五站补首页专题区、站名词、内容词和底部锚文本。
|
||||||
|
3. 每站首页新增 `3-5` 个站内入口,指向搜索/详情/播放正样本。
|
||||||
|
4. 生成或刷新 sitemap。
|
||||||
|
5. 提交百度推送或现有推送任务。
|
||||||
|
|
||||||
|
禁止动作:
|
||||||
|
|
||||||
|
1. 不批量替换所有站标题。
|
||||||
|
2. 不把 32 站同一天全改。
|
||||||
|
3. 不改 `videoGpt1` 共享路由逻辑。
|
||||||
|
|
||||||
|
### Day3:2026-05-02,内链闭环
|
||||||
|
|
||||||
|
目标:让蜘蛛从首页进得去,也能从深页回得来。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. S2 每站选 `5` 个详情/播放正样本补回链。
|
||||||
|
2. S3 每站选 `3` 个深抓 URL 放到首页或专题区。
|
||||||
|
3. 代理浏览复测 S1/S2 的首页可见文本是否已刷新。
|
||||||
|
4. 看国内蜘蛛是否从 `home/robots` 转到 `category/detail/play`。
|
||||||
|
|
||||||
|
### Day4:2026-05-03,异常压降
|
||||||
|
|
||||||
|
目标:把预算浪费降下来。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 重点处理 S4 的 `403 / 444`。
|
||||||
|
2. 复核 `robots.txt`、`sitemap.xml`、`sitemap_index.xml`。
|
||||||
|
3. 对 `301` 偏高站做 host 归一核验。
|
||||||
|
4. 当天不新增大批内容,只修入口。
|
||||||
|
|
||||||
|
### Day5:2026-05-04,出词组二次放大
|
||||||
|
|
||||||
|
目标:把 S1 的单词扩成多词。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. S1 三站补同义首页词。
|
||||||
|
2. S2 中代理浏览已经出现首页命中的站,提升到 S1 临时组。
|
||||||
|
3. 对仍无命中的 S2 站,继续压缩关键词,不扩太散。
|
||||||
|
4. 爱站/百度快照跑一次中期对比。
|
||||||
|
|
||||||
|
### Day6:2026-05-05,收录转词冲刺
|
||||||
|
|
||||||
|
目标:把 `indexed_like` 的站尽量推到首页词。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. S2 五站重新提交 sitemap。
|
||||||
|
2. 代理浏览复查 `site:` 与 K1/K2。
|
||||||
|
3. S3 中 `detail/play` 连续 3 天存在的站,补入收录转词候选。
|
||||||
|
4. 整理掉队站,不再给无效站分配首页词资源。
|
||||||
|
|
||||||
|
### Day7:2026-05-06,验收与下轮分流
|
||||||
|
|
||||||
|
目标:明确是否比上一周更强。
|
||||||
|
|
||||||
|
验收问题:
|
||||||
|
|
||||||
|
1. 爱站 PC 词域名是否超过 `3` 个。
|
||||||
|
2. 首页词总数是否超过 `4` 个。
|
||||||
|
3. 百度 `indexed_like` 是否超过 `5` 个。
|
||||||
|
4. S1 三站是否保住已有词。
|
||||||
|
5. S2 是否至少有 `2` 个站出现首页词或首页命中。
|
||||||
|
6. 国内蜘蛛 `403 + 444` 是否下降。
|
||||||
|
|
||||||
|
输出:
|
||||||
|
|
||||||
|
1. 《GPT模板第二周首页词验收结论》
|
||||||
|
2. 《首页词正样本站名单》
|
||||||
|
3. 《下轮继续放大 / 修复 / 暂停域名表》
|
||||||
|
|
||||||
|
## 7. 每日数据命令
|
||||||
|
|
||||||
|
### 7.1 国内蜘蛛日聚合
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find /www/wwwroot/diff-maccms/SEONexus/code/storage/domain-spider-crawl/runs -maxdepth 3 -name 'crawl-logs.summary.json' | sort
|
||||||
|
```
|
||||||
|
|
||||||
|
筛选口径:
|
||||||
|
|
||||||
|
- `baiduspider`
|
||||||
|
- `bytespider`
|
||||||
|
- `sogou`
|
||||||
|
|
||||||
|
每日回报只看:
|
||||||
|
|
||||||
|
1. 总量
|
||||||
|
2. `home / category / detail / play / sitemap / robots`
|
||||||
|
3. `200 / 301 / 403 / 444`
|
||||||
|
4. S1/S2/S3 分组变化
|
||||||
|
|
||||||
|
### 7.2 站外快照
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
host,
|
||||||
|
MAX(CASE WHEN provider='baidu_site' THEN status END) AS baidu_status,
|
||||||
|
MAX(CASE WHEN provider='aizhan' AND snapshot_type='aizhan_summary' THEN pc_keyword_count END) AS pc_keywords,
|
||||||
|
MAX(CASE WHEN provider='aizhan' AND snapshot_type='aizhan_summary' THEN mobile_keyword_count END) AS mobile_keywords
|
||||||
|
FROM seo_external_snapshot
|
||||||
|
WHERE metric_date = (SELECT MAX(metric_date) FROM seo_external_snapshot)
|
||||||
|
GROUP BY host
|
||||||
|
ORDER BY pc_keywords DESC, baidu_status DESC, host;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 决策规则
|
||||||
|
|
||||||
|
### 继续加码
|
||||||
|
|
||||||
|
满足任意两条:
|
||||||
|
|
||||||
|
1. 首页词新增。
|
||||||
|
2. `indexed_like` 新增。
|
||||||
|
3. `detail + play` 连续 3 天存在。
|
||||||
|
4. `403 + 444` 连续 2 天下滑。
|
||||||
|
|
||||||
|
### 暂停加码
|
||||||
|
|
||||||
|
出现任意两条:
|
||||||
|
|
||||||
|
1. `robots / sitemap` 连续异常。
|
||||||
|
2. 首页访问和 `?__nocache=1` 不一致。
|
||||||
|
3. 代理浏览连续 captcha,无法核验。
|
||||||
|
4. 爱站词掉光。
|
||||||
|
|
||||||
|
### 回炉修复
|
||||||
|
|
||||||
|
出现任意一条:
|
||||||
|
|
||||||
|
1. 首页 `404 / 500 / 502 / 504`。
|
||||||
|
2. canonical 指向错误域名。
|
||||||
|
3. sitemap 返回 `403 / 444`。
|
||||||
|
4. 已出词页面不再返回首页。
|
||||||
|
|
||||||
|
## 9. 一句话结论
|
||||||
|
|
||||||
|
下周 GPT 模板不要再平均推 32 个站;先用 `zbsv3.com / sdxhtgcl.com / sdxtwnc.com` 保词放大,再用 `alarmsinstallers.com / caosheninan.com / jpjdxs.com / nblssy.com / vikau.com` 做收录转词,最后把 `sjzyunyang.com / jingxifa.com / codohealth.com / lgyz.net / gxhongzhuang.com` 的深抓信号补成第二批首页词候选。代理浏览负责核验,不负责制造点击。
|
||||||
252
docs/gpt-template-seo/14-GPT模板Day1进度复盘-2026-04-30.md
Normal file
252
docs/gpt-template-seo/14-GPT模板Day1进度复盘-2026-04-30.md
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
# 14 GPT模板 Day1 进度复盘 2026-04-30
|
||||||
|
|
||||||
|
## 1. 复盘口径
|
||||||
|
|
||||||
|
计划来源:
|
||||||
|
|
||||||
|
- [13-GPT模板下周7日首页词冲量计划-2026-04-29.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/13-GPT模板下周7日首页词冲量计划-2026-04-29.md)
|
||||||
|
|
||||||
|
统计窗口:
|
||||||
|
|
||||||
|
- 蜘蛛日志:`2026-04-30 00:00` 到 `2026-04-30 13:10`
|
||||||
|
- 站外快照:`2026-04-30 03:41`
|
||||||
|
- 对比基准:`2026-04-29 00:00` 到 `2026-04-29 13:10`
|
||||||
|
|
||||||
|
蜘蛛口径:
|
||||||
|
|
||||||
|
- `baiduspider`
|
||||||
|
- `bytespider`
|
||||||
|
- `sogou`
|
||||||
|
|
||||||
|
## 2. 今日总判断
|
||||||
|
|
||||||
|
Day1 进度判定:
|
||||||
|
|
||||||
|
- 蜘蛛侧:`偏正向`
|
||||||
|
- 站点底座:`通过`
|
||||||
|
- 百度收录快照:`偏负向,但快照质量不稳`
|
||||||
|
- 爱站出词:`保住 2 个域名,掉 1 个域名`
|
||||||
|
- 今日综合:`Day1 未失败,但不能直接进入放大;先做代理二次核验和掉词修复`
|
||||||
|
|
||||||
|
一句话:
|
||||||
|
|
||||||
|
> 今天不能因为百度 site 快照回落就判计划失败;蜘蛛数据和站点可访问性是正向的,但站外快照质量差,必须先用代理浏览把 S1/S2 的收录和首页词重新核实,再决定 Day2 是否加码。
|
||||||
|
|
||||||
|
## 3. 蜘蛛日志进度
|
||||||
|
|
||||||
|
### 3.1 国内蜘蛛同比同窗口
|
||||||
|
|
||||||
|
| 指标 | 2026-04-29 00:00-13:10 | 2026-04-30 00:00-13:10 | 判断 |
|
||||||
|
|---|---:|---:|---|
|
||||||
|
| 总量 | 260 | 260 | 持平 |
|
||||||
|
| Baiduspider | 126 | 198 | 明显上升 |
|
||||||
|
| Bytespider | 76 | 46 | 下降 |
|
||||||
|
| Sogou | 58 | 16 | 下降 |
|
||||||
|
| home | 117 | 138 | 上升 |
|
||||||
|
| detail | 8 | 29 | 上升 |
|
||||||
|
| play | 16 | 21 | 上升 |
|
||||||
|
| detail + play | 24 | 50 | 明显上升 |
|
||||||
|
| category | 36 | 2 | 明显下降 |
|
||||||
|
| 200 | 96 | 121 | 上升 |
|
||||||
|
| 301 | 73 | 84 | 略升 |
|
||||||
|
| 403 | 65 | 29 | 下降 |
|
||||||
|
| 444 | 26 | 21 | 下降 |
|
||||||
|
| 403 + 444 | 91 | 50 | 明显下降 |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
1. 百度蜘蛛是今天最强的正向信号。
|
||||||
|
2. `detail + play` 从 `24` 到 `50`,说明深页没有断。
|
||||||
|
3. `403 + 444` 从 `91` 到 `50`,入口异常比昨天同窗口干净。
|
||||||
|
4. 分类页掉到 `2`,是今天主要短板。
|
||||||
|
|
||||||
|
### 3.2 分组表现
|
||||||
|
|
||||||
|
| 分组 | 今日总量 | 主要页面 | 状态判断 |
|
||||||
|
|---|---:|---|---|
|
||||||
|
| S1 已出词放大组 | 22 | `home=18`, `robots=4` | 保词组仍偏首页层,`sdxtwnc.com` 今日未进入日志前列 |
|
||||||
|
| S2 收录转词组 | 42 | `home=30`, `robots=11` | 有回访,但还没进 detail/play |
|
||||||
|
| S3 深抓转收录组 | 82 | `detail=28`, `play=21`, `home=18` | 今日最健康,应继续作为第二批正样本 |
|
||||||
|
| S4 风险修复组 | 25 | `robots=12`, `home=8` | 异常仍高,继续修入口,不参与放大 |
|
||||||
|
|
||||||
|
### 3.3 今日最值得盯的域名
|
||||||
|
|
||||||
|
1. `jingxifa.com`
|
||||||
|
- 今日同窗口 `34`
|
||||||
|
- `detail/play` 仍强
|
||||||
|
- 站外快照出现疑似收录信号,但需代理复验
|
||||||
|
2. `sjzyunyang.com`
|
||||||
|
- 今日同窗口 `21`
|
||||||
|
- 仍是百度深抓强样本
|
||||||
|
3. `www.codohealth.com`
|
||||||
|
- 今日同窗口 `19`
|
||||||
|
- 有深页承接,但后续仍要压 `403/301`
|
||||||
|
4. `zbsv3.com`
|
||||||
|
- 今日同窗口 `18`
|
||||||
|
- 爱站 2 词仍保留,是 S1 头号样板
|
||||||
|
|
||||||
|
## 4. 百度收录快照
|
||||||
|
|
||||||
|
最新快照:`2026-04-30 03:41`
|
||||||
|
|
||||||
|
### 4.1 快照明细变化
|
||||||
|
|
||||||
|
| 域名 | 2026-04-27 | 2026-04-30 | 判断 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `alarmsinstallers.com` | `indexed_like` | `failed` | 掉收录快照 |
|
||||||
|
| `caosheninan.com` | `indexed_like` | `failed` | 掉收录快照 |
|
||||||
|
| `jpjdxs.com` | `indexed_like` | `failed` | 掉收录快照 |
|
||||||
|
| `nblssy.com` | `indexed_like` | `failed` | 掉收录快照 |
|
||||||
|
| `vikau.com` | `indexed_like` | `failed` | 掉收录快照 |
|
||||||
|
| `jingxifa.com` | `failed` | `indexed_like` | 新增疑似收录 |
|
||||||
|
|
||||||
|
### 4.2 重要注意
|
||||||
|
|
||||||
|
`jingxifa.com` 的原始 payload 里同时出现:
|
||||||
|
|
||||||
|
- `query_status = indexed_like`
|
||||||
|
- `matched_text` 包含“未找到相关结果”类文本
|
||||||
|
|
||||||
|
因此今天不能把 `jingxifa.com` 直接算作稳定收录,只能算:
|
||||||
|
|
||||||
|
- `疑似新增`
|
||||||
|
- `必须用代理浏览复核`
|
||||||
|
|
||||||
|
### 4.3 今日判断
|
||||||
|
|
||||||
|
百度收录侧今天不达 Day1 理想状态。
|
||||||
|
|
||||||
|
但这更像是:
|
||||||
|
|
||||||
|
1. Baidu site 快照抓取失败率高。
|
||||||
|
2. 部分查询为空 failed。
|
||||||
|
3. 有安全验证与无结果文本混杂。
|
||||||
|
|
||||||
|
所以今天不建议据此大改模板标题或删除收录转词组。
|
||||||
|
|
||||||
|
## 5. 爱站信息
|
||||||
|
|
||||||
|
最新快照:`2026-04-30 03:41`
|
||||||
|
|
||||||
|
| 域名 | 2026-04-27 PC 词 | 2026-04-30 PC 词 | 判断 |
|
||||||
|
|---|---:|---:|---|
|
||||||
|
| `zbsv3.com` | 2 | 2 | 保住 |
|
||||||
|
| `sdxhtgcl.com` | 1 | 1 | 保住 |
|
||||||
|
| `sdxtwnc.com` | 1 | 0 | 掉词 |
|
||||||
|
|
||||||
|
今日爱站结论:
|
||||||
|
|
||||||
|
1. 已出词域名从 `3` 个降到 `2` 个。
|
||||||
|
2. 总 PC 词从 `4` 降到 `3`。
|
||||||
|
3. `zbsv3.com` 和 `sdxhtgcl.com` 不要大改首页标题。
|
||||||
|
4. `sdxtwnc.com` 需要先做掉词复查,不应直接扩词。
|
||||||
|
|
||||||
|
## 6. Day1 底座复查
|
||||||
|
|
||||||
|
用 Baiduspider UA 复查 S1/S2/S3/S4 重点域名:
|
||||||
|
|
||||||
|
- `/`
|
||||||
|
- `/robots.txt`
|
||||||
|
- `/sitemap.xml`
|
||||||
|
- `/sitemap_index.xml`
|
||||||
|
|
||||||
|
结果:
|
||||||
|
|
||||||
|
- 重点域名裸域全部 `200`
|
||||||
|
- 重点域名 `www` 首页也全部 `200`
|
||||||
|
- S1/S2/S3 首页 canonical 均指向裸域
|
||||||
|
- 未发现首页、robots、sitemap 的站点级不可访问问题
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
> 站点底座不是今天的主问题。当前主矛盾是外部抓取质量、site 快照不稳、以及部分域名日志里仍有 `301/403/444` 消耗。
|
||||||
|
|
||||||
|
## 7. 对 7 日计划的进度判断
|
||||||
|
|
||||||
|
### S1 已出词放大组
|
||||||
|
|
||||||
|
| 域名 | 今日状态 | 动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| `zbsv3.com` | 爱站 2 词保住,首页/robots/sitemap 正常 | 不大改,继续保词,补内链 |
|
||||||
|
| `sdxhtgcl.com` | 爱站 1 词保住,首页/robots/sitemap 正常 | 不大改,先复核 site failed |
|
||||||
|
| `sdxtwnc.com` | 爱站掉 1 词,日志今日弱 | 暂停扩词,代理核验掉词原因 |
|
||||||
|
|
||||||
|
### S2 收录转词组
|
||||||
|
|
||||||
|
| 域名 | 今日状态 | 动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| `alarmsinstallers.com` | site 快照从收录转 failed,但站点底座正常 | 保留候选,代理复核 |
|
||||||
|
| `caosheninan.com` | 同上 | 保留候选,代理复核 |
|
||||||
|
| `jpjdxs.com` | 同上,今日日志弱 | 补首页到详情入口,不大改标题 |
|
||||||
|
| `nblssy.com` | 同上,有首页回访 | 保留品牌词承接 |
|
||||||
|
| `vikau.com` | 同上,今日回访相对最好 | 优先复核,若代理仍有收录则继续冲 |
|
||||||
|
|
||||||
|
### S3 深抓转收录组
|
||||||
|
|
||||||
|
今日最值得加权的是 S3。
|
||||||
|
|
||||||
|
优先级:
|
||||||
|
|
||||||
|
1. `jingxifa.com`
|
||||||
|
2. `sjzyunyang.com`
|
||||||
|
3. `codohealth.com`
|
||||||
|
4. `lgyz.net`
|
||||||
|
5. `gxhongzhuang.com`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 保持 detail/play 稳定。
|
||||||
|
2. 用首页专题区接回深页主题。
|
||||||
|
3. 代理复核 `site:` 和首页主词。
|
||||||
|
|
||||||
|
### S4 风险修复组
|
||||||
|
|
||||||
|
今日仍不参与放大。
|
||||||
|
|
||||||
|
优先处理:
|
||||||
|
|
||||||
|
1. `cnzhenbang.com`
|
||||||
|
2. `oronorent.com`
|
||||||
|
3. `visitsumenep.com`
|
||||||
|
4. `sdtljq.com`
|
||||||
|
5. `stsgf.com`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 查日志里的具体 `403/444` path。
|
||||||
|
2. 对比裸域与 `www` 的 canonical。
|
||||||
|
3. 不做首页词扩展。
|
||||||
|
|
||||||
|
## 8. 今天下一步
|
||||||
|
|
||||||
|
### 8.1 必做
|
||||||
|
|
||||||
|
1. 用代理浏览复核:
|
||||||
|
- `zbsv3.com` 当前 2 个首页词是否还在。
|
||||||
|
- `sdxhtgcl.com` 当前 1 个首页词是否还在。
|
||||||
|
- `sdxtwnc.com` 掉词是否真实。
|
||||||
|
- S2 五站 `site:` 是否真的掉收录。
|
||||||
|
- `jingxifa.com` 是否真实新增收录。
|
||||||
|
2. 重新跑一轮站外快照,要求记录 captcha / no_result / failed 的具体原因。
|
||||||
|
3. S1 不大改首页标题,只补轻量内链与正文承接。
|
||||||
|
4. S3 允许进入 Day2 加权,尤其是 `jingxifa.com` 和 `sjzyunyang.com`。
|
||||||
|
|
||||||
|
### 8.2 暂缓
|
||||||
|
|
||||||
|
1. 暂缓 32 站整体改标题。
|
||||||
|
2. 暂缓把 S2 直接判死。
|
||||||
|
3. 暂缓对 `sdxtwnc.com` 做大改。
|
||||||
|
4. 暂缓把 `jingxifa.com` 当作稳定收录公布。
|
||||||
|
|
||||||
|
## 9. Day1 结论
|
||||||
|
|
||||||
|
Day1 当前是:
|
||||||
|
|
||||||
|
- `蜘蛛达标`
|
||||||
|
- `站点底座达标`
|
||||||
|
- `爱站部分达标`
|
||||||
|
- `百度收录未达标/需复核`
|
||||||
|
|
||||||
|
下一步不是加大模板改动,而是:
|
||||||
|
|
||||||
|
> 先用代理浏览确认外部结果面,再把资源从掉词站临时转给 `jingxifa.com / sjzyunyang.com / codohealth.com` 这类有深抓的站,保住 `zbsv3.com / sdxhtgcl.com` 的首页词,不让 Day1 的外部快照波动打乱整周节奏。
|
||||||
209
docs/gpt-template-seo/15-GPT模板Day2阶段效果复盘-2026-05-01.md
Normal file
209
docs/gpt-template-seo/15-GPT模板Day2阶段效果复盘-2026-05-01.md
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
# 15 GPT模板 Day2 阶段效果复盘 2026-05-01
|
||||||
|
|
||||||
|
## 1. 复盘口径
|
||||||
|
|
||||||
|
计划来源:
|
||||||
|
|
||||||
|
- [13-GPT模板下周7日首页词冲量计划-2026-04-29.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/13-GPT模板下周7日首页词冲量计划-2026-04-29.md)
|
||||||
|
- [14-GPT模板Day1进度复盘-2026-04-30.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/14-GPT模板Day1进度复盘-2026-04-30.md)
|
||||||
|
|
||||||
|
统计窗口:
|
||||||
|
|
||||||
|
- 蜘蛛日志:`code/storage/domain-spider-crawl/runs/20260501`,截至 `2026-05-01 13:20`
|
||||||
|
- 对比窗口:同口径聚合 `20260429 / 20260430 / 20260501` 的结构化 `crawl-logs.summary.json`
|
||||||
|
- 站外快照:`seo_external_snapshot.metric_date = 2026-05-01`
|
||||||
|
- 辅助反馈池:`code/data/seo_resource/keyword_feedback/hot_keywords.latest.json`,更新时间 `2026-05-01 04:01:02 +08:00`
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
`keyword_feedback/hot_keywords.latest.json` 是 30 天反馈池,会带入历史 `indexed_like` 与历史爱站词;今天判断收录/爱站增减,以 `seo_external_snapshot` 当日快照为准。
|
||||||
|
|
||||||
|
## 2. 今日总判断
|
||||||
|
|
||||||
|
Day2 进度判定:
|
||||||
|
|
||||||
|
- 蜘蛛侧:`回落,但百度仍是主力`
|
||||||
|
- 深页侧:`S3 仍有正向样本,但 detail 明显偏少`
|
||||||
|
- 百度收录快照:`未达标,且今天 captcha/failed 质量问题仍重`
|
||||||
|
- 爱站出词:`总词数保 3,出词域名缩到 1`
|
||||||
|
- 今日综合:`Day2 不适合全站加码;只保 S1 头部,继续把 S3 当第二批候选,S2 先不判死`
|
||||||
|
|
||||||
|
一句话:
|
||||||
|
|
||||||
|
> 5 月 1 日不是失败日,但也不是放大日。`zbsv3.com` 出词从 2 到 3 是唯一明确外部增量;百度 site 快照今天没有有效新增收录,蜘蛛从 4 月 30 的强势回访回落,Day2 应该收缩到“保词、补首页承接、压异常、等下一次稳定快照”。
|
||||||
|
|
||||||
|
## 3. 蜘蛛日志阶段变化
|
||||||
|
|
||||||
|
### 3.1 国内蜘蛛日聚合
|
||||||
|
|
||||||
|
统计口径:`baiduspider + bytespider + sogou`
|
||||||
|
|
||||||
|
| 指标 | 2026-04-29 | 2026-04-30 | 2026-05-01 截至 13:20 | 判断 |
|
||||||
|
|---|---:|---:|---:|---|
|
||||||
|
| 总量 | 436 | 616 | 253 | Day2 回落 |
|
||||||
|
| Baiduspider | 243 | 488 | 148 | 仍是主力,但低于 Day1 |
|
||||||
|
| Bytespider | 107 | 80 | 46 | 持续偏弱 |
|
||||||
|
| Sogou | 86 | 48 | 59 | 小幅回升 |
|
||||||
|
| home | 212 | 345 | 111 | 首页回访仍在 |
|
||||||
|
| detail | 31 | 45 | 4 | 今日短板 |
|
||||||
|
| play | 26 | 25 | 15 | 仍有接力 |
|
||||||
|
| detail + play | 57 | 70 | 19 | 深页接力减弱 |
|
||||||
|
| category | 54 | 22 | 28 | 比 Day1 好,但主要集中风险站 |
|
||||||
|
| 200 | 170 | 378 | 99 | 有效返回回落 |
|
||||||
|
| 301 | 133 | 138 | 73 | 仍偏高 |
|
||||||
|
| 403 | 96 | 63 | 53 | 没有继续明显下降 |
|
||||||
|
| 444 | 37 | 32 | 19 | 有改善,但样本量小 |
|
||||||
|
| 403 + 444 | 133 | 95 | 72 | 占比偏高 |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
1. Day1 的百度强回访没有延续到同等强度。
|
||||||
|
2. `detail + play` 从 `70` 回到 `19`,说明深页接力需要继续保,不要把模板重心突然全切首页。
|
||||||
|
3. `301 + 403 + 444 = 145`,占总量约 `57.3%`,预算浪费仍是 Day2 主问题。
|
||||||
|
4. 今日 `category=28` 主要由 `cnzhenbang.com` 贡献,不能直接视为健康分类页增长。
|
||||||
|
|
||||||
|
### 3.2 分组表现
|
||||||
|
|
||||||
|
| 分组 | 今日量 | 主要结构 | 判断 |
|
||||||
|
|---|---:|---|---|
|
||||||
|
| S1 已出词放大组 | 10 | `sdxtwnc.com home=10` | `zbsv3.com / sdxhtgcl.com` 今日蜘蛛弱,但爱站外部仍有信号 |
|
||||||
|
| S2 收录转词组 | 30 | `vikau.com=15`,其它偏弱 | 百度快照失败,不适合直接扩大标题 |
|
||||||
|
| S3 深抓转收录组 | 59 | `sjzyunyang.com=20`, `codohealth.com=19`, `lgyz.net=10`, `jingxifa.com=8` | 仍是今天最值得保的第二批候选 |
|
||||||
|
| S4 风险修复组 | 57 | `cnzhenbang.com=32`, `gz-yxsw.com=13` | 异常仍多,只修入口,不加码 |
|
||||||
|
|
||||||
|
### 3.3 今日重点样本
|
||||||
|
|
||||||
|
| 域名 | 今日蜘蛛 | 页面结构 | 状态结构 | 判断 |
|
||||||
|
|---|---:|---|---|---|
|
||||||
|
| `sjzyunyang.com` | 20 | `home=8`, `play=8`, `detail=4` | `200=12`, `301=8` | S3 今日最好,继续保深页和回链 |
|
||||||
|
| `codohealth.com` | 19 | `home=8`, `other=8`, `robots=3` | `200=10`, `301=6`, `403=3` | 仍有抓取,但异常要压 |
|
||||||
|
| `jingxifa.com` | 8 | `home=8` | `200=8` | 干净但变浅,暂不当稳定收录样板 |
|
||||||
|
| `lgyz.net` | 10 | `robots=6`, `play=4` | `403=5`, `301=3`, `200=2` | 有 play,但入口异常偏重 |
|
||||||
|
| `sdxtwnc.com` | 10 | `home=10` | `200=10` | 蜘蛛回访干净,可做掉词复查 |
|
||||||
|
| `cnzhenbang.com` | 32 | `category=28` | `403=17`, `301=15` | 风险站,不参与加码 |
|
||||||
|
|
||||||
|
## 4. 百度收录快照
|
||||||
|
|
||||||
|
最新当日快照:`2026-05-01`
|
||||||
|
|
||||||
|
### 4.1 大盘变化
|
||||||
|
|
||||||
|
| 日期 | indexed_like | failed | unknown | 判断 |
|
||||||
|
|---|---:|---:|---:|---|
|
||||||
|
| 2026-04-27 | 5 | 10 | 17 | 基线日,有 5 个收录样本 |
|
||||||
|
| 2026-04-30 | 1 | 30 | 1 | Day1 回落,仅 `jingxifa.com` 疑似 |
|
||||||
|
| 2026-05-01 | 0 | 30 | 2 | Day2 无有效新增,2 个 captcha/unknown |
|
||||||
|
|
||||||
|
### 4.2 今日重点域名
|
||||||
|
|
||||||
|
| 域名 | 2026-04-30 | 2026-05-01 | 判断 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `jingxifa.com` | `indexed_like` | `failed` | 昨天疑似新增未坐实 |
|
||||||
|
| `zbsv3.com` | `failed` | `unknown` | 今天遇到百度验证码,不是收录成功 |
|
||||||
|
| `visitsumenep.com` | `failed` | `unknown` | 验证码样本,不参与正向统计 |
|
||||||
|
| S2 五站 | `failed` | `failed` | 当日快照仍不支持“已恢复收录”结论 |
|
||||||
|
|
||||||
|
重要判断:
|
||||||
|
|
||||||
|
1. 今天不能把 30 天反馈池里的 `indexed_like=true` 当作当日新增收录。
|
||||||
|
2. `failed` payload 多数为空返回,说明采集质量仍差;但按验收规则,今天只能算未达标。
|
||||||
|
3. 下一轮必须用代理浏览或更稳定出口复核 `site:`,并记录 `captcha / no_result / empty_failed` 三类原因。
|
||||||
|
|
||||||
|
## 5. 爱站信息
|
||||||
|
|
||||||
|
最新当日快照:`2026-05-01`
|
||||||
|
|
||||||
|
| 日期 | 有 PC 词域名数 | PC 词总数 | 主要变化 |
|
||||||
|
|---|---:|---:|---|
|
||||||
|
| 2026-04-27 | 3 | 4 | `zbsv3.com=2`, `sdxhtgcl.com=1`, `sdxtwnc.com=1` |
|
||||||
|
| 2026-04-30 | 2 | 3 | `zbsv3.com=2`, `sdxhtgcl.com=1` |
|
||||||
|
| 2026-05-01 | 1 | 3 | `zbsv3.com=3` |
|
||||||
|
|
||||||
|
今日爱站结论:
|
||||||
|
|
||||||
|
1. `zbsv3.com` 从 `2` 个 PC 词到 `3` 个 PC 词,是今天唯一明确外部增量。
|
||||||
|
2. `sdxhtgcl.com` 当日爱站 summary 为 `0`,但 30 天反馈池仍保留 4 月 30 日词;先按“掉出当日快照、待复核”处理。
|
||||||
|
3. `sdxtwnc.com` 当日 summary 仍为 `0`,30 天反馈池保留 4 月 27 日历史词;不应按稳定保词站加码。
|
||||||
|
4. 今日不写具体关键词到公开日报,避免把敏感词扩散到协作文档。
|
||||||
|
|
||||||
|
## 6. 对 7 日计划的阶段判断
|
||||||
|
|
||||||
|
### S1 已出词放大组
|
||||||
|
|
||||||
|
| 域名 | 今日状态 | 动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| `zbsv3.com` | 爱站 `3` 词,百度 `unknown/captcha`,今日蜘蛛弱 | 保词优先,不改主标题;补首页正文承接和少量内链 |
|
||||||
|
| `sdxhtgcl.com` | 当日爱站 summary 掉到 `0`,历史词仍在反馈池 | 暂停扩词,代理复查当前词是否仍命中 |
|
||||||
|
| `sdxtwnc.com` | 今日蜘蛛 `home=10/200=10`,但当日爱站仍 `0` | 可以做掉词复查和轻量首页承接,不做大改 |
|
||||||
|
|
||||||
|
### S2 收录转词组
|
||||||
|
|
||||||
|
| 域名 | 今日状态 | 动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| `alarmsinstallers.com` | 百度当日 `failed`,蜘蛛弱 | 保留候选,等待代理 site 复核 |
|
||||||
|
| `caosheninan.com` | 百度当日 `failed`,今日弱 | 不扩标题,先做首页可见文本检查 |
|
||||||
|
| `jpjdxs.com` | 百度当日 `failed`,今日弱 | 补首页入口即可 |
|
||||||
|
| `nblssy.com` | 百度当日 `failed`,今日弱 | 不判死,继续观察 |
|
||||||
|
| `vikau.com` | 今日 S2 内蜘蛛最强,但异常多 | 优先压 `403/444`,再谈转词 |
|
||||||
|
|
||||||
|
### S3 深抓转收录组
|
||||||
|
|
||||||
|
今日继续把 S3 当第二批候选,但动作要收敛。
|
||||||
|
|
||||||
|
优先级:
|
||||||
|
|
||||||
|
1. `sjzyunyang.com`
|
||||||
|
2. `codohealth.com`
|
||||||
|
3. `jingxifa.com`
|
||||||
|
4. `lgyz.net`
|
||||||
|
5. `gxhongzhuang.com`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. `sjzyunyang.com` 保持 `detail/play`,补深页回首页。
|
||||||
|
2. `codohealth.com` 压 `403/301`,避免深抓预算浪费。
|
||||||
|
3. `jingxifa.com` 昨日疑似收录未坐实,只做首页承接,不作为稳定收录样板宣传。
|
||||||
|
4. `lgyz.net` 先处理 `robots/403/301`,保留 `play` 正样本。
|
||||||
|
|
||||||
|
### S4 风险修复组
|
||||||
|
|
||||||
|
今日继续不参与放大。
|
||||||
|
|
||||||
|
重点:
|
||||||
|
|
||||||
|
1. `cnzhenbang.com`:`category=28` 但全是 `301/403`,优先修 URL family 与入口返回。
|
||||||
|
2. `gz-yxsw.com`:今日 `home=13` 且多数 `200`,可从风险组里继续观察,但暂不加词。
|
||||||
|
3. `visitsumenep.com`:百度 `unknown/captcha`,不作为收录正样本。
|
||||||
|
|
||||||
|
## 7. Day2 下一步
|
||||||
|
|
||||||
|
### 7.1 今天可做
|
||||||
|
|
||||||
|
1. `zbsv3.com`:保现有 3 词,不改主标题;首页补同语义承接与 `3-5` 个站内入口。
|
||||||
|
2. `sdxhtgcl.com / sdxtwnc.com`:用代理复查历史词是否仍存在,结果分 `命中首页 / 命中内页 / 未命中 / captcha`。
|
||||||
|
3. `sjzyunyang.com`:选今日 `detail/play` 样本补回链首页。
|
||||||
|
4. `codohealth.com / lgyz.net`:压 `403/301`,先让 `robots / sitemap / play` 稳。
|
||||||
|
5. 重新跑百度 site 快照时,采集脚本必须记录失败原因,空 payload 不再和无结果混写。
|
||||||
|
|
||||||
|
### 7.2 今天暂缓
|
||||||
|
|
||||||
|
1. 暂缓 32 站批量改标题。
|
||||||
|
2. 暂缓把 S2 五站判死或全部移出候选。
|
||||||
|
3. 暂缓把 `jingxifa.com` 当稳定新增收录。
|
||||||
|
4. 暂缓扩大 `cnzhenbang.com` 分类页流量,先修异常。
|
||||||
|
|
||||||
|
## 8. Day2 结论
|
||||||
|
|
||||||
|
当前 7 日计划处在:
|
||||||
|
|
||||||
|
- `爱站局部达标`:`zbsv3.com` 有明确增量。
|
||||||
|
- `百度收录未达标`:当日 `indexed_like=0`,且采集质量仍需代理复核。
|
||||||
|
- `蜘蛛未失败但回落`:百度仍主导,但深页接力变弱。
|
||||||
|
- `执行策略应收缩`:从“加码”改为“保词 + 补承接 + 压异常 + 等复核”。
|
||||||
|
|
||||||
|
下一步不是扩大站群动作,而是把资源集中在:
|
||||||
|
|
||||||
|
1. `zbsv3.com` 保词。
|
||||||
|
2. `sdxhtgcl.com / sdxtwnc.com` 查掉词真假。
|
||||||
|
3. `sjzyunyang.com / codohealth.com / jingxifa.com / lgyz.net` 保深抓和降异常。
|
||||||
|
4. 百度 site 复核改成高质量代理浏览,不再用空失败快照主导决策。
|
||||||
176
docs/gpt-template-seo/16-GPT模板多源协作边界与真实启用核查-2026-05-01.md
Normal file
176
docs/gpt-template-seo/16-GPT模板多源协作边界与真实启用核查-2026-05-01.md
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# 16 GPT模板多源协作边界与真实启用核查 2026-05-01
|
||||||
|
|
||||||
|
## 1. 多源协作边界
|
||||||
|
|
||||||
|
当前部署边界:
|
||||||
|
|
||||||
|
- GPT 模板:当前共有 `3` 套源。
|
||||||
|
- 老模板 `1001-1005`:当前共有 `4` 套源。
|
||||||
|
- 当前这套 `SEONexus` 是 GPT 模板主要测试源。
|
||||||
|
|
||||||
|
代码修改规则:
|
||||||
|
|
||||||
|
1. GPT 模板所有代码修改只能在当前主测试源做。
|
||||||
|
2. 其它 GPT 源只允许拉取主测试源已验证代码,不能单独改代码。
|
||||||
|
3. 其它 GPT 源发现问题时,只能把优化记录、蜘蛛日志、收录/爱站反馈写回文档。
|
||||||
|
4. 老模板也必须固定一个测试优化源;其它老模板源只拉取和反馈。
|
||||||
|
5. 禁止在多个源同时试不同 SEO 代码,否则无法判断是哪一个动作影响了蜘蛛和收录。
|
||||||
|
|
||||||
|
一句话:
|
||||||
|
|
||||||
|
> 当前源负责“试代码和出结论”,其它源负责“拉取、跑数据、回传反馈”。
|
||||||
|
|
||||||
|
## 2. GPT 模板优化是否已经开始使用
|
||||||
|
|
||||||
|
### 2.1 已经进入页面渲染链的部分
|
||||||
|
|
||||||
|
`videoGpt1` 已经在前台页面使用 `seo_copy`:
|
||||||
|
|
||||||
|
| 页面 | 使用位置 | 判断 |
|
||||||
|
|---|---|---|
|
||||||
|
| 首页 | `videoGpt1/index/index.html` | 已使用 `scene="home"` |
|
||||||
|
| 搜索页 | `videoGpt1/video/getSearchVideo.html` | 已使用 `scene="search"` |
|
||||||
|
| 分类频道页 | `videoGpt1/video/getCategoryType.html` | 已使用 `scene="category_index"` |
|
||||||
|
| 分类列表页 | `videoGpt1/video/getCategory.html` | 已使用 `scene="category_list"` |
|
||||||
|
| 榜单页 | `videoGpt1/video/getRankIndex.html` / `getRankList.html` | 已使用榜单补料 |
|
||||||
|
| 详情页 | `module/detail_main/desc.html` | 已使用 `scene="detail"` |
|
||||||
|
| 播放页 | `video/getVideoPlayUrl.html` | 已使用 `scene="play"` |
|
||||||
|
|
||||||
|
前台读取链路:
|
||||||
|
|
||||||
|
1. 模板调用 `{video:seocopy ... /}`。
|
||||||
|
2. 标签进入 `VideoService::getSeoCopyBlock(...)`。
|
||||||
|
3. 优先读取 `code/data/seo_copy_published/{host}/{scene}/{page}.json`。
|
||||||
|
4. 缺失时回退到 `code/data/seo_copy/{host}/{scene}/{page}.json`。
|
||||||
|
5. 再缺失时用 `SeoCopyFallbackBuilder` 兜底,避免页面空白。
|
||||||
|
|
||||||
|
### 2.2 已经进入 TKD 的部分
|
||||||
|
|
||||||
|
首页、分类、搜索等页面的 TKD 已经不是只靠旧标题池:
|
||||||
|
|
||||||
|
1. `site:seotkd` 调用 `SiteContext::getSeoTkd(...)`。
|
||||||
|
2. 首页、搜索页、分类页、榜单页优先读域名记录和已发布 `seo_copy`。
|
||||||
|
3. 详情/播放页保留新池、旧池、域名记录的兼容兜底。
|
||||||
|
|
||||||
|
所以“AI 文案 / 引导文案”并不是只停在文件里,已经进入前台页面输出。
|
||||||
|
|
||||||
|
## 3. 发现的真实断点
|
||||||
|
|
||||||
|
本次核查发现一个关键问题:
|
||||||
|
|
||||||
|
> `seo_copy` 已经在用,但 `keyword_feedback` 之前主要停在数据产物层,没有充分反哺到运行时页面承接。
|
||||||
|
|
||||||
|
具体表现:
|
||||||
|
|
||||||
|
1. 爱站/百度反馈已经生成到 `code/data/seo_resource/keyword_feedback/`。
|
||||||
|
2. `hot_keywords.latest.json` 和 `by_host/*.json` 里有域名级反馈。
|
||||||
|
3. 但运行时 `VideoService::getSeoCopyBlock(...)` 原本不读取这些反馈。
|
||||||
|
4. 结果就是:采集到了“哪些词有反馈”,页面却没有自动增强对应承接。
|
||||||
|
|
||||||
|
这会导致一个 SEO 问题:
|
||||||
|
|
||||||
|
- 文案系统在工作。
|
||||||
|
- 蜘蛛日志在跟踪。
|
||||||
|
- 爱站/百度在回传信号。
|
||||||
|
- 但三者没有形成闭环,页面承接容易落后于真实出词方向。
|
||||||
|
|
||||||
|
## 4. 本次已做代码修正
|
||||||
|
|
||||||
|
只在当前 GPT 主测试源修改:
|
||||||
|
|
||||||
|
- [VideoService.php](/www/wwwroot/diff-maccms/SEONexus/code/app/services/VideoService.php)
|
||||||
|
|
||||||
|
新增运行时闭环:
|
||||||
|
|
||||||
|
1. 首页、分类、搜索页补料块读取当前域名的 `keyword_feedback/by_host/*.json`。
|
||||||
|
2. 优先使用爱站关键词;没有爱站词时,使用域名导入关键词兜底。
|
||||||
|
3. 将近期外部反馈写入页面补料块 `_keyword_feedback`。
|
||||||
|
4. 在页面导览卡片中增加“近期检索方向”。
|
||||||
|
5. 在辅助说明里补一句近期重点承接方向。
|
||||||
|
|
||||||
|
边界:
|
||||||
|
|
||||||
|
1. 不改老模板。
|
||||||
|
2. 不改其它 GPT 源。
|
||||||
|
3. 不批量改标题。
|
||||||
|
4. 不替换原 AI 文案,只做反馈增强。
|
||||||
|
5. 只增强首页、分类、搜索这类承接页,不动详情/播放页主体逻辑。
|
||||||
|
|
||||||
|
## 5. 为什么当前效果仍然感觉不行
|
||||||
|
|
||||||
|
从 Day1/Day2 数据看,不是“完全没优化”,而是优化还没有形成稳定正循环。
|
||||||
|
|
||||||
|
当前问题优先级:
|
||||||
|
|
||||||
|
1. 百度 `site:` 采集质量差,`failed` 空 payload 和 captcha 混在一起,导致判断失真。
|
||||||
|
2. Day2 蜘蛛回落,`detail + play` 明显变少,深页接力弱。
|
||||||
|
3. `301 / 403 / 444` 占比仍高,蜘蛛预算被消耗。
|
||||||
|
4. 爱站只看到 `zbsv3.com` 有明确增量,其它出词站没有稳定扩张。
|
||||||
|
5. 外部反馈原本没有自动进入页面承接,本次已补。
|
||||||
|
|
||||||
|
## 6. 接下来 SEO 推进原则
|
||||||
|
|
||||||
|
当前不要平均推 32 个站。
|
||||||
|
|
||||||
|
第一优先级:保住已出词站
|
||||||
|
|
||||||
|
- `zbsv3.com`:保现有词,不大改主标题;只补首页承接、内链、详情入口。
|
||||||
|
- `sdxhtgcl.com / sdxtwnc.com`:先复核掉词真假,再决定是否扩词。
|
||||||
|
|
||||||
|
第二优先级:把深抓站做成第二批正样本
|
||||||
|
|
||||||
|
- `sjzyunyang.com`
|
||||||
|
- `codohealth.com`
|
||||||
|
- `jingxifa.com`
|
||||||
|
- `lgyz.net`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 保 `detail/play` 不断。
|
||||||
|
2. 首页补回深页入口。
|
||||||
|
3. 压 `301/403/444`。
|
||||||
|
4. sitemap 保持可访问。
|
||||||
|
|
||||||
|
第三优先级:修风险站
|
||||||
|
|
||||||
|
- `cnzhenbang.com`
|
||||||
|
- `oronorent.com`
|
||||||
|
- `visitsumenep.com`
|
||||||
|
- `sdtljq.com`
|
||||||
|
- `stsgf.com`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 只修入口、canonical、robots、sitemap。
|
||||||
|
2. 不加词。
|
||||||
|
3. 不扩标题。
|
||||||
|
|
||||||
|
## 7. 每日闭环
|
||||||
|
|
||||||
|
每天只看四件事:
|
||||||
|
|
||||||
|
1. 蜘蛛:`baiduspider / bytespider / sogou` 的 `home / detail / play / sitemap / robots`。
|
||||||
|
2. 异常:`301 / 403 / 444` 是否下降。
|
||||||
|
3. 百度:`site:` 结果必须区分 `indexed_like / no_result / captcha / empty_failed`。
|
||||||
|
4. 爱站:出词域名数和 PC 词总数,不只看历史反馈池。
|
||||||
|
|
||||||
|
执行节奏:
|
||||||
|
|
||||||
|
1. 当前源先改。
|
||||||
|
2. 当前源跑 24-48 小时。
|
||||||
|
3. 看蜘蛛和站外反馈。
|
||||||
|
4. 有效再同步其它 GPT 源。
|
||||||
|
5. 其它源只写反馈,不单独试代码。
|
||||||
|
|
||||||
|
## 8. 今日结论
|
||||||
|
|
||||||
|
GPT 模板的 AI 文案和引导文案已经开始使用,但之前没有把外部反馈真正接入运行时页面承接。
|
||||||
|
|
||||||
|
本次已把 `keyword_feedback` 接入 `VideoService::getSeoCopyBlock(...)`,让爱站/百度反馈能进入首页、分类、搜索页的可见内容层。
|
||||||
|
|
||||||
|
后续判断效果时,不再只看“有没有写文案”,而要看:
|
||||||
|
|
||||||
|
1. 蜘蛛是否继续抓这些承接区。
|
||||||
|
2. 已出词站是否保住。
|
||||||
|
3. 深抓站是否转收录。
|
||||||
|
4. `301/403/444` 是否降下来。
|
||||||
262
docs/gpt-template-seo/17-GPT模板7日10词上首页冲刺目标-2026-05-01.md
Normal file
262
docs/gpt-template-seo/17-GPT模板7日10词上首页冲刺目标-2026-05-01.md
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
# 17 GPT模板 7日10词上首页冲刺目标 2026-05-01
|
||||||
|
|
||||||
|
## 1. 硬目标
|
||||||
|
|
||||||
|
执行窗口:
|
||||||
|
|
||||||
|
- 起跑:`2026-05-01`
|
||||||
|
- 冲刺结束:`2026-05-07`
|
||||||
|
- 验收:`2026-05-08 上午`
|
||||||
|
|
||||||
|
核心目标:
|
||||||
|
|
||||||
|
> 7 日后,GPT 模板主测试源必须冲出至少 `10` 个关键词进入百度首页结果页。
|
||||||
|
|
||||||
|
验收口径:
|
||||||
|
|
||||||
|
1. 百度 PC 首页结果页命中,算 `1` 个有效词。
|
||||||
|
2. 百度移动首页结果页命中,也算有效,但 PC 优先级更高。
|
||||||
|
3. 同一个关键词 PC/移动都命中,只算 `1` 个词。
|
||||||
|
4. 同一个关键词多个域名命中,只按最稳定的 `1` 个主命中统计。
|
||||||
|
5. 优先要求落地 URL 是站点首页;若落地到分类/搜索/详情页,必须能稳定回链首页,且页面主题和词一致。
|
||||||
|
6. 遇到 captcha 不算成功,记录为 `captcha`。
|
||||||
|
7. 原关键词不写入公开文档,只用 `K0/K1/K2...` 编号管理。
|
||||||
|
|
||||||
|
最低通过线:
|
||||||
|
|
||||||
|
- `10` 个关键词进入百度首页。
|
||||||
|
- 至少 `4` 个域名参与命中,不能只靠单域名短期波动。
|
||||||
|
- `zbsv3.com` 当前已出词必须保住,不能为了冲新词把已有词打掉。
|
||||||
|
|
||||||
|
## 2. 目标拆分
|
||||||
|
|
||||||
|
### 2.1 主攻域名
|
||||||
|
|
||||||
|
| 组别 | 域名 | 7日目标 | 定位 |
|
||||||
|
|---|---|---:|---|
|
||||||
|
| S1 | `zbsv3.com` | 4 词 | 已出词放大,作为头号样板 |
|
||||||
|
| S1 | `sdxhtgcl.com` | 2 词 | 掉词复核后做轻量恢复 |
|
||||||
|
| S1 | `sdxtwnc.com` | 2 词 | 蜘蛛首页回访干净,做掉词修复 |
|
||||||
|
| S3 | `sjzyunyang.com` | 1 词 | 深抓强,做首页词承接 |
|
||||||
|
| S3 | `jingxifa.com` | 1 词 | 深抓强,做第二批候选 |
|
||||||
|
|
||||||
|
合计:`10` 词。
|
||||||
|
|
||||||
|
### 2.2 备选域名
|
||||||
|
|
||||||
|
如果主攻域名中有站遇到 captcha、快照失败、蜘蛛断抓,则用备选补位:
|
||||||
|
|
||||||
|
| 域名 | 目标 | 使用条件 |
|
||||||
|
|---|---:|---|
|
||||||
|
| `codohealth.com` | 1-2 词 | `403/301` 压下去后补位 |
|
||||||
|
| `lgyz.net` | 1 词 | play/detail 继续存在后补位 |
|
||||||
|
| `gxhongzhuang.com` | 1 词 | 详情页干净、首页有承接后补位 |
|
||||||
|
| `vikau.com` | 1 词 | S2 收录转词恢复后补位 |
|
||||||
|
|
||||||
|
## 3. 关键词池规则
|
||||||
|
|
||||||
|
每个主攻域名锁 `4` 个关键词编号:
|
||||||
|
|
||||||
|
- `K0`:品牌/站名词,保底收口。
|
||||||
|
- `K1`:当前最接近爱站/外部反馈的主词。
|
||||||
|
- `K2`:主词同义或更长尾的辅助词。
|
||||||
|
- `K3`:分类/题材组合词。
|
||||||
|
|
||||||
|
公开文档只写编号,不写原词。
|
||||||
|
|
||||||
|
运营私表字段:
|
||||||
|
|
||||||
|
| 日期 | 域名 | K编号 | 原词 | 目标落地页 | PC状态 | 移动状态 | 页码/位置 | 备注 |
|
||||||
|
|---|---|---|---|---|---|---|---|---|
|
||||||
|
|
||||||
|
判定:
|
||||||
|
|
||||||
|
- `首页命中`:百度首页结果页出现目标域名,且 URL 是 `/` 或首页 canonical。
|
||||||
|
- `内页命中`:百度首页结果页出现分类/搜索/详情/播放页。
|
||||||
|
- `未命中`:前 1 页无目标域名。
|
||||||
|
- `captcha`:遇到验证。
|
||||||
|
- `no_result`:明确无结果。
|
||||||
|
- `empty_failed`:采集为空,不能等同无结果。
|
||||||
|
|
||||||
|
## 4. 7日执行节奏
|
||||||
|
|
||||||
|
### Day1:2026-05-01,闭环上线
|
||||||
|
|
||||||
|
目标:让外部反馈开始进入页面承接。
|
||||||
|
|
||||||
|
已完成:
|
||||||
|
|
||||||
|
1. `VideoService::getSeoCopyBlock(...)` 接入 `keyword_feedback/by_host/*.json`。
|
||||||
|
2. 首页、分类、搜索页补“近期检索方向”承接卡片。
|
||||||
|
3. 固定多源规则:当前源改代码,其它源只反馈。
|
||||||
|
|
||||||
|
当天动作:
|
||||||
|
|
||||||
|
1. 给 S1/S3 主攻域名锁 `K0-K3`。
|
||||||
|
2. 当前源清缓存或确认页面缓存刷新。
|
||||||
|
3. 用 Baiduspider UA 抽查首页、分类、搜索页是否输出反馈承接。
|
||||||
|
4. 提交或刷新 sitemap。
|
||||||
|
|
||||||
|
### Day2:2026-05-02,首页承接加密
|
||||||
|
|
||||||
|
目标:每个主攻站首页有明确、可见、非堆砌的关键词承接。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. `zbsv3.com`:保已有词,首页只做同义承接,不大改标题。
|
||||||
|
2. `sdxhtgcl.com / sdxtwnc.com`:围绕历史反馈词补首页正文和站内入口。
|
||||||
|
3. `sjzyunyang.com / jingxifa.com`:从深页回收主题到首页。
|
||||||
|
4. 每站首页至少放 `3` 个可点击入口:分类、搜索、详情/播放正样本。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- 首页 `200`。
|
||||||
|
- canonical 正确。
|
||||||
|
- 页面正文可见 `K1/K2` 语义。
|
||||||
|
- 不出现空白补料块。
|
||||||
|
|
||||||
|
### Day3:2026-05-03,内链闭环
|
||||||
|
|
||||||
|
目标:让蜘蛛从首页进入深页,再从深页回首页。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 每个主攻域名选 `3-5` 个详情/播放正样本。
|
||||||
|
2. 首页链到这些正样本。
|
||||||
|
3. 详情/播放页保持回首页、回分类、回搜索入口。
|
||||||
|
4. 检查 `detail + play` 是否继续出现。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- 主攻域名 `detail + play` 当日不断。
|
||||||
|
- `301/403/444` 不继续扩大。
|
||||||
|
|
||||||
|
### Day4:2026-05-04,异常压降
|
||||||
|
|
||||||
|
目标:减少蜘蛛预算浪费。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 优先压 `301 / 403 / 444`。
|
||||||
|
2. 重点看 `codohealth.com / lgyz.net / cnzhenbang.com`。
|
||||||
|
3. sitemap、robots、首页用 Baiduspider UA 复测。
|
||||||
|
4. 对异常站只修入口,不加词。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- 主攻域名 `403 + 444` 占比下降。
|
||||||
|
- robots / sitemap 不返回 `403 / 444`。
|
||||||
|
|
||||||
|
### Day5:2026-05-05,出词放大
|
||||||
|
|
||||||
|
目标:把已出词域名从单词扩成词组。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. `zbsv3.com` 冲 `4` 词,不改主标题,只增强承接区。
|
||||||
|
2. `sdxhtgcl.com / sdxtwnc.com` 复核是否恢复命中。
|
||||||
|
3. 对已命中的词,补同义词和搜索页入口。
|
||||||
|
4. 重新跑爱站/百度快照。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- 至少 `5` 个 K 词有首页或内页命中迹象。
|
||||||
|
- `zbsv3.com` 不掉已有词。
|
||||||
|
|
||||||
|
### Day6:2026-05-06,收录转词
|
||||||
|
|
||||||
|
目标:把深抓强站推到首页词候选。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. `sjzyunyang.com / jingxifa.com` 聚焦各 `1` 个主词。
|
||||||
|
2. `codohealth.com / lgyz.net` 作为补位。
|
||||||
|
3. 代理浏览复查百度 PC/移动。
|
||||||
|
4. 对已出现首页命中的域名补首页承接,不做大标题替换。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- 至少 `7` 个 K 词进入首页结果页或接近首页。
|
||||||
|
- 至少 `3` 个域名有有效命中。
|
||||||
|
|
||||||
|
### Day7:2026-05-07,冲刺与冻结
|
||||||
|
|
||||||
|
目标:不再大改,稳定等待结果。
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. 冻结主标题、canonical、路由。
|
||||||
|
2. 只补轻量内链和正文承接。
|
||||||
|
3. sitemap 再刷新一次。
|
||||||
|
4. 代理浏览完成最终前夜核验。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- `10` 个 K 词冲刺名单明确。
|
||||||
|
- 每个词有对应域名、落地页、承接位置。
|
||||||
|
- 异常站不参与最终统计。
|
||||||
|
|
||||||
|
## 5. 每日数据板
|
||||||
|
|
||||||
|
每天必须回填:
|
||||||
|
|
||||||
|
| 日期 | 百度首页命中词数 | 首页URL命中 | 内页命中 | 有效域名数 | 爱站PC词总数 | indexed_like | 国内蜘蛛总量 | detail+play | 403+444占比 | 判断 |
|
||||||
|
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|
|
||||||
|
|
||||||
|
最低日进度:
|
||||||
|
|
||||||
|
| 日期 | 目标累计首页词 | 说明 |
|
||||||
|
|---|---:|---|
|
||||||
|
| 2026-05-02 | 2 | 先保已有词和恢复词 |
|
||||||
|
| 2026-05-03 | 3 | 首页承接开始生效 |
|
||||||
|
| 2026-05-04 | 4 | 异常压降后补位 |
|
||||||
|
| 2026-05-05 | 6 | 出词组放大 |
|
||||||
|
| 2026-05-06 | 8 | 深抓站转词 |
|
||||||
|
| 2026-05-07 | 10 | 冲刺完成 |
|
||||||
|
|
||||||
|
## 6. 禁止动作
|
||||||
|
|
||||||
|
1. 不在其它 GPT 源单独改代码。
|
||||||
|
2. 不在老模板非测试源改代码。
|
||||||
|
3. 不批量替换 32 站主标题。
|
||||||
|
4. 不同时改标题、canonical、URL 归一。
|
||||||
|
5. 不用刷点击代替代理核验。
|
||||||
|
6. 不把 `captcha / empty_failed` 当成真实无结果。
|
||||||
|
7. 不把 30 天反馈池当作当日收录结论。
|
||||||
|
|
||||||
|
## 7. 当前优先级
|
||||||
|
|
||||||
|
第一梯队:
|
||||||
|
|
||||||
|
1. `zbsv3.com`
|
||||||
|
2. `sdxhtgcl.com`
|
||||||
|
3. `sdxtwnc.com`
|
||||||
|
|
||||||
|
第二梯队:
|
||||||
|
|
||||||
|
1. `sjzyunyang.com`
|
||||||
|
2. `jingxifa.com`
|
||||||
|
3. `codohealth.com`
|
||||||
|
4. `lgyz.net`
|
||||||
|
|
||||||
|
第三梯队:
|
||||||
|
|
||||||
|
1. `vikau.com`
|
||||||
|
2. `alarmsinstallers.com`
|
||||||
|
3. `caosheninan.com`
|
||||||
|
4. `jpjdxs.com`
|
||||||
|
5. `nblssy.com`
|
||||||
|
|
||||||
|
风险修复:
|
||||||
|
|
||||||
|
1. `cnzhenbang.com`
|
||||||
|
2. `oronorent.com`
|
||||||
|
3. `visitsumenep.com`
|
||||||
|
4. `sdtljq.com`
|
||||||
|
5. `stsgf.com`
|
||||||
|
|
||||||
|
## 8. 一句话执行令
|
||||||
|
|
||||||
|
未来 7 天所有 GPT 模板 SEO 动作只服务一个目标:
|
||||||
|
|
||||||
|
> 到 `2026-05-08` 验收时,至少 `10` 个关键词进入百度首页结果页;当前源负责试代码和固化方法,其它源只拉取与反馈。
|
||||||
124
docs/gpt-template-seo/18-GPT模板10词冲刺夜间收口执行单-2026-05-01.md
Normal file
124
docs/gpt-template-seo/18-GPT模板10词冲刺夜间收口执行单-2026-05-01.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# 18 GPT模板10词冲刺夜间收口执行单 2026-05-01
|
||||||
|
|
||||||
|
## 1. 当前时间
|
||||||
|
|
||||||
|
服务器时间:
|
||||||
|
|
||||||
|
- `2026-05-01 22:46 CST`
|
||||||
|
|
||||||
|
当前阶段:
|
||||||
|
|
||||||
|
- 7 日 10 词上首页冲刺 Day1 夜间。
|
||||||
|
- 今晚不做大改,只做确认、记录、冻结和明早验收准备。
|
||||||
|
|
||||||
|
## 2. 截至夜间蜘蛛状态
|
||||||
|
|
||||||
|
数据来源:
|
||||||
|
|
||||||
|
- `code/storage/domain-spider-crawl/runs/20260501`
|
||||||
|
- 统计口径:`baiduspider + bytespider + sogou`
|
||||||
|
|
||||||
|
### 2.1 全日截至 22:40 左右
|
||||||
|
|
||||||
|
| 指标 | 数值 |
|
||||||
|
|---|---:|
|
||||||
|
| 国内蜘蛛总量 | 475 |
|
||||||
|
| Baiduspider | 327 |
|
||||||
|
| Bytespider | 64 |
|
||||||
|
| Sogou | 84 |
|
||||||
|
| home | 273 |
|
||||||
|
| detail | 20 |
|
||||||
|
| play | 22 |
|
||||||
|
| detail + play | 42 |
|
||||||
|
| 200 | 212 |
|
||||||
|
| 301 | 151 |
|
||||||
|
| 403 | 77 |
|
||||||
|
| 444 | 26 |
|
||||||
|
|
||||||
|
判断:
|
||||||
|
|
||||||
|
1. 百度仍是主力。
|
||||||
|
2. `detail + play = 42`,深页没有断。
|
||||||
|
3. `301` 仍偏高,是今晚和明天要压的核心问题。
|
||||||
|
|
||||||
|
### 2.2 18:00 后夜间窗口
|
||||||
|
|
||||||
|
| 指标 | 数值 |
|
||||||
|
|---|---:|
|
||||||
|
| 国内蜘蛛总量 | 132 |
|
||||||
|
| Baiduspider | 112 |
|
||||||
|
| Bytespider | 10 |
|
||||||
|
| Sogou | 10 |
|
||||||
|
| home | 100 |
|
||||||
|
| detail | 12 |
|
||||||
|
| play | 0 |
|
||||||
|
| 200 | 67 |
|
||||||
|
| 301 | 50 |
|
||||||
|
| 403 | 10 |
|
||||||
|
| 444 | 5 |
|
||||||
|
|
||||||
|
夜间判断:
|
||||||
|
|
||||||
|
1. 18:00 后百度蜘蛛占比很高,这是正向信号。
|
||||||
|
2. 夜间主要抓首页,说明刚上线的承接增强有机会被重新读取。
|
||||||
|
3. `jingxifa.com` 夜间有 `detail=4`,是今晚最值得保的深页信号。
|
||||||
|
4. `sjzyunyang.com` 夜间有 `detail=4`,但 `301/403` 仍要压。
|
||||||
|
5. `play` 夜间暂未出现,明早必须看是否恢复。
|
||||||
|
|
||||||
|
## 3. 主攻域名夜间状态
|
||||||
|
|
||||||
|
| 域名 | 夜间蜘蛛 | 判断 |
|
||||||
|
|---|---:|---|
|
||||||
|
| `zbsv3.com` | 弱 | 不动标题,等明早爱站/百度核验 |
|
||||||
|
| `sdxhtgcl.com` | 弱 | 不加码,先复核掉词 |
|
||||||
|
| `sdxtwnc.com` | 全日 `home=18/200=18` | 首页回访干净,适合做掉词修复 |
|
||||||
|
| `sjzyunyang.com` | 夜间 `6`,含 `detail=4` | 深页仍在,明早补回链 |
|
||||||
|
| `jingxifa.com` | 夜间 `14`,含 `detail=4` | 今晚最佳候选之一 |
|
||||||
|
|
||||||
|
备选:
|
||||||
|
|
||||||
|
- `codohealth.com` 夜间 `11`,有首页回访,但 `301/403` 仍在。
|
||||||
|
- `gxhongzhuang.com` 夜间 `detail=4`,可作为备选观察。
|
||||||
|
- `vikau.com` 夜间 `18`,但归 S2,需要先确认收录/异常。
|
||||||
|
|
||||||
|
## 4. 今晚要做什么
|
||||||
|
|
||||||
|
### 必做
|
||||||
|
|
||||||
|
1. 冻结主标题、canonical、路由,不再做大改。
|
||||||
|
2. 保留当前 `keyword_feedback` 运行时承接逻辑。
|
||||||
|
3. 运营私表锁定主攻域名 `K0-K3`。
|
||||||
|
4. 明早优先查 `zbsv3.com / sdxtwnc.com / jingxifa.com / sjzyunyang.com`。
|
||||||
|
5. 明早看 `play` 是否恢复,尤其是 S3 域名。
|
||||||
|
|
||||||
|
### 不做
|
||||||
|
|
||||||
|
1. 今晚不批量改 32 站标题。
|
||||||
|
2. 今晚不改老模板。
|
||||||
|
3. 今晚不向其它 GPT 源同步代码。
|
||||||
|
4. 今晚不把 `captcha / empty_failed` 当作真实无结果。
|
||||||
|
5. 今晚不追大规模 sitemap 变更,只保入口稳定。
|
||||||
|
|
||||||
|
## 5. 明早第一轮验收
|
||||||
|
|
||||||
|
明早检查顺序:
|
||||||
|
|
||||||
|
1. 百度 PC:主攻域名 `K0-K3` 是否首页命中。
|
||||||
|
2. 百度移动:同一批 K 词是否首页命中。
|
||||||
|
3. 爱站:`zbsv3.com` 3 词是否保住,`sdxhtgcl.com / sdxtwnc.com` 是否恢复。
|
||||||
|
4. 蜘蛛:夜间到早晨是否继续有 `home / detail / play`。
|
||||||
|
5. 异常:`301 / 403 / 444` 是否继续偏高。
|
||||||
|
|
||||||
|
明早最低期待:
|
||||||
|
|
||||||
|
- 至少 `2` 个 K 词有首页或接近首页迹象。
|
||||||
|
- `zbsv3.com` 不掉已有词。
|
||||||
|
- `jingxifa.com / sjzyunyang.com` 继续有 detail 或 play。
|
||||||
|
|
||||||
|
## 6. 夜间结论
|
||||||
|
|
||||||
|
今晚不适合继续改大逻辑。
|
||||||
|
|
||||||
|
正确动作是:
|
||||||
|
|
||||||
|
> 保持当前闭环上线状态,冻结大改,锁 K 词,明早用百度 PC/移动、爱站、蜘蛛日志做第一轮验收。现在最重要的是别把刚起来的百度夜间回访打断。
|
||||||
170
docs/gpt-template-seo/19-GPT模板Day5蜘蛛日志与7日进度复盘-2026-05-05.md
Normal file
170
docs/gpt-template-seo/19-GPT模板Day5蜘蛛日志与7日进度复盘-2026-05-05.md
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
# 19 GPT模板 Day5 蜘蛛日志与7日进度复盘 2026-05-05
|
||||||
|
|
||||||
|
## 1. 复盘口径
|
||||||
|
|
||||||
|
当前时间:
|
||||||
|
|
||||||
|
- `2026-05-05 09:18 CST`
|
||||||
|
|
||||||
|
统计来源:
|
||||||
|
|
||||||
|
- 蜘蛛日志:`code/storage/domain-spider-crawl/runs/20260501` 到 `20260505`
|
||||||
|
- 站外快照:`seo_external_snapshot`
|
||||||
|
- 反馈池:`code/data/seo_resource/keyword_feedback/hot_keywords.latest.json`
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
1. `2026-05-05` 蜘蛛只统计到上午 `09:10` 左右,不是全日。
|
||||||
|
2. `keyword_feedback` 是 30 天反馈池;当日判断仍以 `seo_external_snapshot.metric_date = 2026-05-05` 为准。
|
||||||
|
3. 7 日冲刺目标来自 [17-GPT模板7日10词上首页冲刺目标-2026-05-01.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/17-GPT模板7日10词上首页冲刺目标-2026-05-01.md)。
|
||||||
|
|
||||||
|
## 2. 今日总判断
|
||||||
|
|
||||||
|
Day5 阶段判定:
|
||||||
|
|
||||||
|
- 蜘蛛侧:`未断,但总量偏低,上午样本不足`
|
||||||
|
- 深页侧:`S3 仍有 detail/play,尤其 codohealth/lgyz/jingxifa`
|
||||||
|
- S1 目标侧:`zbsv3 弱,sdxhtgcl 有爱站当日词,sdxtwnc 仍只有首页蜘蛛`
|
||||||
|
- 百度收录侧:`当日 indexed_like=0,不达标`
|
||||||
|
- 爱站侧:`当日 PC 词总数 3,但主目标只命中 sdxhtgcl.com`
|
||||||
|
- 7 日目标进度:`落后`
|
||||||
|
|
||||||
|
一句话:
|
||||||
|
|
||||||
|
> 到 2026-05-05 上午,10 词首页目标没有按计划跑到 Day5 应有的 6 词节奏;蜘蛛仍在抓,但有效外部词集中度不足,必须把资源从平均观察切到“sdxhtgcl 保词放大 + jingxifa/codohealth/vikau 收录转词 + zbsv3 保历史词复核”。
|
||||||
|
|
||||||
|
## 3. 蜘蛛趋势
|
||||||
|
|
||||||
|
统计口径:`baiduspider + bytespider + sogou`
|
||||||
|
|
||||||
|
| 日期 | 总量 | 百度 | home | detail | play | detail+play | 200 | 301 | 403+444 | 异常占比 | 判断 |
|
||||||
|
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|
|
||||||
|
| 2026-05-01 | 496 | 343 | 281 | 28 | 22 | 50 | 222 | 158 | 107 | 21.6% | 闭环上线后百度仍强 |
|
||||||
|
| 2026-05-02 | 367 | 198 | 122 | 49 | 40 | 89 | 124 | 133 | 110 | 30.0% | 深页最好,但异常升 |
|
||||||
|
| 2026-05-03 | 302 | 136 | 67 | 44 | 26 | 70 | 77 | 113 | 111 | 36.8% | 质量下滑,异常偏高 |
|
||||||
|
| 2026-05-04 | 323 | 195 | 139 | 32 | 24 | 56 | 143 | 89 | 89 | 27.6% | 有恢复,S3 仍在 |
|
||||||
|
| 2026-05-05 上午 | 109 | 50 | 31 | 17 | 4 | 21 | 30 | 37 | 42 | 38.5% | 样本不足,异常偏高 |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
1. 5 月 2 日深页最好,说明闭环上线后不是完全没效果。
|
||||||
|
2. 5 月 3 日和 5 月 5 日异常占比偏高,会吃蜘蛛预算。
|
||||||
|
3. 5 月 5 日上午 `detail+play=21`,深页没断,但主要在 S3 和补位站,不在 S1 头部。
|
||||||
|
4. `301` 仍长期偏高,尤其 `jingxifa / codohealth / lgyz / cnzhenbang`。
|
||||||
|
|
||||||
|
## 4. 今日重点域名
|
||||||
|
|
||||||
|
### 4.1 主攻域名
|
||||||
|
|
||||||
|
| 域名 | 今日蜘蛛 | 今日站外 | 判断 | 动作 |
|
||||||
|
|---|---:|---|---|---|
|
||||||
|
| `zbsv3.com` | 今日上午弱 | 反馈池历史 3 词;当日爱站 summary 为 0 | 已出词样板有掉出当日快照风险 | 不改主标题,立即复核历史 3 词是否仍在首页 |
|
||||||
|
| `sdxhtgcl.com` | 今日上午弱 | 当日爱站 PC 1 词 | 今天主目标里唯一明确当日出词站 | 立刻保词放大,补首页/分类/搜索承接 |
|
||||||
|
| `sdxtwnc.com` | 5月1-4 首页干净,今日上午 4 | 仅历史词,今日 summary 0 | 有首页蜘蛛,但外部词未恢复 | 继续做掉词修复,不加大标题 |
|
||||||
|
| `sjzyunyang.com` | 5月4 `play=16/detail=8`,今日上午未进前列 | 当日无词、无收录 | 深抓强,但还没转外部结果 | 保 detail/play,暂不承担新增词主力 |
|
||||||
|
| `jingxifa.com` | 今日上午 `6`,含 `detail=4` | 反馈池 `indexed_like=true`,当日 site failed | 深抓连续,适合从候选升为补位主力 | 补首页承接,压 301 |
|
||||||
|
|
||||||
|
### 4.2 补位域名
|
||||||
|
|
||||||
|
| 域名 | 今日状态 | 判断 |
|
||||||
|
|---|---|---|
|
||||||
|
| `codohealth.com` | 今日上午 `18`,含 `detail=4`,反馈池 `indexed_like=true` | 应从备选升为补位主力 |
|
||||||
|
| `lgyz.net` | 今日上午 `13`,含 `detail=5/play=4`,但 `403/301` 仍在 | 有深页,但先压异常 |
|
||||||
|
| `vikau.com` | 反馈池 `indexed_like=true`,今日上午只有 robots 且 `444` | 先修入口,不立即加码 |
|
||||||
|
| `glae.cc` | 当日爱站 2 词,但不在原主攻名单 | 可作为新增观察样本,但不能替代 GPT 主攻闭环判断 |
|
||||||
|
|
||||||
|
## 5. 站外快照进度
|
||||||
|
|
||||||
|
### 5.1 大盘
|
||||||
|
|
||||||
|
| 日期 | 百度 indexed_like | 百度 failed | 百度 unknown | 爱站出词域名 | 爱站 PC 词总数 |
|
||||||
|
|---|---:|---:|---:|---:|---:|
|
||||||
|
| 2026-05-01 | 0 | 30 | 2 | 1 | 3 |
|
||||||
|
| 2026-05-02 | 0 | 28 | 4 | 2 | 3 |
|
||||||
|
| 2026-05-03 | 2 | 23 | 7 | 2 | 3 |
|
||||||
|
| 2026-05-04 | 3 | 12 | 17 | 2 | 3 |
|
||||||
|
| 2026-05-05 | 0 | 26 | 6 | 2 | 3 |
|
||||||
|
|
||||||
|
判断:
|
||||||
|
|
||||||
|
1. 5 月 4 日出现过 `codohealth.com / glae.cc / jingxifa.com` 的 `indexed_like`,但 5 月 5 日没有延续。
|
||||||
|
2. 5 月 5 日 unknown 多数是 captcha,不能算真实无结果。
|
||||||
|
3. 爱站 PC 词总数 5 天一直是 `3`,没有达到 Day5 应有放大。
|
||||||
|
4. 5 月 5 日当日出词站是 `glae.cc=2`、`sdxhtgcl.com=1`;原主攻里只有 `sdxhtgcl.com` 当日有词。
|
||||||
|
|
||||||
|
### 5.2 与 10 词目标对比
|
||||||
|
|
||||||
|
7 日计划最低日进度:
|
||||||
|
|
||||||
|
- 2026-05-05 应累计 `6` 个首页词。
|
||||||
|
|
||||||
|
当前可确认:
|
||||||
|
|
||||||
|
- 当日爱站 PC 词总数:`3`
|
||||||
|
- 原主攻域名当日明确词:`sdxhtgcl.com=1`
|
||||||
|
- `zbsv3.com` 反馈池仍有 3 历史词,但当日 summary 为 0,必须复核
|
||||||
|
- 百度当日 `indexed_like=0`
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
> Day5 进度落后,不能再按原计划平均推进;必须把 5 月 5 日变成“保词与补位重排日”。
|
||||||
|
|
||||||
|
## 6. 今天必须调整的策略
|
||||||
|
|
||||||
|
### 6.1 资源重排
|
||||||
|
|
||||||
|
第一优先级:
|
||||||
|
|
||||||
|
1. `sdxhtgcl.com`
|
||||||
|
- 当日有爱站词。
|
||||||
|
- 目标从 `2` 词不变。
|
||||||
|
- 今日只做承接增强,不换主标题。
|
||||||
|
|
||||||
|
2. `zbsv3.com`
|
||||||
|
- 历史 3 词必须复核。
|
||||||
|
- 若百度/爱站确认掉词,立即降为“保词修复”,不再冲 4 词。
|
||||||
|
|
||||||
|
3. `jingxifa.com`
|
||||||
|
- 连续深抓,5 月 4 日有 `indexed_like`。
|
||||||
|
- 升为补位主力,目标 `1` 词。
|
||||||
|
|
||||||
|
4. `codohealth.com`
|
||||||
|
- 5 月 4 日有 `indexed_like`,今日仍有 detail。
|
||||||
|
- 升为补位主力,目标 `1` 词。
|
||||||
|
|
||||||
|
第二优先级:
|
||||||
|
|
||||||
|
- `lgyz.net`:保 detail/play,先压异常。
|
||||||
|
- `sdxtwnc.com`:继续恢复历史词。
|
||||||
|
- `sjzyunyang.com`:保深页,不再强压首页词。
|
||||||
|
|
||||||
|
### 6.2 今日动作
|
||||||
|
|
||||||
|
1. 复核 `zbsv3.com` 历史 3 个 K 词是否仍在百度首页。
|
||||||
|
2. 围绕 `sdxhtgcl.com` 当日爱站词补首页、分类、搜索三处承接。
|
||||||
|
3. 给 `jingxifa.com / codohealth.com` 各锁 `1` 个首页主词,补首页承接。
|
||||||
|
4. 处理 `lgyz.net / codohealth.com / jingxifa.com` 的 `301`。
|
||||||
|
5. `cnzhenbang.com` 今日不参与冲词,只修异常。
|
||||||
|
|
||||||
|
### 6.3 今天不做
|
||||||
|
|
||||||
|
1. 不批量改 32 站标题。
|
||||||
|
2. 不把 `glae.cc` 的 2 词直接算进原 10 词主攻目标,除非决定正式补位。
|
||||||
|
3. 不把 30 天反馈池里的 `indexed_like=true` 当作当日收录。
|
||||||
|
4. 不在其它 GPT 源单独试代码。
|
||||||
|
|
||||||
|
## 7. 今日结论
|
||||||
|
|
||||||
|
今天不是放大顺风局,是中段纠偏日。
|
||||||
|
|
||||||
|
当前最准确判断:
|
||||||
|
|
||||||
|
- 蜘蛛没有断。
|
||||||
|
- 深页还有生命力。
|
||||||
|
- 爱站有小信号,但主攻目标没有拉开。
|
||||||
|
- 百度 site 当日不达标。
|
||||||
|
- 10 词首页目标截至 Day5 已落后。
|
||||||
|
|
||||||
|
下一步要从“原主攻名单固定推进”改为:
|
||||||
|
|
||||||
|
> `sdxhtgcl.com` 保词放大,`zbsv3.com` 复核保词,`jingxifa.com / codohealth.com` 升为补位主力,`lgyz.net` 保深抓压异常,`cnzhenbang.com` 只修不冲。
|
||||||
184
docs/gpt-template-seo/20-GPT模板7日目标验收与蜘蛛日志复盘-2026-05-09.md
Normal file
184
docs/gpt-template-seo/20-GPT模板7日目标验收与蜘蛛日志复盘-2026-05-09.md
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
# 20 GPT模板 7日目标验收与蜘蛛日志复盘 2026-05-09
|
||||||
|
|
||||||
|
## 1. 复盘口径
|
||||||
|
|
||||||
|
当前时间:
|
||||||
|
|
||||||
|
- `2026-05-09 09:56 CST`
|
||||||
|
|
||||||
|
统计来源:
|
||||||
|
|
||||||
|
- 蜘蛛日志:`code/storage/domain-spider-crawl/runs/20260501` 到 `20260509`
|
||||||
|
- 最新蜘蛛摘要:`code/storage/domain-spider-crawl/latest/spider-crawl.summary.json`
|
||||||
|
- 站外快照:`seo_external_snapshot`
|
||||||
|
- 反馈池:`code/data/seo_resource/keyword_feedback/hot_keywords.latest.json`
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
1. `2026-05-09` 蜘蛛只统计到上午 `09:50` 左右,不是全日。
|
||||||
|
2. `keyword_feedback` 是 30 天反馈池,会保留历史爱站词和历史收录信号。
|
||||||
|
3. 7 日 10 词目标的验收必须以 `seo_external_snapshot` 当日/近两日快照为准,不能把 30 天历史池直接算作当日首页词。
|
||||||
|
|
||||||
|
## 2. 今日总判断
|
||||||
|
|
||||||
|
7 日目标验收判定:
|
||||||
|
|
||||||
|
- 蜘蛛侧:`5月8日明显恢复,5月9日上午仍有抓取`
|
||||||
|
- 百度收录侧:`5月8日 indexed_like=6,5月9日 indexed_like=5,收录面比 Day5 好`
|
||||||
|
- 爱站首页词侧:`5月8日和5月9日当日 PC 词为 0`
|
||||||
|
- 反馈池侧:`仍保留 8 个历史爱站关键词,集中在 zbsv3/glae/sdxhtgcl/sdxtwnc`
|
||||||
|
- 目标结果:`7日10词上首页未达标`
|
||||||
|
|
||||||
|
一句话:
|
||||||
|
|
||||||
|
> 这 7 天不是完全没效果,蜘蛛和收录信号在 5 月 8 日有明显回升;但首页词没有完成放大,爱站当日词从 5 月 8 日开始归零,说明“收录转首页词”的最后一段没有跑通。
|
||||||
|
|
||||||
|
## 3. 蜘蛛趋势
|
||||||
|
|
||||||
|
统计口径:`baiduspider + bytespider + sogou`,不把 Googlebot 的 robots/444 噪声计入主判断。
|
||||||
|
|
||||||
|
| 日期 | 总量 | 百度 | Byte | Sogou | home | category | detail | play | robots | 200 | 301 | 403 | 444 | 域名数 | 判断 |
|
||||||
|
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|
|
||||||
|
| 2026-05-01 | 496 | 343 | 67 | 86 | 281 | 42 | 28 | 22 | 66 | 222 | 158 | 78 | 29 | 26 | Day1 百度强,首页为主 |
|
||||||
|
| 2026-05-02 | 367 | 198 | 70 | 99 | 122 | 56 | 49 | 40 | 74 | 124 | 133 | 84 | 26 | 25 | 深页最好 |
|
||||||
|
| 2026-05-03 | 302 | 136 | 83 | 83 | 67 | 48 | 44 | 26 | 69 | 77 | 113 | 76 | 35 | 24 | 异常偏高 |
|
||||||
|
| 2026-05-04 | 323 | 195 | 68 | 60 | 139 | 34 | 32 | 24 | 65 | 143 | 89 | 63 | 26 | 25 | 有恢复 |
|
||||||
|
| 2026-05-05 | 371 | 187 | 65 | 119 | 128 | 74 | 29 | 27 | 60 | 132 | 110 | 92 | 35 | 24 | Sogou/分类补量 |
|
||||||
|
| 2026-05-06 | 263 | 147 | 79 | 37 | 84 | 24 | 41 | 26 | 64 | 102 | 77 | 57 | 27 | 21 | 总量回落,深页尚可 |
|
||||||
|
| 2026-05-07 | 285 | 180 | 62 | 43 | 118 | 26 | 32 | 28 | 58 | 135 | 70 | 49 | 30 | 23 | 平稳但无放大 |
|
||||||
|
| 2026-05-08 | 626 | 470 | 80 | 76 | 406 | 46 | 40 | 22 | 85 | 393 | 128 | 78 | 27 | 23 | 明显恢复,百度大幅回访 |
|
||||||
|
| 2026-05-09 上午 | 229 | 162 | 35 | 32 | 123 | 16 | 27 | 13 | 34 | 103 | 75 | 34 | 16 | 23 | 上午仍有抓取 |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
1. 蜘蛛没有断,5 月 8 日是本轮最高点,百度抓取从 5 月 7 日 `180` 升到 5 月 8 日 `470`。
|
||||||
|
2. 深页抓取一直存在,但 `detail+play` 没有形成持续放大,5 月 8 日为 `62`,5 月 9 日上午为 `40`。
|
||||||
|
3. `301` 仍偏高,5 月 8 日 `128`,5 月 9 日上午 `75`,会继续消耗蜘蛛预算。
|
||||||
|
4. 5 月 9 日上午主抓集中在 `jingxifa/glae/sdxtwnc/vikau/codohealth/sjzyunyang`,不是原先所有 S1 主攻站同步起量。
|
||||||
|
|
||||||
|
## 4. 今日重点域名
|
||||||
|
|
||||||
|
### 4.1 2026-05-09 上午蜘蛛
|
||||||
|
|
||||||
|
| 域名 | 总量 | 百度 | home | detail | play | 200 | 301 | 403/444 | 判断 |
|
||||||
|
|---|---:|---:|---:|---:|---:|---:|---:|---:|---|
|
||||||
|
| `jingxifa.com` | 26 | 26 | 18 | 0 | 8 | 16 | 10 | 0 | 百度抓取最强,可继续做补位 |
|
||||||
|
| `glae.cc` | 20 | 20 | 20 | 0 | 0 | 14 | 6 | 0 | 有词、有收录、有首页抓取 |
|
||||||
|
| `sdxtwnc.com` | 18 | 18 | 18 | 0 | 0 | 12 | 6 | 0 | 首页回访稳定,但词未恢复 |
|
||||||
|
| `codohealth.com` | 19 | 17 | 0 | 9 | 0 | 8 | 9 | 2 | 有深页,但 301 偏高 |
|
||||||
|
| `vikau.com` | 20 | 8 | 1 | 10 | 5 | 4 | 4 | 12 | 深页有,异常也重 |
|
||||||
|
| `sjzyunyang.com` | 8 | 8 | 0 | 8 | 0 | 4 | 4 | 0 | 保深页观察 |
|
||||||
|
| `cnzhenbang.com` | 22 | 0 | 2 | 0 | 0 | 0 | 10 | 12 | 不适合冲词,只修异常 |
|
||||||
|
|
||||||
|
### 4.2 主攻与补位判断
|
||||||
|
|
||||||
|
| 域名 | 站外快照 2026-05-09 | 反馈池 | 判断 | 动作 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `zbsv3.com` | 百度 unknown,爱站 summary 0 | 历史 3 词 | 历史词未形成当日延续 | 只做保词复核,不再按 4 词目标加码 |
|
||||||
|
| `sdxhtgcl.com` | 百度 unknown,爱站 summary 0 | 历史 1 词 | 5月3-5有词,5月8-9断 | 保留承接,先查为什么当日词归零 |
|
||||||
|
| `sdxtwnc.com` | 百度 unknown,爱站 summary 0 | 历史 1 词 | 有首页蜘蛛,无当日词 | 做掉词修复,不大改标题 |
|
||||||
|
| `jingxifa.com` | 百度 failed | 历史 indexed_like | 蜘蛛强但收录快照没跟上 | 保补位,压 301 |
|
||||||
|
| `codohealth.com` | 百度 unknown | 历史 indexed_like | 深页仍有抓取 | 保补位,压 301 |
|
||||||
|
| `glae.cc` | 百度 indexed_like,爱站 summary 0 | 历史 2 词 | 本轮最稳定样本,但不是原主攻 | 可正式纳入补位目标 |
|
||||||
|
| `jxxgygy.com` | 百度 indexed_like | 历史 indexed_like | 5月8-9收录连续 | 新增观察,暂不算首页词 |
|
||||||
|
|
||||||
|
## 5. 站外快照进度
|
||||||
|
|
||||||
|
### 5.1 大盘
|
||||||
|
|
||||||
|
| 日期 | 百度 indexed_like | 百度 failed | 百度 unknown | 爱站出词域名 | 爱站 PC 词总数 |
|
||||||
|
|---|---:|---:|---:|---:|---:|
|
||||||
|
| 2026-05-01 | 0 | 30 | 2 | 1 | 3 |
|
||||||
|
| 2026-05-02 | 0 | 28 | 4 | 2 | 3 |
|
||||||
|
| 2026-05-03 | 2 | 23 | 7 | 2 | 3 |
|
||||||
|
| 2026-05-04 | 3 | 12 | 17 | 2 | 3 |
|
||||||
|
| 2026-05-05 | 0 | 26 | 6 | 2 | 3 |
|
||||||
|
| 2026-05-06 | 1 | 28 | 3 | 1 | 2 |
|
||||||
|
| 2026-05-07 | 3 | 14 | 15 | 1 | 2 |
|
||||||
|
| 2026-05-08 | 6 | 7 | 19 | 0 | 0 |
|
||||||
|
| 2026-05-09 | 5 | 4 | 23 | 0 | 0 |
|
||||||
|
|
||||||
|
判断:
|
||||||
|
|
||||||
|
1. 百度收录侧变好:5 月 8 日和 5 月 9 日分别有 `6/5` 个 `indexed_like`。
|
||||||
|
2. 爱站首页词侧变差:5 月 8 日、5 月 9 日当日 `pc_keyword_count=0`。
|
||||||
|
3. 这说明当前不是“蜘蛛没来”,而是“页面进入检索结果后,没有稳定转成爱站可见首页词”。
|
||||||
|
|
||||||
|
### 5.2 爱站关键词验收
|
||||||
|
|
||||||
|
当日 `aizhan_keyword` 记录:
|
||||||
|
|
||||||
|
| 日期 | 域名 | PC 词数 |
|
||||||
|
|---|---|---:|
|
||||||
|
| 2026-05-01 | `zbsv3.com` | 3 |
|
||||||
|
| 2026-05-02 | `glae.cc` | 2 |
|
||||||
|
| 2026-05-02 | `zbsv3.com` | 1 |
|
||||||
|
| 2026-05-03 | `glae.cc` | 2 |
|
||||||
|
| 2026-05-03 | `sdxhtgcl.com` | 1 |
|
||||||
|
| 2026-05-04 | `glae.cc` | 2 |
|
||||||
|
| 2026-05-04 | `sdxhtgcl.com` | 1 |
|
||||||
|
| 2026-05-05 | `glae.cc` | 2 |
|
||||||
|
| 2026-05-05 | `sdxhtgcl.com` | 1 |
|
||||||
|
| 2026-05-06 | `glae.cc` | 2 |
|
||||||
|
| 2026-05-07 | `glae.cc` | 2 |
|
||||||
|
| 2026-05-08 | 无 | 0 |
|
||||||
|
| 2026-05-09 | 无 | 0 |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
> 7 日目标要求至少 10 个关键词上首页;按当日快照验收,最高稳定可见只有 `3`,5 月 8 日和 5 月 9 日为 `0`,目标未达标。
|
||||||
|
|
||||||
|
## 6. 真实效果拆解
|
||||||
|
|
||||||
|
有效的部分:
|
||||||
|
|
||||||
|
1. 蜘蛛回访被拉起来了,尤其 5 月 8 日百度抓取达到 `470`。
|
||||||
|
2. 百度 indexed_like 从 Day5 的 `0` 回升到 5 月 8 日 `6`、5 月 9 日 `5`。
|
||||||
|
3. `glae.cc / jxxgygy.com / chuanjiafeng.net / sdtljq.com / leici1940.com` 等站出现当前收录信号。
|
||||||
|
|
||||||
|
无效或不足的部分:
|
||||||
|
|
||||||
|
1. 原主攻站 `zbsv3/sdxhtgcl/sdxtwnc` 没有把历史词维持成当日词。
|
||||||
|
2. `jingxifa/codohealth/vikau` 有蜘蛛或历史收录,但没有稳定产出爱站首页词。
|
||||||
|
3. `301/403/444` 仍偏高,尤其 `cnzhenbang/vikau/codohealth/jingxifa`,影响抓取质量。
|
||||||
|
4. GPT 引导文案、AI 承接、关键词反馈闭环已经接入,但目前更像提升了抓取和收录,不足以直接把词推到首页。
|
||||||
|
|
||||||
|
## 7. 今天必须调整的策略
|
||||||
|
|
||||||
|
### 7.1 目标调整
|
||||||
|
|
||||||
|
从今天开始,不再喊“大盘 10 词平均推进”,改成两层目标:
|
||||||
|
|
||||||
|
1. 保历史词:`zbsv3.com` 3 个历史词、`sdxhtgcl.com` 1 个历史词、`sdxtwnc.com` 1 个历史词,先确认是否真实还在首页。
|
||||||
|
2. 收录转词:把 `glae.cc / jxxgygy.com / jingxifa.com / codohealth.com` 作为补位,目标先做 `3` 个稳定可见词。
|
||||||
|
|
||||||
|
### 7.2 今日动作
|
||||||
|
|
||||||
|
1. `glae.cc` 正式纳入补位主力,因为它同时有历史词和 5 月 9 日百度 `indexed_like`。
|
||||||
|
2. `jxxgygy.com` 进入新观察主力,因为 5 月 8 日、5 月 9 日连续 `indexed_like`,且 5 月 8 日蜘蛛强。
|
||||||
|
3. `jingxifa.com` 保留补位,但重点不是继续加文案,而是压 `301`,今天上午 `301=10`。
|
||||||
|
4. `codohealth.com` 保 detail 深页,先处理 `301=9`,否则深页蜘蛛会被浪费。
|
||||||
|
5. `vikau.com` 暂停冲词,先处理异常,今天上午 `403/444=12`。
|
||||||
|
6. `cnzhenbang.com` 不参与冲词,只修 `301/403`。
|
||||||
|
|
||||||
|
### 7.3 今天不做
|
||||||
|
|
||||||
|
1. 不在其它 GPT 源单独改代码。
|
||||||
|
2. 不把反馈池历史词直接算作今日达标。
|
||||||
|
3. 不批量换标题。
|
||||||
|
4. 不继续扩大域名池,先把已出收录信号的站压实。
|
||||||
|
|
||||||
|
## 8. 今日结论
|
||||||
|
|
||||||
|
这轮 7 日冲刺没有完成“10 个关键词上首页”的硬目标。
|
||||||
|
|
||||||
|
但项目不是完全失败,真实进展是:
|
||||||
|
|
||||||
|
- 蜘蛛恢复了。
|
||||||
|
- 百度收录面扩大了。
|
||||||
|
- 反馈闭环开始起作用。
|
||||||
|
- 首页词承接能力不足,需要从“引蜘蛛/促收录”切到“保词/转词/降异常”。
|
||||||
|
|
||||||
|
下一阶段优先级:
|
||||||
|
|
||||||
|
> `glae.cc + jxxgygy.com` 做新增补位,`zbsv3.com + sdxhtgcl.com + sdxtwnc.com` 做历史词复核和保词,`jingxifa.com + codohealth.com` 做深页转词,`vikau.com + cnzhenbang.com` 先修异常。
|
||||||
162
docs/gpt-template-seo/21-GPT模板7日后续执行单-2026-05-09.md
Normal file
162
docs/gpt-template-seo/21-GPT模板7日后续执行单-2026-05-09.md
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
# 21 GPT模板 7日后续执行单 2026-05-09
|
||||||
|
|
||||||
|
## 1. 执行背景
|
||||||
|
|
||||||
|
上一份复盘已经确认:
|
||||||
|
|
||||||
|
- 7 日 10 词首页目标未达标。
|
||||||
|
- 蜘蛛和百度收录信号在 `2026-05-08` 开始恢复。
|
||||||
|
- 爱站当日首页词在 `2026-05-08`、`2026-05-09` 为 `0`。
|
||||||
|
- 下一阶段不能继续平均推进,要改成 `保历史词 + 收录转词 + 降异常`。
|
||||||
|
|
||||||
|
本执行单只针对当前 GPT 主测试源,不在其它 GPT 源单独改代码。
|
||||||
|
|
||||||
|
## 2. 异常定位
|
||||||
|
|
||||||
|
### 2.1 301 判断
|
||||||
|
|
||||||
|
用 Baiduspider UA 复查重点域名 HTTP 头:
|
||||||
|
|
||||||
|
| 域名/页面 | 当前链路 | 判断 |
|
||||||
|
|---|---|---|
|
||||||
|
| `glae.cc/` | `http -> https -> 200` | 正常 canonical 跳转,但日志会记 301 |
|
||||||
|
| `sdxtwnc.com/` | `http -> https -> 200` | 正常 canonical 跳转 |
|
||||||
|
| `jingxifa.com/` | `http -> https -> 200` | 正常 canonical 跳转 |
|
||||||
|
| `codohealth.com/` | `http -> https -> 200` | 正常 canonical 跳转 |
|
||||||
|
| `vikau.com/` | `http -> https -> 200` | 正常 canonical 跳转 |
|
||||||
|
| `zbsv3.com/` | `http -> https -> 200` | 正常 canonical 跳转 |
|
||||||
|
| `codohealth.com/voddetail/...` | `http -> https -> 200` | detail 301 主要来自旧 http URL |
|
||||||
|
| `jingxifa.com/video-bofang/...` | `http -> https -> 200` | play 301 主要来自旧 http URL |
|
||||||
|
| `vikau.com/voddetail/...` | `http -> https -> 200` | detail 301 主要来自旧 http URL |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
> 重点站的 301 不是应用死循环,主要是蜘蛛还在抓历史 `http` 地址。处理方向不是取消 301,而是把站内入口、sitemap、推送 URL、页面 canonical 全部压到 `https`。
|
||||||
|
|
||||||
|
### 2.2 robots 判断
|
||||||
|
|
||||||
|
重点站 `robots.txt` 当前均可通过 HTTPS 访问,且都包含:
|
||||||
|
|
||||||
|
- `User-agent: Baiduspider`
|
||||||
|
- `Allow: /`
|
||||||
|
- `Sitemap: https://{host}/sitemap_index.xml`
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
> Baidu robots 没挡。日志里大量 `googlebot/bingbot robots 444` 是噪声,不作为百度 SEO 主问题;但 `vikau/cnzhenbang` 的 Sogou/Bytespider 403/444 仍要降。
|
||||||
|
|
||||||
|
## 3. 今日优先级
|
||||||
|
|
||||||
|
### 3.1 P0 保词复核
|
||||||
|
|
||||||
|
目标:确认历史词是不是真还在首页,避免反馈池误导。
|
||||||
|
|
||||||
|
| 域名 | 反馈池状态 | 今日动作 | 结果口径 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `zbsv3.com` | 历史 3 词 | 逐个复核百度首页是否仍在 | 还在则保词,不在则降级 |
|
||||||
|
| `sdxhtgcl.com` | 历史 1 词,5月3-5有当日词 | 复核该词是否掉出 | 掉出则只做恢复,不扩词 |
|
||||||
|
| `sdxtwnc.com` | 历史 1 词 | 复核是否仍有首页位置 | 无则做掉词修复 |
|
||||||
|
|
||||||
|
执行要求:
|
||||||
|
|
||||||
|
1. 不改主标题。
|
||||||
|
2. 不扩新词。
|
||||||
|
3. 只补该词的首页、分类、搜索承接。
|
||||||
|
|
||||||
|
### 3.2 P1 收录转词
|
||||||
|
|
||||||
|
目标:从已有收录信号里挑最可能转词的站。
|
||||||
|
|
||||||
|
| 域名 | 依据 | 今日动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| `glae.cc` | 5月9日 `indexed_like`,反馈池历史 2 词,上午百度 home 20 | 正式纳入补位主力,做 2 词保留与承接 |
|
||||||
|
| `jxxgygy.com` | 5月8/9 连续 `indexed_like`,5月8蜘蛛强 | 作为新补位站,先做 1 个首页词承接 |
|
||||||
|
| `jingxifa.com` | 上午百度抓取 26,含 play 8 | 保留补位,先压首页/play 的 http 入口 |
|
||||||
|
| `codohealth.com` | 上午 detail 9,历史收录信号 | 保 detail 转词,压 detail 旧 http 入口 |
|
||||||
|
|
||||||
|
执行要求:
|
||||||
|
|
||||||
|
1. `glae.cc` 不再只作为观察样本,可纳入下一轮目标。
|
||||||
|
2. `jxxgygy.com` 先做 1 词,不扩成多词。
|
||||||
|
3. `jingxifa/codohealth` 先保深页质量,不盲目换首页词。
|
||||||
|
|
||||||
|
### 3.3 P2 降异常
|
||||||
|
|
||||||
|
目标:降低蜘蛛预算浪费。
|
||||||
|
|
||||||
|
| 域名 | 今日异常 | 动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| `vikau.com` | 上午 `403/444=12`,detail/play 有抓取 | 暂停冲词,先修 Sogou/Bytespider 403 和异常入口 |
|
||||||
|
| `cnzhenbang.com` | 上午 `301=10`、`403/444=12`,百度为 0 | 不参与冲词,只修分类/首页/robots 异常 |
|
||||||
|
| `codohealth.com` | detail 和 play 同时 200/301 | 统一站内 detail/play 链接为 HTTPS |
|
||||||
|
| `jingxifa.com` | 首页/play 同时 200/301 | 统一站内首页/play 链接为 HTTPS |
|
||||||
|
|
||||||
|
## 4. 今天具体动作
|
||||||
|
|
||||||
|
### 4.1 URL 入口统一
|
||||||
|
|
||||||
|
必须检查:
|
||||||
|
|
||||||
|
1. sitemap 里是否全是 `https://`。
|
||||||
|
2. 首页、分类页、detail、play 的内部链接是否全是 `https://` 或相对路径。
|
||||||
|
3. 百度推送队列是否还在推 `http://`。
|
||||||
|
4. canonical 是否输出 HTTPS。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- 新一轮日志里重点域名 Baidu 的 `301` 占比下降。
|
||||||
|
- `glae/sdxtwnc/jingxifa/codohealth` 首页和深页保持 `200`。
|
||||||
|
|
||||||
|
### 4.2 承接页处理
|
||||||
|
|
||||||
|
P0/P1 域名只做承接,不做大改:
|
||||||
|
|
||||||
|
1. 首页:保留主词相关的自然文案。
|
||||||
|
2. 分类页:加与主词匹配的聚合入口。
|
||||||
|
3. 搜索页:把历史词和补位词变成可访问搜索结果。
|
||||||
|
4. detail/play:用真实影片标题和相关推荐承接,不堆词。
|
||||||
|
|
||||||
|
验收:
|
||||||
|
|
||||||
|
- 蜘蛛继续抓 `home + detail/play`。
|
||||||
|
- 当日/次日 `aizhan_summary` 恢复到 `pc_keyword_count>0`。
|
||||||
|
|
||||||
|
### 4.3 域名池收缩
|
||||||
|
|
||||||
|
今天不要继续扩域名池。
|
||||||
|
|
||||||
|
保留主线:
|
||||||
|
|
||||||
|
- 保历史词:`zbsv3.com / sdxhtgcl.com / sdxtwnc.com`
|
||||||
|
- 收录转词:`glae.cc / jxxgygy.com / jingxifa.com / codohealth.com`
|
||||||
|
- 修异常:`vikau.com / cnzhenbang.com`
|
||||||
|
|
||||||
|
其它站只观察,不加资源。
|
||||||
|
|
||||||
|
## 5. 明天验收点
|
||||||
|
|
||||||
|
明天看三件事:
|
||||||
|
|
||||||
|
1. `2026-05-10` 百度蜘蛛是否继续维持 `300+`,重点看 `glae/jxxgygy/jingxifa/codohealth`。
|
||||||
|
2. 爱站 `pc_keyword_count` 是否从 `0` 恢复到至少 `2`。
|
||||||
|
3. `301/403/444` 是否下降,尤其 `vikau/cnzhenbang/codohealth/jingxifa`。
|
||||||
|
|
||||||
|
通过线:
|
||||||
|
|
||||||
|
- 百度 `indexed_like >= 5`
|
||||||
|
- 爱站 PC 词 `>= 2`
|
||||||
|
- 重点站 Baidu `301` 比今天下降
|
||||||
|
|
||||||
|
失败线:
|
||||||
|
|
||||||
|
- 百度回访仍有,但爱站 PC 词继续 `0`
|
||||||
|
- `glae.cc` 历史 2 词继续不回
|
||||||
|
- `vikau/cnzhenbang` 异常不降
|
||||||
|
|
||||||
|
## 6. 当前结论
|
||||||
|
|
||||||
|
今天继续推进的核心不是再加一轮“AI 文案”,而是把已恢复的蜘蛛和收录信号变成稳定词。
|
||||||
|
|
||||||
|
执行顺序:
|
||||||
|
|
||||||
|
> 先复核历史词,再保 `glae/jxxgygy` 补位,随后修 `jingxifa/codohealth` 的旧入口 301,最后把 `vikau/cnzhenbang` 从冲词池里拿出来专门降异常。
|
||||||
146
docs/gpt-template-seo/22-GPT模板Sitemap与百度推送URL规范化修正-2026-05-09.md
Normal file
146
docs/gpt-template-seo/22-GPT模板Sitemap与百度推送URL规范化修正-2026-05-09.md
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
# 22 GPT模板 Sitemap 与百度推送 URL 规范化修正 2026-05-09
|
||||||
|
|
||||||
|
## 1. 背景
|
||||||
|
|
||||||
|
7 日验收后继续排查 `301`,发现重点域名的 HTTP 头链路是:
|
||||||
|
|
||||||
|
- `http://domain/ -> https://domain/ -> 200`
|
||||||
|
- `http://domain/detail -> https://domain/detail -> 200`
|
||||||
|
|
||||||
|
这说明 `301` 不是应用死循环,而是蜘蛛还在抓旧 HTTP 或旧入口。
|
||||||
|
|
||||||
|
继续核查代码和生成产物后,发现更关键的问题:
|
||||||
|
|
||||||
|
1. `robots.txt` 指向 `https://domain/sitemap_index.xml`
|
||||||
|
2. 页面 canonical 多数指向 `https://domain/...`
|
||||||
|
3. 但 sitemap 模板、生成逻辑、百度推送逻辑里仍有 `https://www.domain/...`
|
||||||
|
|
||||||
|
这会造成 `domain` 与 `www.domain` 两套规范 URL 并存,削弱收录和首页词承接。
|
||||||
|
|
||||||
|
## 2. 本次代码修正
|
||||||
|
|
||||||
|
只在当前 GPT 主测试源修改,不改其它 GPT 源,也不动老模板。
|
||||||
|
|
||||||
|
### 2.1 动态 sitemap 输出
|
||||||
|
|
||||||
|
修改:
|
||||||
|
|
||||||
|
- `code/app/services/SiteContext.php`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
- `/rss/so.xml` 动态兼容输出从 `https://www.{host}` 改为 `https://{host}`。
|
||||||
|
|
||||||
|
### 2.2 GPT 模板 sitemap 文件
|
||||||
|
|
||||||
|
修改:
|
||||||
|
|
||||||
|
- `code/app/home/view/videoGpt1/rss/so.xml`
|
||||||
|
- `code/app/home/view/videoGpt1/sitemap/sitemap_index.xml`
|
||||||
|
- `code/app/home/view/videoGpt1/sitemap/sitemap-main.xml`
|
||||||
|
- `code/app/home/view/videoGpt1/sitemap/sitemap-books.xml`
|
||||||
|
- `code/app/home/view/videoGpt1/sitemap/sitemap-books-catalog.xml`
|
||||||
|
- `code/app/home/view/videoGpt1/sitemap/sitemap-chapters.xml`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
- sitemap 内所有站点 URL 从 `https://www.{$DomainModel->d_domain}` 改成 `https://{$DomainModel->d_domain}`。
|
||||||
|
|
||||||
|
### 2.3 后台 sitemap 生成逻辑
|
||||||
|
|
||||||
|
修改:
|
||||||
|
|
||||||
|
- `code/app/task/logic/VideoSiteMapLogic.php`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
1. `sitemap_index.xml` 生成改为 `https://domain/...`
|
||||||
|
2. `sitemap-main.xml` 生成改为 `https://domain/...`
|
||||||
|
3. `sitemap-videos-*.xml` 生成改为 `https://domain/...`
|
||||||
|
4. `sitemap-videos-*.txt` 生成改为 `https://domain/...`
|
||||||
|
5. `video-list-*.json` 的 `href` 改为 `https://domain/...`
|
||||||
|
6. 修复 `sitemap-videos-*.txt` 追加写入问题:每次生成前先清空 txt,避免旧 `https://www.domain/...` 残留。
|
||||||
|
|
||||||
|
### 2.4 百度主动推送
|
||||||
|
|
||||||
|
修改:
|
||||||
|
|
||||||
|
- `code/app/task/logic/BaiduPushVideoUrlLogic.php`
|
||||||
|
|
||||||
|
动作:
|
||||||
|
|
||||||
|
- 百度推送 API 的 `site=` 从 `https://www.domain` 改为 `https://domain`。
|
||||||
|
|
||||||
|
## 3. 已刷新运行产物
|
||||||
|
|
||||||
|
已重生成以下重点域名的 `code/storage/SiteMap/{domain}`:
|
||||||
|
|
||||||
|
- `zbsv3.com`
|
||||||
|
- `sdxhtgcl.com`
|
||||||
|
- `sdxtwnc.com`
|
||||||
|
- `glae.cc`
|
||||||
|
- `jxxgygy.com`
|
||||||
|
- `jingxifa.com`
|
||||||
|
- `codohealth.com`
|
||||||
|
- `vikau.com`
|
||||||
|
- `cnzhenbang.com`
|
||||||
|
|
||||||
|
抽查结果:
|
||||||
|
|
||||||
|
- `sitemap_index.xml` 输出 `https://domain/sitemap-main.xml`
|
||||||
|
- `sitemap-main.xml` 输出 `https://domain/`
|
||||||
|
- `sitemap-videos-1.txt` 输出 `https://domain/...`
|
||||||
|
- `video-list-1.json` 的 `href` 输出 `https://domain/...`
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
> 抽查命令里仍会看到 `http://www.sitemaps.org/schemas/sitemap/0.9`,这是 XML 命名空间,不是站点 URL,不影响 canonical 判断。
|
||||||
|
|
||||||
|
## 4. 验证
|
||||||
|
|
||||||
|
已执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -l code/app/services/SiteContext.php
|
||||||
|
php -l code/app/task/logic/VideoSiteMapLogic.php
|
||||||
|
php -l code/app/task/logic/BaiduPushVideoUrlLogic.php
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:
|
||||||
|
|
||||||
|
- 三个 PHP 文件均无语法错误。
|
||||||
|
|
||||||
|
生成命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -r 'require __DIR__ . "/vendor/autoload.php"; $app = new think\App(); $app->initialize(); app\common\helper\DomainSitemapGenerationHelper::generateNow(["zbsv3.com","sdxhtgcl.com","sdxtwnc.com","glae.cc","jxxgygy.com","jingxifa.com","codohealth.com","vikau.com","cnzhenbang.com"]);'
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:
|
||||||
|
|
||||||
|
- 4 页 sitemap/video-list 全部生成完成。
|
||||||
|
- 结束时间:`2026-05-09 10:49:49`
|
||||||
|
|
||||||
|
## 5. SEO 影响判断
|
||||||
|
|
||||||
|
这次修正解决的是 URL 规范化问题,不是直接加词。
|
||||||
|
|
||||||
|
预期影响:
|
||||||
|
|
||||||
|
1. 减少 `www` 与非 `www` 的 URL 信号分散。
|
||||||
|
2. 让 robots、canonical、sitemap、百度推送保持同一规范版本。
|
||||||
|
3. 后续百度抓取里 `http -> https` 的 301 不会立刻归零,但 `www` 相关的分裂入口会逐步减少。
|
||||||
|
4. 对 `glae/jxxgygy/jingxifa/codohealth` 的收录转词更有利。
|
||||||
|
|
||||||
|
明天复查:
|
||||||
|
|
||||||
|
1. `2026-05-10` 蜘蛛日志里重点域名的 Baidu `301` 是否下降。
|
||||||
|
2. `sitemap-videos-*.txt` 是否继续保持非 www。
|
||||||
|
3. 百度推送摘要里 `site=` 是否不再出现 `https://www.domain`。
|
||||||
|
4. 爱站 `pc_keyword_count` 是否从 `0` 恢复到 `>=2`。
|
||||||
|
|
||||||
|
## 6. 当前结论
|
||||||
|
|
||||||
|
本次属于 7 日失败后的必要技术纠偏。
|
||||||
|
|
||||||
|
> 前面的问题不是“AI 文案没用”,而是 URL 规范信号有分裂:页面告诉搜索引擎看非 www,sitemap/推送却给了 www。现在当前 GPT 主测试源已经统一到非 www,下一步看蜘蛛日志中的 301 和爱站词恢复情况。
|
||||||
166
docs/gpt-template-seo/23-GPT模板5月12蜘蛛日志与7日后续进度-2026-05-12.md
Normal file
166
docs/gpt-template-seo/23-GPT模板5月12蜘蛛日志与7日后续进度-2026-05-12.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# GPT 模板 5 月 12 日蜘蛛日志与 7 日后续进度
|
||||||
|
|
||||||
|
记录时间:2026-05-12 00:03 CST
|
||||||
|
|
||||||
|
本次只分析当前 GPT 主测试源相关数据。5 月 12 日目前只有 1 批早盘日志,样本太小,不能当作全天效果判断;今天的主结论以 2026-05-11 完整日为准,5 月 12 日只作为零点观察。
|
||||||
|
|
||||||
|
## 一、今天总判断
|
||||||
|
|
||||||
|
7 日“10 个关键词上首页”目标仍未达成。5 月 9 日完成 sitemap、百度推送、txt/json 产物的非 www 规范化后,301 浪费确实下降了,但蜘蛛量、百度收录状态和爱站出词还没有形成正反馈。
|
||||||
|
|
||||||
|
目前阶段不能继续盲目扩词,策略要从“冲 10 词”切到“保历史词 + 把已收录候选转成出词 + 降异常浪费”。
|
||||||
|
|
||||||
|
关键结论:
|
||||||
|
|
||||||
|
- 5 月 11 日百度 indexed_like 站点数为 5,爱站 PC 词为 0。
|
||||||
|
- 历史反馈池里还有 7 个爱站关键词记录,但这些是 30 日历史记录,不能当作今天实际排名。
|
||||||
|
- 5 月 9 日修正后,301 从 198 降到 146,再降到 112,说明 URL 规范化有效。
|
||||||
|
- 同期百度蜘蛛从 432 降到 292,再降到 221,说明只是减少了浪费,还没有把抓取量重新拉起来。
|
||||||
|
- 5 月 11 日深页抓取比 5 月 10 日恢复了一部分,重点看 `codohealth.com`、`jingxifa.com`、`lgyz.net`。
|
||||||
|
|
||||||
|
## 二、蜘蛛趋势
|
||||||
|
|
||||||
|
| 日期 | 统计批次 | 总蜘蛛 | 百度 | 字节 | 搜狗 | 首页 | 栏目 | 详情 | 播放 | robots | 200 | 301 | 403 | 444 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| 2026-05-09 | 143 | 578 | 432 | 75 | 71 | 316 | 32 | 57 | 39 | 85 | 276 | 198 | 71 | 32 |
|
||||||
|
| 2026-05-10 | 143 | 471 | 292 | 97 | 82 | 287 | 54 | 12 | 16 | 80 | 203 | 146 | 90 | 31 |
|
||||||
|
| 2026-05-11 | 143 | 355 | 221 | 75 | 59 | 132 | 36 | 28 | 36 | 70 | 145 | 112 | 63 | 30 |
|
||||||
|
| 2026-05-12 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
|
||||||
|
|
||||||
|
判读:
|
||||||
|
|
||||||
|
- URL 规范化修正有效,301 连续下降,这是正向信号。
|
||||||
|
- 200 也从 276 降到 145,说明蜘蛛总量没有跟着恢复,当前不是“推更多页面”能解决的阶段。
|
||||||
|
- 详情页 + 播放页从 5 月 10 日的 28 回升到 5 月 11 日的 64,深页有恢复,但还集中在少数站。
|
||||||
|
- 5 月 12 日零点数据只有 1 条,且无百度蜘蛛,上午 9 点后需要继续观察是否恢复正常批量采集。
|
||||||
|
|
||||||
|
## 三、百度收录与爱站信息
|
||||||
|
|
||||||
|
| 日期 | 百度 indexed_like | 百度 failed | 百度 unknown | 爱站有词域名数 | 爱站 PC 词 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| 2026-05-08 | 6 | 7 | 19 | 0 | 0 |
|
||||||
|
| 2026-05-09 | 5 | 4 | 23 | 0 | 0 |
|
||||||
|
| 2026-05-10 | 4 | 7 | 21 | 0 | 0 |
|
||||||
|
| 2026-05-11 | 5 | 9 | 18 | 0 | 0 |
|
||||||
|
|
||||||
|
5 月 11 日 indexed_like 站点:
|
||||||
|
|
||||||
|
- `codohealth.com`
|
||||||
|
- `hbczccq.com`
|
||||||
|
- `hyjssb.com`
|
||||||
|
- `lsrxs.com`
|
||||||
|
- `nblssy.com`
|
||||||
|
|
||||||
|
重点判断:
|
||||||
|
|
||||||
|
- `codohealth.com` 同时具备 indexed_like、百度蜘蛛 20、详情页抓取 4,是今天最值得转词的候选。
|
||||||
|
- `glae.cc` 5 月 11 日转为 unknown,且百度蜘蛛只有 1,不能再作为短期主冲站。
|
||||||
|
- `jxxgygy.com` 5 月 10 日 indexed_like,5 月 11 日 unknown,且蜘蛛量只有 4,需要低成本观察。
|
||||||
|
- `zbsv3.com`、`sdxhtgcl.com`、`sdxtwnc.com` 有历史词基础,但 5 月 11 日外部快照没有形成爱站词回归。
|
||||||
|
|
||||||
|
## 四、域名分层
|
||||||
|
|
||||||
|
### P0:历史词恢复,不再盲目扩词
|
||||||
|
|
||||||
|
`sdxtwnc.com`
|
||||||
|
|
||||||
|
- 5 月 11 日百度蜘蛛 55,全部集中首页,200 为 46,301 为 9。
|
||||||
|
- 蜘蛛非常强,但外部快照显示百度 failed,爱站 0。
|
||||||
|
- 今天动作:保留标题和主关键词稳定性,检查首页内容、canonical、sitemap、推送 URL 是否完全一致;暂不扩词。
|
||||||
|
|
||||||
|
`zbsv3.com`
|
||||||
|
|
||||||
|
- 历史反馈池有 3 个词,是之前最有价值的老目标。
|
||||||
|
- 5 月 11 日外部快照为 failed,且蜘蛛热度明显下降。
|
||||||
|
- 今天动作:从主冲降为保词复核,只做 URL/收录/推送复查,不继续加新词。
|
||||||
|
|
||||||
|
`sdxhtgcl.com`
|
||||||
|
|
||||||
|
- 历史反馈池有 1 个词。
|
||||||
|
- 5 月 11 日外部快照为 failed。
|
||||||
|
- 今天动作:保历史词,先恢复可抓取和可收录状态。
|
||||||
|
|
||||||
|
### P1:收录转词候选
|
||||||
|
|
||||||
|
`codohealth.com`
|
||||||
|
|
||||||
|
- 5 月 11 日 indexed_like。
|
||||||
|
- 百度蜘蛛 20,详情页抓取 4,200 为 10,301 为 10,403 为 4。
|
||||||
|
- 今天动作:作为第一转词候选,只锁 1 个主词,优先降低 301/403,不扩大页面池。
|
||||||
|
|
||||||
|
`jingxifa.com`
|
||||||
|
|
||||||
|
- 5 月 11 日百度蜘蛛 24,详情页 4,播放页 20。
|
||||||
|
- 当前外部快照仍是 unknown。
|
||||||
|
- 今天动作:保深页抓取,重点降 301;如果 5 月 12 日转 indexed_like,再进入转词候选。
|
||||||
|
|
||||||
|
`lgyz.net`
|
||||||
|
|
||||||
|
- 5 月 11 日百度蜘蛛 18,详情页 8,播放页 8。
|
||||||
|
- 403 为 7,浪费偏高。
|
||||||
|
- 今天动作:观察为第二深页候选,先降 403,再考虑推词。
|
||||||
|
|
||||||
|
`hyjssb.com`、`nblssy.com`、`lsrxs.com`
|
||||||
|
|
||||||
|
- 5 月 11 日 indexed_like。
|
||||||
|
- 先作为收录观察站,不直接占用 GPT 主冲资源,除非确认模板、内容和蜘蛛路径都适合。
|
||||||
|
|
||||||
|
### P2:异常修复或低成本观察
|
||||||
|
|
||||||
|
`glae.cc`
|
||||||
|
|
||||||
|
- 历史反馈池仍有 2 个词。
|
||||||
|
- 5 月 11 日百度蜘蛛只有 1,爱站 0。
|
||||||
|
- 今天动作:保历史词,不再作为 48 小时内的主冲站。
|
||||||
|
|
||||||
|
`jxxgygy.com`
|
||||||
|
|
||||||
|
- 5 月 10 日 indexed_like,5 月 11 日 unknown。
|
||||||
|
- 5 月 11 日百度蜘蛛 4,全部首页 200。
|
||||||
|
- 今天动作:低成本观察,等蜘蛛量回升后再判断。
|
||||||
|
|
||||||
|
`cnzhenbang.com`
|
||||||
|
|
||||||
|
- 5 月 11 日栏目抓取 36,但百度蜘蛛只有 2,301 为 18,403 为 20。
|
||||||
|
- 今天动作:异常修复站,不做关键词推进。
|
||||||
|
|
||||||
|
`vikau.com`
|
||||||
|
|
||||||
|
- 5 月 11 日 robots 和 403/444 仍偏高。
|
||||||
|
- 今天动作:异常修复站,不做关键词推进。
|
||||||
|
|
||||||
|
## 五、5 月 9 日代码修正验收
|
||||||
|
|
||||||
|
已生效的正向部分:
|
||||||
|
|
||||||
|
- sitemap、百度推送、txt/json 产物统一到非 www 后,301 明显下降。
|
||||||
|
- 运行产物已按关键域名刷新,推送口径不再继续制造 `https://www.domain` 与 `https://domain` 混用。
|
||||||
|
|
||||||
|
仍未解决的问题:
|
||||||
|
|
||||||
|
- 百度蜘蛛总量没有恢复,5 月 11 日只有 221。
|
||||||
|
- 爱站 PC 词仍为 0。
|
||||||
|
- 部分域名仍有较高 403/444,说明抓取链路和防护/路径状态还在浪费蜘蛛。
|
||||||
|
|
||||||
|
结论:5 月 9 日修正是必要底座修复,但它只能减少浪费,不能单独创造排名。接下来要靠“收录候选转词”和“历史词恢复”两条线推进。
|
||||||
|
|
||||||
|
## 六、今天执行动作
|
||||||
|
|
||||||
|
1. 上午 9 点后继续看 5 月 12 日蜘蛛批次。如果百度仍然接近 0,先查采集/日志链路,再判断是否真无蜘蛛。
|
||||||
|
2. `codohealth.com` 作为今天第一转词候选,保 1 个主词,先降详情页 301/403。
|
||||||
|
3. `sdxtwnc.com` 作为历史词恢复候选,重点诊断“百度蜘蛛强但外部快照 failed”的原因,暂不改标题、不扩词。
|
||||||
|
4. `jingxifa.com` 和 `lgyz.net` 保持深页抓取,优先降 301/403。
|
||||||
|
5. `glae.cc`、`zbsv3.com`、`sdxhtgcl.com` 只做历史词恢复复核,不继续加页面池。
|
||||||
|
6. `cnzhenbang.com`、`vikau.com` 只修异常,不计入今天关键词冲刺资源。
|
||||||
|
|
||||||
|
## 七、明天验收口径
|
||||||
|
|
||||||
|
2026-05-13 复盘时看这几个硬指标:
|
||||||
|
|
||||||
|
- 百度蜘蛛总量是否回到 250 以上。
|
||||||
|
- 301 是否继续压到 100 以下。
|
||||||
|
- 百度 indexed_like 是否稳定不低于 5。
|
||||||
|
- 爱站 PC 词是否至少恢复到 1。
|
||||||
|
- `codohealth.com` 或 `sdxtwnc.com` 是否出现更明确的正向信号。
|
||||||
|
|
||||||
|
如果明天仍然是 indexed_like 有少量、爱站 0、百度蜘蛛继续下降,就要继续缩小主冲范围,只保 2 到 3 个站,把其它站全部转为观察或异常修复。
|
||||||
117
docs/gpt-template-seo/24-GPT模板5月12午盘蜘蛛日志与7日进度续报-2026-05-12.md
Normal file
117
docs/gpt-template-seo/24-GPT模板5月12午盘蜘蛛日志与7日进度续报-2026-05-12.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# GPT 模板 5 月 12 日午盘蜘蛛日志与 7 日进度续报
|
||||||
|
|
||||||
|
记录时间:2026-05-12 13:30 CST
|
||||||
|
窗口范围:2026-05-06 至 2026-05-12,5 月 12 日为午盘非完整日。
|
||||||
|
数据源:`code/storage/domain-spider-crawl/runs/YYYYMMDD/*/crawl-logs.summary.json`、`seo_external_snapshot`、`keyword_feedback` 最新反馈文件。
|
||||||
|
口径说明:蜘蛛主表只统计 `baiduspider`、`bytespider`、`sogou`,排除 Google/Bing 的 robots 444 干扰。Baidu `site:` 线上直连请求会触发安全验证,本次以外部快照表为准。
|
||||||
|
|
||||||
|
## 一句话结论
|
||||||
|
|
||||||
|
7 日 10 词上首页目标仍未达成。5 月 12 日午盘核心蜘蛛只有 160 次,其中百度 74 次,低于 5 月 8 日至 5 月 9 日峰值;百度 `site:` 快照由 5 月 11 日的 5 个 `indexed_like` 降到 5 月 12 日的 3 个;爱站当前日 PC 词仍为 0。
|
||||||
|
|
||||||
|
`leici1940.com` 不是当前可放大的主线:5 月 9 日曾出现 `indexed_like`,但 5 月 10 日至 5 月 12 日回到 `unknown`;5 月 12 日午盘无百度蜘蛛命中,且 7 日内没有 detail/play 蜘蛛深抓。播放器 JS 报错已定位到前端容器空指针与前端缓存问题,仍需要清前置缓存,但 SEO 主因更偏向抓取深度和 canonical/301 消耗。
|
||||||
|
|
||||||
|
## 7 日核心蜘蛛进度
|
||||||
|
|
||||||
|
| 日期 | 批次 | 核心蜘蛛 | 百度 | 头条 | 搜狗 | 首页 | 详情+播放 | robots | 200 | 301 | 403 | 444 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| 2026-05-06 | 141 | 263 | 147 | 79 | 37 | 84 | 67 | 64 | 102 | 77 | 57 | 27 |
|
||||||
|
| 2026-05-07 | 144 | 285 | 180 | 62 | 43 | 118 | 60 | 58 | 135 | 70 | 49 | 30 |
|
||||||
|
| 2026-05-08 | 144 | 626 | 470 | 80 | 76 | 406 | 62 | 85 | 393 | 128 | 78 | 27 |
|
||||||
|
| 2026-05-09 | 143 | 578 | 432 | 75 | 71 | 316 | 96 | 85 | 276 | 198 | 71 | 32 |
|
||||||
|
| 2026-05-10 | 143 | 471 | 292 | 97 | 82 | 287 | 28 | 80 | 203 | 146 | 90 | 31 |
|
||||||
|
| 2026-05-11 | 143 | 355 | 221 | 75 | 59 | 132 | 64 | 70 | 145 | 112 | 63 | 30 |
|
||||||
|
| 2026-05-12 | 80 | 160 | 74 | 48 | 38 | 63 | 24 | 44 | 49 | 51 | 40 | 20 |
|
||||||
|
|
||||||
|
判断:
|
||||||
|
|
||||||
|
1. 百度蜘蛛峰值出现在 5 月 8 日和 5 月 9 日,之后连续回落:470 -> 432 -> 292 -> 221 -> 74 午盘。
|
||||||
|
2. URL 规范化后 301 在 5 月 9 日至 5 月 11 日从 198 降到 112,但 5 月 12 日午盘已到 51,按全日投影仍可能接近 90 至 100,说明 www/non-www 和历史入口还在消耗蜘蛛。
|
||||||
|
3. 详情+播放页 5 月 11 日为 64,5 月 12 日午盘只有 24,深抓没有形成稳定放大。
|
||||||
|
|
||||||
|
## Baidu Site 与爱站进度
|
||||||
|
|
||||||
|
| 日期 | Baidu indexed_like | Baidu failed | Baidu unknown | 爱站快照站点 | 爱站 PC 词 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| 2026-05-06 | 1 | 28 | 3 | 32 | 2 |
|
||||||
|
| 2026-05-07 | 3 | 14 | 15 | 16 | 2 |
|
||||||
|
| 2026-05-08 | 6 | 7 | 19 | 16 | 0 |
|
||||||
|
| 2026-05-09 | 5 | 4 | 23 | 15 | 0 |
|
||||||
|
| 2026-05-10 | 4 | 7 | 21 | 17 | 0 |
|
||||||
|
| 2026-05-11 | 5 | 9 | 18 | 17 | 0 |
|
||||||
|
| 2026-05-12 | 3 | 18 | 11 | 13 | 0 |
|
||||||
|
|
||||||
|
5 月 12 日 `indexed_like` 域名:`cnzhenbang.com`、`gulenyuzlercocukevi.com`、`gz-yxsw.com`。
|
||||||
|
5 月 6 日至 5 月 7 日爱站 PC 词只出现在 `glae.cc`,各 2 个;5 月 8 日以后当前日爱站 PC 词为 0。30 日反馈里仍有历史词,但不能按当前出词计算。
|
||||||
|
|
||||||
|
## 5 月 12 日午盘域名层表现
|
||||||
|
|
||||||
|
按去掉 `www.` 后的主域聚合,取核心蜘蛛前 15:
|
||||||
|
|
||||||
|
| 域名 | 核心蜘蛛 | 百度 | 头条 | 搜狗 | 首页 | 详情+播放 | 200 | 301 | 403 | 444 |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| cnzhenbang.com | 24 | 0 | 2 | 22 | 2 | 0 | 0 | 11 | 13 | 0 |
|
||||||
|
| lcdchq.com | 23 | 17 | 6 | 0 | 17 | 0 | 13 | 7 | 3 | 0 |
|
||||||
|
| jingxifa.com | 14 | 12 | 0 | 2 | 2 | 12 | 6 | 7 | 1 | 0 |
|
||||||
|
| sjzyunyang.com | 14 | 12 | 0 | 2 | 2 | 12 | 6 | 7 | 1 | 0 |
|
||||||
|
| vikau.com | 11 | 2 | 7 | 2 | 3 | 0 | 0 | 1 | 4 | 6 |
|
||||||
|
| hyjssb.com | 10 | 5 | 5 | 0 | 5 | 0 | 5 | 1 | 1 | 3 |
|
||||||
|
| sdxtwnc.com | 10 | 10 | 0 | 0 | 10 | 0 | 6 | 4 | 0 | 0 |
|
||||||
|
| nblssy.com | 7 | 1 | 6 | 0 | 4 | 0 | 1 | 3 | 3 | 0 |
|
||||||
|
| jxxgygy.com | 6 | 0 | 0 | 6 | 4 | 0 | 0 | 3 | 3 | 0 |
|
||||||
|
| lmjcg.com | 6 | 0 | 2 | 4 | 2 | 0 | 0 | 2 | 4 | 0 |
|
||||||
|
| stsgf.com | 6 | 3 | 3 | 0 | 3 | 0 | 3 | 0 | 0 | 3 |
|
||||||
|
| codohealth.com | 5 | 4 | 1 | 0 | 0 | 0 | 2 | 2 | 1 | 0 |
|
||||||
|
| lgyz.net | 5 | 1 | 4 | 0 | 1 | 0 | 1 | 0 | 4 | 0 |
|
||||||
|
| visitsumenep.com | 4 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 4 |
|
||||||
|
| caosheninan.com | 3 | 3 | 0 | 0 | 3 | 0 | 2 | 1 | 0 | 0 |
|
||||||
|
|
||||||
|
域名判断:
|
||||||
|
|
||||||
|
1. `jingxifa.com` 和 `sjzyunyang.com` 是今天少数有详情+播放深抓的域名,各 12 次,优先保留在收录转词观察层。
|
||||||
|
2. `sdxtwnc.com` 仍有百度首页抓取,但 `site:` 快照 5 月 12 日为 `failed`,需要先查为什么“有抓取但快照不稳”。
|
||||||
|
3. `cnzhenbang.com` 虽然 5 月 12 日为 `indexed_like`,但午盘核心蜘蛛里没有百度,且 301/403 占满,不适合直接当转词主力。
|
||||||
|
4. `vikau.com` 403/444 仍偏高,只做异常修复,不进入放大。
|
||||||
|
5. `codohealth.com` 5 月 11 日有 `indexed_like`,但 5 月 12 日午盘深抓为 0,先观察,不加资源。
|
||||||
|
|
||||||
|
## leici1940.com 单站复查
|
||||||
|
|
||||||
|
| 日期 | 核心蜘蛛 | 百度 | 头条 | 搜狗 | 详情+播放 | 200 | 301 | 403 | 444 | Baidu site |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
|
||||||
|
| 2026-05-06 | 11 | 7 | 4 | 0 | 0 | 3 | 6 | 2 | 0 | failed |
|
||||||
|
| 2026-05-07 | 5 | 3 | 2 | 0 | 0 | 2 | 2 | 1 | 0 | failed |
|
||||||
|
| 2026-05-08 | 23 | 17 | 6 | 0 | 0 | 11 | 9 | 3 | 0 | unknown |
|
||||||
|
| 2026-05-09 | 8 | 4 | 4 | 0 | 0 | 2 | 4 | 2 | 0 | indexed_like |
|
||||||
|
| 2026-05-10 | 23 | 12 | 11 | 0 | 0 | 6 | 10 | 6 | 1 | unknown |
|
||||||
|
| 2026-05-11 | 14 | 12 | 2 | 0 | 0 | 6 | 7 | 1 | 0 | unknown |
|
||||||
|
| 2026-05-12 | 3 | 0 | 3 | 0 | 0 | 0 | 2 | 1 | 0 | unknown |
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
1. `leici1940.com` 的 watch 页面播放器报错会影响用户侧体验和页面质量信号,但蜘蛛层面更大的问题是:7 日没有形成详情/播放深抓,5 月 12 日午盘也没有百度蜘蛛。
|
||||||
|
2. 该站 301 占比偏高,且 5 月 12 日 3 次核心蜘蛛中 2 次 301、1 次 403,没有有效 200 落点。
|
||||||
|
3. 前端 JS 文件已经采用带签名的新文件名绕开路径缓存,但线上普通入口仍可能命中前置缓存旧 HTML。需要清前置缓存后,再用同一 watch URL 复查 console 是否还报 `classList` 空指针。
|
||||||
|
|
||||||
|
## 下一步执行口径
|
||||||
|
|
||||||
|
P0:保历史词,不扩词。
|
||||||
|
保留 `glae.cc`、`zbsv3.com`、`sdxhtgcl.com`、`sdxtwnc.com` 的历史词反馈链路,但按当前日爱站 0 词处理,不做新增关键词铺量。
|
||||||
|
|
||||||
|
P1:收录转词只看有深抓的域名。
|
||||||
|
`jingxifa.com`、`sjzyunyang.com` 今天有详情+播放抓取,优先检查详情页和播放页 200 落点、标题差异、canonical、sitemap 是否一致。`codohealth.com`、`hyjssb.com`、`nblssy.com` 等先等 5 月 13 日回访确认。
|
||||||
|
|
||||||
|
P2:异常域名先降 301/403/444。
|
||||||
|
`cnzhenbang.com`、`vikau.com`、`jxxgygy.com`、`lmjcg.com` 目前异常状态占比高,不作为首页词冲刺对象。先处理 www/non-www、robots、WAF/封禁和历史入口 301。
|
||||||
|
|
||||||
|
`leici1940.com` 专项:
|
||||||
|
先清前置缓存并复查播放器;然后观察 5 月 13 日是否恢复百度蜘蛛、详情/播放深抓和 `site:` 稳定状态。未恢复前,不把它列入关键词放大主线。
|
||||||
|
|
||||||
|
## 5 月 13 日验收线
|
||||||
|
|
||||||
|
1. 核心蜘蛛全日大于等于 350,百度大于等于 180。
|
||||||
|
2. 详情+播放页全日大于等于 60,且至少 2 个候选域名有稳定深抓。
|
||||||
|
3. 301 全日控制在 100 以下,403/444 不继续扩大。
|
||||||
|
4. Baidu `indexed_like` 回到 5 个以上。
|
||||||
|
5. 爱站当前日 PC 词出现非 0,或者历史词域名重新被 Baidu `site:` 捕获。
|
||||||
|
|
||||||
|
如果以上 5 条达不到,不进入新一轮关键词扩张,只继续做收录稳定、深抓和异常状态修复。
|
||||||
@@ -40,6 +40,30 @@
|
|||||||
作用:给后续 Codex 或技术接手同学,快速说明这轮模板中文化与自动补全到底改了什么。
|
作用:给后续 Codex 或技术接手同学,快速说明这轮模板中文化与自动补全到底改了什么。
|
||||||
8. [12-GPT模板导入模板改造交付清单-2026-04-18.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/12-GPT模板导入模板改造交付清单-2026-04-18.md)
|
8. [12-GPT模板导入模板改造交付清单-2026-04-18.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/12-GPT模板导入模板改造交付清单-2026-04-18.md)
|
||||||
作用:把本轮模板改造的交付边界、统一口径和验收标准一次性钉住。
|
作用:把本轮模板改造的交付边界、统一口径和验收标准一次性钉住。
|
||||||
|
9. [13-GPT模板下周7日首页词冲量计划-2026-04-29.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/13-GPT模板下周7日首页词冲量计划-2026-04-29.md)
|
||||||
|
作用:第二周从“推收录/看回访”升级到“已出词放大、收录转词、代理浏览核验”的 7 日执行计划。
|
||||||
|
10. [14-GPT模板Day1进度复盘-2026-04-30.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/14-GPT模板Day1进度复盘-2026-04-30.md)
|
||||||
|
作用:记录 Day1 蜘蛛、百度收录、爱站信息和站点底座复查结果,为后续 7 日计划每日对比提供基线。
|
||||||
|
11. [15-GPT模板Day2阶段效果复盘-2026-05-01.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/15-GPT模板Day2阶段效果复盘-2026-05-01.md)
|
||||||
|
作用:继续分析 Day2 蜘蛛日志、百度收录快照、爱站出词变化,给出是否加码、修复或暂缓的阶段判断。
|
||||||
|
12. [16-GPT模板多源协作边界与真实启用核查-2026-05-01.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/16-GPT模板多源协作边界与真实启用核查-2026-05-01.md)
|
||||||
|
作用:固定 GPT/老模板多源协作规则,核查 AI 文案、引导文案、外部反馈是否真实进入前台,并记录本次运行时反馈闭环修正。
|
||||||
|
13. [17-GPT模板7日10词上首页冲刺目标-2026-05-01.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/17-GPT模板7日10词上首页冲刺目标-2026-05-01.md)
|
||||||
|
作用:把 2026-05-01 到 2026-05-07 的硬目标固定为至少 10 个关键词进入百度首页结果页,并按域名、关键词编号、每日动作和验收口径倒排执行。
|
||||||
|
14. [18-GPT模板10词冲刺夜间收口执行单-2026-05-01.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/18-GPT模板10词冲刺夜间收口执行单-2026-05-01.md)
|
||||||
|
作用:记录 Day1 晚上 22:46 的蜘蛛状态,明确夜间冻结大改、锁 K 词、明早验收的执行边界。
|
||||||
|
15. [19-GPT模板Day5蜘蛛日志与7日进度复盘-2026-05-05.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/19-GPT模板Day5蜘蛛日志与7日进度复盘-2026-05-05.md)
|
||||||
|
作用:复盘 2026-05-05 上午蜘蛛、百度收录、爱站出词和 7 日 10 词首页目标进度,给出 Day5 资源重排策略。
|
||||||
|
16. [20-GPT模板7日目标验收与蜘蛛日志复盘-2026-05-09.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/20-GPT模板7日目标验收与蜘蛛日志复盘-2026-05-09.md)
|
||||||
|
作用:验收 7 日 10 词首页目标,复盘 2026-05-01 到 2026-05-09 蜘蛛、百度收录、爱站出词,并给出下一阶段保词/转词/降异常策略。
|
||||||
|
17. [21-GPT模板7日后续执行单-2026-05-09.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/21-GPT模板7日后续执行单-2026-05-09.md)
|
||||||
|
作用:把 7 日验收后的下一步拆成保历史词、收录转词、降异常三条执行线,并明确 2026-05-10 验收口径。
|
||||||
|
18. [22-GPT模板Sitemap与百度推送URL规范化修正-2026-05-09.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/22-GPT模板Sitemap与百度推送URL规范化修正-2026-05-09.md)
|
||||||
|
作用:记录当前 GPT 主测试源 sitemap、运行生成逻辑、百度推送 URL 从 `https://www.domain` 统一到 `https://domain` 的代码修正、产物刷新和次日验收口径。
|
||||||
|
19. [23-GPT模板5月12蜘蛛日志与7日后续进度-2026-05-12.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/23-GPT模板5月12蜘蛛日志与7日后续进度-2026-05-12.md)
|
||||||
|
作用:复盘 2026-05-11 完整日与 5 月 12 日零点蜘蛛、百度收录、爱站信息,验收 sitemap/推送 URL 规范化后的实际效果,并重排历史词恢复、收录转词和异常修复优先级。
|
||||||
|
20. [24-GPT模板5月12午盘蜘蛛日志与7日进度续报-2026-05-12.md](/www/wwwroot/diff-maccms/SEONexus/docs/gpt-template-seo/24-GPT模板5月12午盘蜘蛛日志与7日进度续报-2026-05-12.md)
|
||||||
|
作用:按 2026-05-06 至 2026-05-12 午盘窗口复盘核心蜘蛛、Baidu site、爱站和 leici1940.com 单站状态,给出 5 月 13 日继续验收的域名分层与阈值。
|
||||||
|
|
||||||
首批 4 站的执行材料也全部放在本目录:
|
首批 4 站的执行材料也全部放在本目录:
|
||||||
|
|
||||||
|
|||||||
278
docs/old-tmp-seo/45-老模板每日复盘-2026-04-20.md
Normal file
278
docs/old-tmp-seo/45-老模板每日复盘-2026-04-20.md
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
# 45-老模板每日复盘 - 2026-04-20
|
||||||
|
|
||||||
|
## 1. 基础信息
|
||||||
|
|
||||||
|
- 复盘日期:`2026-04-20`
|
||||||
|
- 复盘口径:
|
||||||
|
- 主判断以 `domestic bots` 为准
|
||||||
|
- 即:`baiduspider + bytespider + sogou`
|
||||||
|
- 当前样板站:
|
||||||
|
- `yagyjt.com`
|
||||||
|
- `www.ningxiaowei.com`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 今日总判断
|
||||||
|
|
||||||
|
- 今天相较 `2026-04-18`、`2026-04-19`,老模板这条线已经不是“只剩入口层回访”,而是重新回到“首页 + 深页并行抓取”的状态。
|
||||||
|
- 如果只看全量蜘蛛,今天会被 `googlebot + category 444` 放大噪音带偏。
|
||||||
|
- 但如果按我们真正关心的国内蜘蛛口径看,今天应判定为:
|
||||||
|
- `主线没有跑偏`
|
||||||
|
- `7 日进度继续向前`
|
||||||
|
- `仍然是部分达标,未到完全达标`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 今日 domestic 口径总量
|
||||||
|
|
||||||
|
基于 `2026-04-20` 全日 run 聚合,`baiduspider + bytespider + sogou` 合计:
|
||||||
|
|
||||||
|
- 总请求:`592`
|
||||||
|
- 页面类型:
|
||||||
|
- `home = 317`
|
||||||
|
- `detail = 117`
|
||||||
|
- `robots = 64`
|
||||||
|
- `other = 58`
|
||||||
|
- `play = 35`
|
||||||
|
- `sitemap = 1`
|
||||||
|
- `category = 0`
|
||||||
|
- 状态:
|
||||||
|
- `200 = 308`
|
||||||
|
- `301 = 204`
|
||||||
|
- `403 = 56`
|
||||||
|
- `404 = 13`
|
||||||
|
- `444 = 11`
|
||||||
|
- 蜘蛛分布:
|
||||||
|
- `baiduspider = 488`
|
||||||
|
- `bytespider = 66`
|
||||||
|
- `sogou = 38`
|
||||||
|
|
||||||
|
重点 host:
|
||||||
|
|
||||||
|
- `yagyjt.com = 103`
|
||||||
|
- `www.haotianhaiyuan.com = 46`
|
||||||
|
- `ctshuhua.com = 42`
|
||||||
|
- `www.ningxiaowei.com = 36`
|
||||||
|
- `ningxiaowei.com = 23`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 对比 Day0 与前两天
|
||||||
|
|
||||||
|
### 相对 Day0(2026-04-17)
|
||||||
|
|
||||||
|
Day0 基线:
|
||||||
|
|
||||||
|
- 总请求:`72`
|
||||||
|
- `detail = 21`
|
||||||
|
- `play = 4`
|
||||||
|
- `category = 1`
|
||||||
|
- `sitemap = 2`
|
||||||
|
- `200 = 34`
|
||||||
|
- `301 = 24`
|
||||||
|
- `444 = 8`
|
||||||
|
- `403 = 6`
|
||||||
|
|
||||||
|
今天:
|
||||||
|
|
||||||
|
- 总请求:`592`
|
||||||
|
- `detail = 117`
|
||||||
|
- `play = 35`
|
||||||
|
- `category = 0`
|
||||||
|
- `sitemap = 1`
|
||||||
|
- `200 = 308`
|
||||||
|
- `301 = 204`
|
||||||
|
- `444 = 11`
|
||||||
|
- `403 = 56`
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
1. 深页量级相比 Day0 已大幅放大
|
||||||
|
2. `detail + play = 152`,说明百度确实在继续消费老模板深页
|
||||||
|
3. 但分类层仍然没有起量
|
||||||
|
4. `301` 和 `403` 绝对值仍高,说明抓取面扩大后,入口归一和深页承接仍在吃预算
|
||||||
|
|
||||||
|
### 相对 2026-04-18
|
||||||
|
|
||||||
|
`2026-04-18` 是入口窗口收缩日:
|
||||||
|
|
||||||
|
- 总请求:`36`
|
||||||
|
- `detail = 0`
|
||||||
|
- `play = 0`
|
||||||
|
|
||||||
|
今天:
|
||||||
|
|
||||||
|
- 总请求:`592`
|
||||||
|
- `detail = 117`
|
||||||
|
- `play = 35`
|
||||||
|
|
||||||
|
结论:
|
||||||
|
|
||||||
|
1. `2026-04-18` 的收缩不是主线打坏
|
||||||
|
2. 今天深页强势回归,说明老模板仍在百度深抓池里
|
||||||
|
|
||||||
|
### 相对 2026-04-19
|
||||||
|
|
||||||
|
`2026-04-19` 口径结论是:
|
||||||
|
|
||||||
|
- 深页已经回归
|
||||||
|
- 但 `category = 0`
|
||||||
|
- `sitemap = 0`
|
||||||
|
- 属于“主线正确、部分达标”
|
||||||
|
|
||||||
|
今天继续验证了这一判断:
|
||||||
|
|
||||||
|
1. 深页不是一次性回访,而是在继续放量
|
||||||
|
2. 但分类层仍旧没有抬起
|
||||||
|
3. sitemap 仍然弱
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 样板站 1:`yagyjt.com`
|
||||||
|
|
||||||
|
## 今日数据
|
||||||
|
|
||||||
|
- 总请求:`103`
|
||||||
|
- 页面类型:
|
||||||
|
- `detail = 69`
|
||||||
|
- `play = 23`
|
||||||
|
- `home = 9`
|
||||||
|
- `robots = 2`
|
||||||
|
- 状态:
|
||||||
|
- `200 = 53`
|
||||||
|
- `301 = 48`
|
||||||
|
- `403 = 2`
|
||||||
|
- 蜘蛛:
|
||||||
|
- `baiduspider = 101`
|
||||||
|
- `bytespider = 2`
|
||||||
|
|
||||||
|
## 判断
|
||||||
|
|
||||||
|
1. 这是今天最明确的“老模板深抓样板站”
|
||||||
|
2. `detail + play = 92`,说明百度在持续吃这个站的深页
|
||||||
|
3. `200` 已经高于 `301`
|
||||||
|
4. 但 `301` 仍然接近 `200`,说明旧 family 到规范 family 的跳转预算仍然偏高
|
||||||
|
5. 今天没有出现 `444`,入口层纯异常明显比 Day0 干净
|
||||||
|
|
||||||
|
## 对目标的意义
|
||||||
|
|
||||||
|
- 好消息:
|
||||||
|
- `yagyjt.com` 已经明显从“是否还在被抓”升级到“深页持续回访”
|
||||||
|
- 当前卡点:
|
||||||
|
- 还没看到分类层接力
|
||||||
|
- 深页承接仍没把 `301` 再压低一大截
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 样板站 2:`www.ningxiaowei.com`
|
||||||
|
|
||||||
|
## 今日数据
|
||||||
|
|
||||||
|
- 总请求:`36`
|
||||||
|
- 页面类型:
|
||||||
|
- `detail = 28`
|
||||||
|
- `play = 8`
|
||||||
|
- 状态:
|
||||||
|
- `301 = 18`
|
||||||
|
- `200 = 18`
|
||||||
|
- 蜘蛛:
|
||||||
|
- `baiduspider = 36`
|
||||||
|
|
||||||
|
同时裸域 `ningxiaowei.com`:
|
||||||
|
|
||||||
|
- 总请求:`23`
|
||||||
|
- 页面类型:
|
||||||
|
- `home = 19`
|
||||||
|
- `detail = 4`
|
||||||
|
- 状态:
|
||||||
|
- `200 = 15`
|
||||||
|
- `301 = 8`
|
||||||
|
|
||||||
|
## 判断
|
||||||
|
|
||||||
|
1. `www.ningxiaowei.com` 今天也重新回到了深页持续抓取
|
||||||
|
2. 但它依旧是 `301 = 200`
|
||||||
|
3. 说明 `/video-info/...` 这条规范详情链路方向没错,但还没压缩到更短更稳
|
||||||
|
4. 裸域 `ningxiaowei.com` 还在被打首页与部分详情,说明域名归一信号仍然存在预算消耗
|
||||||
|
|
||||||
|
## 对目标的意义
|
||||||
|
|
||||||
|
- 好消息:
|
||||||
|
- 规范详情 family 仍在被百度消费
|
||||||
|
- 当前卡点:
|
||||||
|
- `www / 裸域` 维度还有预算分流
|
||||||
|
- 深页承接仍不够干净
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 今天和 7 日目标是否偏差
|
||||||
|
|
||||||
|
对照 [34-老模板7天SEO跟踪板-2026-04-17.md](/www/wwwroot/VideoSource2/docs/old-tmp-seo/34-老模板7天SEO跟踪板-2026-04-17.md) 与 [36-老模板首周验收清单-2026-04-17.md](/www/wwwroot/VideoSource2/docs/old-tmp-seo/36-老模板首周验收清单-2026-04-17.md),今天的结论应是:
|
||||||
|
|
||||||
|
- `方向正确`
|
||||||
|
- `结果继续前进`
|
||||||
|
- `仍属部分达标`
|
||||||
|
|
||||||
|
### 已经在进步的部分
|
||||||
|
|
||||||
|
1. 深页量级明显高于 Day0
|
||||||
|
2. `yagyjt.com` 已出现稳定深抓,且 `200 > 301`
|
||||||
|
3. `www.ningxiaowei.com` 继续保持规范详情深抓
|
||||||
|
4. `500 = 0`
|
||||||
|
|
||||||
|
### 仍然偏差的部分
|
||||||
|
|
||||||
|
1. `category_requests = 0`
|
||||||
|
2. `sitemap_requests = 1`,仍然偏弱
|
||||||
|
3. `301` 总量仍高
|
||||||
|
4. `403` 绝对值偏高
|
||||||
|
5. `www / 裸域` 与旧 family 仍在消耗预算
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 7 日进度当前评级
|
||||||
|
|
||||||
|
如果把 `2026-04-17` 作为 Day0,那么到 `2026-04-20` 这一天,7 日进度应打:
|
||||||
|
|
||||||
|
- `B 档:部分达标,且比前两天更接近 A 档`
|
||||||
|
|
||||||
|
原因:
|
||||||
|
|
||||||
|
1. 深页抓取已经不是偶发,而是连续放大
|
||||||
|
2. 样板站已经能验证“百度仍在吃深页”
|
||||||
|
3. 但入口层稳定度和分类层起量还不够
|
||||||
|
4. 所以还不能判定为“首周已完全打穿”
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 今天最大进步
|
||||||
|
|
||||||
|
1. `yagyjt.com` 深页持续放量,且 `200` 首次明显高于 `301`
|
||||||
|
2. `www.ningxiaowei.com` 深页继续稳定存在,没有掉出抓取池
|
||||||
|
3. `2026-04-18` 的入口收缩已经被今天的深抓回归证伪
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 今天最大卡点
|
||||||
|
|
||||||
|
1. 分类层仍然没有起量
|
||||||
|
2. sitemap 仍然太弱
|
||||||
|
3. `301` 和 `403` 总量仍高
|
||||||
|
4. `www.ningxiaowei.com` 的域名归一与详情承接仍未完全收干净
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 明天第一步
|
||||||
|
|
||||||
|
明天继续只看 4 件事:
|
||||||
|
|
||||||
|
1. `category_requests` 能不能从 `0` 抬起来
|
||||||
|
2. `sitemap_requests` 能不能稳定恢复
|
||||||
|
3. `yagyjt.com` 的 `301` 能不能继续低于 `200`
|
||||||
|
4. `www.ningxiaowei.com` 与 `ningxiaowei.com` 的预算分流能不能继续缩小
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 极简结论
|
||||||
|
|
||||||
|
> `2026-04-20` 这一天,老模板 SEO 7 日进度继续向前,已经能明确看到百度对样板站深页的持续消费,说明主线没有跑偏;但分类层和 sitemap 仍未起量,`301/403` 预算消耗也还偏高,所以当前最准确的判断仍是“部分达标,但正在接近达标”。
|
||||||
706
domain_probe_results.json
Normal file
706
domain_probe_results.json
Normal file
@@ -0,0 +1,706 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"d_id": 1165,
|
||||||
|
"domain": "yqshu8.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92684,
|
||||||
|
"title": "久久精品国产亚洲一区二区,日本免费人成视频播放,国产在线观看免费观看a,欧美激情精品久久久久久不卡,在线观看国产一区二区三区,久久99精品久久只有精品,中文字幕精品一区二区三区视频,国产精品欧美日韩久久久免费观看_言情影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.yqshu8.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1144,
|
||||||
|
"domain": "shxmbz.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 89980,
|
||||||
|
"title": "亚洲国产精品视频,免费人妻精品一区二区三区,久久九九日本韩国精品,日韩国产欧美在线观看一区二区_绪米影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.shxmbz.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1143,
|
||||||
|
"domain": "8866616.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92431,
|
||||||
|
"title": "亚洲精品久久一区二区三区,一区二区三区不卡视频,国产精品视频一区二区三区,日本中文字幕在线视频国产高清一区二区三区_卓斯影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 753,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.8866616.com/sitemap-main.xm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1142,
|
||||||
|
"domain": "ctshuhua.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 140352,
|
||||||
|
"title": "久久国产精品视频,久久精品视频免费观看,久久久久99,国产精品视频大全,精品在线一区_书华影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 759,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.ctshuhua.com/sitemap-main.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1140,
|
||||||
|
"domain": "zhongshuba.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 93370,
|
||||||
|
"title": "国产91免费视频,91视频在线,91视频观看,免费91视频,91免费视频入口_众书影院",
|
||||||
|
"snippet": "<html lang=\"zh\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" conte"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 771,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.zhongshuba.com/sitemap-main"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1133,
|
||||||
|
"domain": "yaleyishu.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92272,
|
||||||
|
"title": "日韩欧美国产精品,视频一区二区在线,99热精品国产,中文国产日韩欧美_雅乐艺书",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 765,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.yaleyishu.com/sitemap-main."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1132,
|
||||||
|
"domain": "mwzyj.top",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 140254,
|
||||||
|
"title": "日韩视频一区二区三区在线播放免费观看,亚洲欧美在线观看视频,久久9999久久免费精品国产,99热在线观看免费精品,99热在线免费观看_谜雾影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 741,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.mwzyj.top/sitemap-main.xml<"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1131,
|
||||||
|
"domain": "forcnehealthcare.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 115622,
|
||||||
|
"title": "国产99久久精品一区二区永久免费,99在线免费观看,国产99久久久欧美黑人,亚洲精品99久久久久中文字幕,99热在线观看免费精品,99热在线免费观看_富辰影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" c"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 807,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.forcnehealthcare.com/sitema"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1128,
|
||||||
|
"domain": "qf123.net",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 89377,
|
||||||
|
"title": "久久久国产精品视频,一区二区中文字幕,久久免费视频在线观看,亚洲欧美一区二区三区国产精品,久久久国产精品久久久_清风影院",
|
||||||
|
"snippet": "<html lang=\"zh\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" conte"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 741,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.qf123.net/sitemap-main.xml<"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1117,
|
||||||
|
"domain": "ruantishafa.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 89611,
|
||||||
|
"title": "久久久精品一区,久久久国产精品视频,日韩欧美在线中文字幕,久久国产中文国产午夜精品视频,99亚洲精品久久精品欧美一区_凯佳影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 777,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.ruantishafa.com/sitemap-mai"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1114,
|
||||||
|
"domain": "haotianhaiyuan.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 118326,
|
||||||
|
"title": "亚洲欧美日韩在线,亚洲欧美日韩综合,国产不卡在线,欧美日韩国产一区,欧美日韩国产免费,亚洲国产高清视频,国产电影在线观看一区_浩天海源影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" c"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 795,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.haotianhaiyuan.com/sitemap-"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1104,
|
||||||
|
"domain": "qingyejianshe.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 116545,
|
||||||
|
"title": "飘雪影院在线观看免费版高清动漫-飘雪日本高清免费观看电视剧-飘雪影院免费版在线观看视频_飘雪影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" c"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 789,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.qingyejianshe.com/sitemap-m"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1098,
|
||||||
|
"domain": "gyssjxq.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 89755,
|
||||||
|
"title": "亚洲精品久久一区二区三区,亚洲国产小视频,日本欧美日韩电影免费观看-三江影院",
|
||||||
|
"snippet": "<html lang=\"zh\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" conte"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 753,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.gyssjxq.com/sitemap-main.xm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1091,
|
||||||
|
"domain": "hymdrz.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 95456,
|
||||||
|
"title": "亚洲国产中文字幕在线,一区二区不卡视频,日本在线播放,中文字幕视频一区,欧洲精品一区二区,中文资源在线观看,中文字幕视频在线,一二三区精品视频_金牌影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.hymdrz.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1090,
|
||||||
|
"domain": "xcgruister.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 140452,
|
||||||
|
"title": "星辰高清影院_星辰视频在线观看免费观看-星辰影视大全免费版官网",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 771,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.xcgruister.com/sitemap-main"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1088,
|
||||||
|
"domain": "ap-hulan.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 93886,
|
||||||
|
"title": "久久99国产精品,亚洲在线免费观看视频,91精品国产综合久久精品,91久久国产综合久久91精品网站,日本不卡视频久久免费视频在线观看_虎澜电影院",
|
||||||
|
"snippet": "<html lang=\"zh\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" conte"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 759,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.ap-hulan.com/sitemap-main.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1058,
|
||||||
|
"domain": "syzhzs.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 89734,
|
||||||
|
"title": "桃花影院-桃花影院电视剧在线播放-影视大全在线免费观看",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.syzhzs.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1056,
|
||||||
|
"domain": "sdqzjbh.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 140012,
|
||||||
|
"title": "神马影院-无敌神马影视影院在线-神马达达兔在线电视剧免费大全",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 753,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.sdqzjbh.com/sitemap-main.xm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1055,
|
||||||
|
"domain": "sctyjz.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 115433,
|
||||||
|
"title": "午夜影院-热搜短剧大片抢先看-2025最新最好看的电影电视剧免费观看",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" c"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.sctyjz.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1054,
|
||||||
|
"domain": "bzxhhjx.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92828,
|
||||||
|
"title": "樱花影院-樱花影院高清电影好看的电视剧-樱花电影大全免费观看西瓜",
|
||||||
|
"snippet": "<html lang=\"zh\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" conte"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 753,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.bzxhhjx.com/sitemap-main.xm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1048,
|
||||||
|
"domain": "haleyhunt.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 89544,
|
||||||
|
"title": "凡桃影视 - 热门短剧免费在线观看,高清电影电视剧在线播",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 765,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.haleyhunt.com/sitemap-main."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1047,
|
||||||
|
"domain": "909664.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92482,
|
||||||
|
"title": "九九六影院 – 最新热门短剧免费在线观看",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.909664.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1046,
|
||||||
|
"domain": "ningxiaowei.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 139353,
|
||||||
|
"title": "宁小微影视 - 免费短剧、电视剧、电影、综艺、动漫免费在线观看",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 777,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.ningxiaowei.com/sitemap-mai"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1045,
|
||||||
|
"domain": "tvwallmountreview.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 114297,
|
||||||
|
"title": "剧集看点 - 热门短剧全集免费在线观看|电影电视剧动漫在线看",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" c"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 813,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.tvwallmountreview.com/sitem"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1044,
|
||||||
|
"domain": "proenerji.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92325,
|
||||||
|
"title": "国产精品99日韩欧美网站,欧美国产精品在线视频日韩一区,日韩欧美视频在线免费观看,欧美视频一区二区三区_剧乐汇",
|
||||||
|
"snippet": "<html lang=\"zh\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" conte"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 765,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.proenerji.com/sitemap-main."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1037,
|
||||||
|
"domain": "yahuawang88.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 94305,
|
||||||
|
"title": "亚洲欧美在线观看,日韩欧美中文在线,亚洲欧美精品在线观看,亚洲欧美视频一区,国产欧美精品一区二区三区四区_雅华网",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 777,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.yahuawang88.com/sitemap-mai"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1035,
|
||||||
|
"domain": "junhaolab.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 141689,
|
||||||
|
"title": "久久久天堂国产精品女人,99视频免费在线观看,久久久国产精品视频,国产精品香蕉在线观看,久久精品欧美一区二区_俊浩辣播影院",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 765,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.junhaolab.com/sitemap-main."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1034,
|
||||||
|
"domain": "yagyjt.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 119202,
|
||||||
|
"title": "欧美日韩视频在线,欧美中文字幕在线观看,欧美日韩视频,欧美日韩精品,日韩欧美在线观看,欧美日韩视频网站_雅格越剧厅",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" c"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.yagyjt.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1033,
|
||||||
|
"domain": "zsxd2020.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 88005,
|
||||||
|
"title": "日韩精品一区二区三区在线播放,99热在线播放,亚洲精品在线免费观看视频,亚洲一区久久,99在线免费观看视频_中石欣达影院",
|
||||||
|
"snippet": "<html lang=\"zh\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\" conte"
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 759,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.zsxd2020.com/sitemap-main.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1017,
|
||||||
|
"domain": "hygfbw.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 93416,
|
||||||
|
"title": "欧美日韩在线免费观看,一区二区欧美日韩高清免费,国产欧美日韩精品在线,高清欧美日韩一区二区三区在线观看,欧美精品国产第一区二区-海洋馆发布网",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.hygfbw.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1016,
|
||||||
|
"domain": "rqgcmc.com",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92653,
|
||||||
|
"title": "欧美在线免费看,欧美中文字幕在线播放,一区二区日韩国产精品,欧美中文日韩在线观看,亚洲欧美日韩专区一区二区三区-瑞奇馆传媒城",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 747,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.rqgcmc.com/sitemap-main.xml"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"d_id": 1001,
|
||||||
|
"domain": "dandanzan.xyz",
|
||||||
|
"/": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 92122,
|
||||||
|
"title": "蛋蛋赞 - 高清电影电视剧在线观看平台",
|
||||||
|
"snippet": "<html lang=\"zh-CN\"> <head> <meta charset=\"UTF-8\"> <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"> <meta name=\"viewport\""
|
||||||
|
},
|
||||||
|
"/rss/so.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 109,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> </urlset>"
|
||||||
|
},
|
||||||
|
"/sitemap.xml": {
|
||||||
|
"status": "200",
|
||||||
|
"len": 765,
|
||||||
|
"title": "",
|
||||||
|
"snippet": "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"> <sitemap> <loc>https://www.dandanzan.xyz/sitemap-main."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user