diff --git a/index.html b/index.html index 71b7364..fb09b27 100644 --- a/index.html +++ b/index.html @@ -31,7 +31,7 @@ - + @@ -39,7 +39,7 @@ - + @@ -57,11 +57,11 @@ "@context": "https://schema.org", "@type": "WebSite", "name": "天远数据", - "url": "https://www.zhinengcha.cn/", + "url": "https://www.tianyuandb.com/", "description": "专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用", "potentialAction": { "@type": "SearchAction", - "target": "https://www.zhinengcha.cn/search?q={search_term_string}", + "target": "https://www.tianyuandb.com/search?q={search_term_string}", "query-input": "required name=search_term_string" } } @@ -72,7 +72,7 @@ "@context": "https://schema.org", "@type": "Organization", "name": "天远数据", - "url": "https://www.zhinengcha.cn/", + "url": "https://www.tianyuandb.com/", "description": "专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用" } @@ -84,9 +84,9 @@ - + - + + + +
+

邀请合作伙伴_发展代理享收益_推广返利计划_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据推出合伙人邀请奖励机制。邀请好友注册成为合作伙伴,每单不仅可获得推广收益,还可叠加合作伙伴活跃奖励及定价差额收益。打造专属推广团队,实现收益持续增长。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/agent-promote.html b/public/seo-templates/agent-promote.html new file mode 100644 index 0000000..70f3216 --- /dev/null +++ b/public/seo-templates/agent-promote.html @@ -0,0 +1,80 @@ + + + + + + + + 生成推广码_自定义价格_0成本代理查价系统_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

生成推广码_自定义价格_0成本代理查价系统_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据推广中心支持代理自主设置报告价格。在此选择报告类型,自定义客户查询价,0成本生成专属推广链接或二维码。差价即为利润,实现个人风险报告的私域流量变现。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/agent.html b/public/seo-templates/agent.html new file mode 100644 index 0000000..aef9a32 --- /dev/null +++ b/public/seo-templates/agent.html @@ -0,0 +1,80 @@ + + + + + + + + 天远数据代理 - 免费开通代理权限 | 大数据风险报告代理 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

天远数据代理 - 免费开通代理权限 | 大数据风险报告代理

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/example.html b/public/seo-templates/example.html new file mode 100644 index 0000000..14ce52b --- /dev/null +++ b/public/seo-templates/example.html @@ -0,0 +1,80 @@ + + + + + + + + 示例报告 - 天远数据报告展示 | 大数据风险报告样例 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

示例报告 - 天远数据报告展示 | 大数据风险报告样例

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/help-guide.html b/public/seo-templates/help-guide.html new file mode 100644 index 0000000..c5496de --- /dev/null +++ b/public/seo-templates/help-guide.html @@ -0,0 +1,80 @@ + + + + + + + + 使用指南 - 天远数据操作教程 | 功能说明 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

使用指南 - 天远数据操作教程 | 功能说明

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/help.html b/public/seo-templates/help.html new file mode 100644 index 0000000..2c600ff --- /dev/null +++ b/public/seo-templates/help.html @@ -0,0 +1,80 @@ + + + + + + + + 天远数据帮助中心_代理操作指南_推广收益计算常见问题 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

天远数据帮助中心_代理操作指南_推广收益计算常见问题

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据帮助中心提供全方位的代理操作指引。包含如何成为代理、推广报告生成教程、收益与成本计算规则及推广效率提升方案。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/historyQuery.html b/public/seo-templates/historyQuery.html new file mode 100644 index 0000000..7667b9c --- /dev/null +++ b/public/seo-templates/historyQuery.html @@ -0,0 +1,80 @@ + + + + + + + + 我的报告_历史查询记录_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

我的报告_历史查询记录_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据用户个人中心,查看及下载历史查询报告。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/index.html b/public/seo-templates/index.html new file mode 100644 index 0000000..a205061 --- /dev/null +++ b/public/seo-templates/index.html @@ -0,0 +1,80 @@ + + + + + + + + 天远数据_背调报告代理加盟_个人风控系统搭建_合规数据服务平台 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

天远数据_背调报告代理加盟_个人风控系统搭建_合规数据服务平台

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据提供低成本的风控系统搭建服务。一键开通独立代理后台,支持自定义品牌与报告价格。平台基于公开合法数据,支持一键生成综合素质报告。诚邀行业合作伙伴,共享数字化风控红利,助力流量合规变现。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-backgroundcheck.html b/public/seo-templates/inquire-backgroundcheck.html new file mode 100644 index 0000000..667e5cd --- /dev/null +++ b/public/seo-templates/inquire-backgroundcheck.html @@ -0,0 +1,80 @@ + + + + + + + + 入职背景核验_候选人履历核验_职场信用与竞业排查_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

入职背景核验_候选人履历核验_职场信用与竞业排查_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据职场风险报告助力企业构建防御体系。基于司法级大数据,一键筛查候选人司法涉诉记录、学历信息、商业利益冲突、历史违约记录及不良社会风险。官方数据,客观预警入职风险,辅助HR高效决策。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-companyinfo.html b/public/seo-templates/inquire-companyinfo.html new file mode 100644 index 0000000..eb7232e --- /dev/null +++ b/public/seo-templates/inquire-companyinfo.html @@ -0,0 +1,80 @@ + + + + + + + + 企业信用风险评估_工商经营异常与司法诉讼核查_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

企业信用风险评估_工商经营异常与司法诉讼核查_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据提供全维度的企业商业画像。基于官方公示数据,核验目标企业的工商变更、经营异常名录、行政处罚、投融资背景及关联风险。深度评估商业履约能力,透视合作方真实状况,规避合同陷阱。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-homeservice.html b/public/seo-templates/inquire-homeservice.html new file mode 100644 index 0000000..1eac4a1 --- /dev/null +++ b/public/seo-templates/inquire-homeservice.html @@ -0,0 +1,80 @@ + + + + + + + + 家政人员背景核实_保姆月嫂司法风险筛查_用工安全评估_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

家政人员背景核实_保姆月嫂司法风险筛查_用工安全评估_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据家政风险报告,为家庭用人安全把关。通过合法大数据,快速筛查家政人员的司法诉讼、失信被执行记录及社会不良风险标签。有效识别潜在隐患,预防雇佣纠纷,让您找保姆、请月嫂更放心。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-marriage.html b/public/seo-templates/inquire-marriage.html new file mode 100644 index 0000000..de0a14a --- /dev/null +++ b/public/seo-templates/inquire-marriage.html @@ -0,0 +1,80 @@ + + + + + + + + 婚恋对象背景了解_司法诉讼与不良记录筛查_婚前风险评估_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

婚恋对象背景了解_司法诉讼与不良记录筛查_婚前风险评估_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据提供专业的婚恋风险评估工具。基于合法的公开司法数据,深度排查法律诉讼记录、失信被执行信息及潜在的履约风险。数据来源合规,仅供个人防范参考,拒绝隐私泄露,为幸福保驾护航。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-personalData.html b/public/seo-templates/inquire-personalData.html new file mode 100644 index 0000000..f407cf8 --- /dev/null +++ b/public/seo-templates/inquire-personalData.html @@ -0,0 +1,80 @@ + + + + + + + + 个人综合风险报告_个人履约评分_多维数据检测_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

个人综合风险报告_个人履约评分_多维数据检测_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据提供个人全维信用画像扫描。一键检测司法涉诉记录、历史履约情况、号码状态异常检测及个人消费等级。数据同步权威行业系统,采用银行级加密技术,保障信息安全,助您全面了解自身信用状况。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/inquire-preloanbackgroundcheck.html b/public/seo-templates/inquire-preloanbackgroundcheck.html new file mode 100644 index 0000000..8e18186 --- /dev/null +++ b/public/seo-templates/inquire-preloanbackgroundcheck.html @@ -0,0 +1,80 @@ + + + + + + + + 综合履约评分检测_多平台履约记录分析_个人财务履约报告_天远数据 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

综合履约评分检测_多平台履约记录分析_个人财务履约报告_天远数据

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/seo-templates/service.html b/public/seo-templates/service.html new file mode 100644 index 0000000..e298da9 --- /dev/null +++ b/public/seo-templates/service.html @@ -0,0 +1,80 @@ + + + + + + + + 客服中心 - 天远数据在线客服 | 技术支持 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

客服中心 - 天远数据在线客服 | 技术支持

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

天远数据客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+ +
+
+ + \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml index 261c820..03520b3 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -1,67 +1,67 @@ - https://www.zhinengcha.cn/ + https://www.tianyuandb.com/ 2025-08-01 daily 1.0 - https://www.zhinengcha.cn/agent + https://www.tianyuandb.com/agent 2025-08-01 weekly 0.8 - https://www.zhinengcha.cn/help + https://www.tianyuandb.com/help 2025-08-01 monthly 0.7 - https://www.zhinengcha.cn/help/guide + https://www.tianyuandb.com/help/guide 2025-08-01 monthly 0.6 - https://www.zhinengcha.cn/example + https://www.tianyuandb.com/example 2025-08-01 monthly 0.6 - https://www.zhinengcha.cn/service + https://www.tianyuandb.com/service 2025-08-01 monthly 0.5 - https://www.zhinengcha.cn/privacyPolicy + https://www.tianyuandb.com/privacyPolicy 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/userAgreement + https://www.tianyuandb.com/userAgreement 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/agentManageAgreement + https://www.tianyuandb.com/agentManageAgreement 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/agentSerivceAgreement + https://www.tianyuandb.com/agentSerivceAgreement 2025-08-01 yearly 0.3 - https://www.zhinengcha.cn/authorization + https://www.tianyuandb.com/authorization 2025-08-01 yearly 0.3 diff --git a/server/README-SEO.md b/server/README-SEO.md new file mode 100644 index 0000000..abe3e6a --- /dev/null +++ b/server/README-SEO.md @@ -0,0 +1,350 @@ +# SPA SEO 优化解决方案 + +## 📋 方案概述 + +针对 SPA 应用 SEO 问题,采用**爬虫检测 + 静态 HTML 回退**方案: + +1. **爬虫检测**:识别搜索引擎爬虫(百度、Google、必应、搜狗等) +2. **静态 HTML**:为爬虫提供预渲染的 HTML 模板,包含完整 TDK、OG、canonical、结构化数据 +3. **正常用户**:继续使用 SPA,体验不受影响 + +**配置统一**:服务端 SEO 模板内容与前端 `src/composables/useSEO.js` 保持一致(标题、描述、关键词、域名),域名默认为 `https://www.tianyuandb.com`(天远数据)。 + +## 🏗️ 项目结构 + +``` +server/ +├── crawler-detector.js # 爬虫检测模块 +├── middleware.js # SEO 中间件(Express/Koa),路由与 useSEO.js 一致 +├── generate-seo-templates.cjs # SEO 模板生成器(与 useSEO.js 同步) +├── server-example-express.js # Express 服务器示例 +├── nginx-www.tianyuandb.com.conf # 天远数据 Nginx 配置(tianyuandb.com) +├── nginx-www.xingfucha.cn.conf # 幸福查 Nginx 配置示例 +├── nginx-seo-location-替换片段.conf # Nginx SEO 片段 +├── test-seo.js # SEO 端到端检测脚本 +└── README-SEO.md # 本文档 + +public/ +└── seo-templates/ # SEO 静态模板目录(运行 generate 后生成) + ├── index.html + ├── historyQuery.html + ├── agent.html + ├── agent-promote.html + ├── agent-invitation.html + ├── help.html + ├── help-guide.html + ├── example.html + ├── service.html + ├── inquire-personalData.html + └── ... # 其他 inquire 等模板 +``` + +## 🚀 快速开始 + +### 步骤1:生成 SEO 模板 + +```bash +cd server +node generate-seo-templates.cjs +# 或 npm run generate +``` + +这会在 `public/seo-templates/` 下生成所有页面的静态 HTML 模板,内容与 `src/composables/useSEO.js` 一致。 + +### 步骤2:集成到你的服务器 + +#### 选项A:使用Express服务器 + +```javascript +const express = require('express') +const SEOMiddleware = require('./server/middleware') + +const app = express() + +// 初始化SEO中间件 +const seoMiddleware = new SEOMiddleware({ + templateDir: path.join(__dirname, 'public/seo-templates'), + debug: true // 开发环境开启调试日志 +}) + +// 应用SEO中间件(必须在静态文件服务之前) +app.use(seoMiddleware.express()) + +// 静态文件服务 +app.use(express.static(path.join(__dirname, 'dist'))) + +// SPA路由处理 +app.get('*', (req, res) => { + res.sendFile(path.join(__dirname, 'dist/index.html')) +}) +``` + +#### 选项B:使用 Nginx + +- 天远数据站点:参考 `server/nginx-www.tianyuandb.com.conf`,将 `root` 和 `server_name`、证书路径改为你的服务器路径。 +- 幸福查站点:参考 `server/nginx-www.xingfucha.cn.conf`。 +- 部署时把 `public/seo-templates/` 整目录上传到服务器 `root` 下的 `seo-templates/`。 + +```bash +# 复制并修改配置 +cp server/nginx-www.tianyuandb.com.conf /etc/nginx/sites-available/zhinengcha +nano /etc/nginx/sites-available/zhinengcha # 修改 root、证书等 + +# 启用并重载 +ln -s /etc/nginx/sites-available/zhinengcha /etc/nginx/sites-enabled/ +nginx -t && systemctl restart nginx +``` + +#### 选项C:使用Koa + +```javascript +const Koa = require('koa') +const serve = require('koa-static') +const SEOMiddleware = require('./server/middleware') + +const app = new Koa() + +// 应用SEO中间件 +const seoMiddleware = new SEOMiddleware({ + templateDir: path.join(__dirname, 'public/seo-templates'), + debug: true +}) + +app.use(seoMiddleware.koa()) + +// 静态文件服务 +app.use(serve(path.join(__dirname, 'dist'))) + +app.listen(3000) +``` + +### 步骤3:测试爬虫检测 + +```bash +# 模拟百度爬虫 +curl -A "Baiduspider" http://localhost:3000/ + +# 模拟Google爬虫 +curl -A "Googlebot/2.1" http://localhost:3000/ + +# 模拟普通用户 +curl http://localhost:3000/ +``` + +## 🔧 配置说明 + +### 爬虫检测器配置 + +`crawler-detector.js` 包含以下爬虫识别: + +- **中文搜索引擎**:百度、360、搜狗、必应、有道、搜搜、头条搜索 +- **国际搜索引擎**:Google、Bing、Yahoo +- **社交媒体爬虫**:Facebook、Twitter、LinkedIn、WhatsApp等 + +你可以根据需要添加或修改爬虫模式: + +```javascript +// 在crawler-detector.js中添加新的爬虫模式 +this.crawlerPatterns.push('your-custom-bot') +``` + +### 路由到模板映射 + +在 `middleware.js` 中配置路由与模板的对应关系: + +```javascript +this.routeTemplateMap = { + '/': 'index.html', + '/agent': 'agent.html', + // 添加新的路由映射 + '/new-route': 'new-template.html' +} +``` + +### 模板生成配置 + +**推荐**:页面 SEO 以 `src/composables/useSEO.js` 为唯一来源;修改标题/描述/关键词时只改 `useSEO.js` 中的 `routeConfigs`,然后同步到服务端: + +- 在 `server/generate-seo-templates.cjs` 的 `pageSEOConfigs` 中保持与 `useSEO.js` 一致(含新增路由与 `BASE_URL`)。 +- 在 `server/middleware.js` 的 `routeTemplateMap` 中为新路由添加映射。 +- 若用 Nginx,在对应 conf 的 `$seo_file` 中增加 `if ($uri = '/新路径') { set $seo_file 新模板.html; }`。 + +新增页面示例(`generate-seo-templates.cjs`): + +```javascript +'new-template.html': { + title: '页面标题', + description: '页面描述', + keywords: '关键词1,关键词2', + url: 'https://www.tianyuandb.com/new-route' +} +``` + +## 📝 自定义模板 + +### 修改模板样式 + +编辑 `generate-seo-templates.js` 中的 `generateHTMLTemplate` 函数: + +```javascript +function generateHTMLTemplate(config) { + return ` + + + + + + + + + ` +} +``` + +### 添加结构化数据 + +模板已包含基本的结构化数据(JSON-LD格式),如需扩展: + +```javascript +const structuredData = { + "@context": "https://schema.org", + "@type": "WebPage", + // 添加更多字段 + "breadcrumb": { + "@type": "BreadcrumbList", + "itemListElement": [...] + } +} +``` + +## 🧪 验证SEO效果 + +### 使用在线工具 + +1. **百度资源平台**:https://ziyuan.baidu.com/ +2. **Google Search Console**:https://search.google.com/search-console +3. **必应网站管理员工具**:https://www.bing.com/webmasters + +### 使用命令行工具与检测脚本 + +```bash +# 本地/线上 SEO 检测(会请求爬虫 UA 与普通 UA) +cd server +SEO_TEST_URL=http://localhost:3000 node test-seo.js +# 或线上:SEO_TEST_URL=https://www.tianyuandb.com node test-seo.js +``` + +```bash +# 查看爬虫看到的标题 +curl -s -A "Baiduspider/2.0" https://www.tianyuandb.com/ | grep -o '.*' + +# 检查 meta 与 canonical +curl -s -A "Googlebot" https://www.tianyuandb.com/ | grep -E ' { + return userAgent.includes(pattern.toLowerCase()) + }) + } + + /** + * 检查请求头 + * @param {Object} headers + * @returns {Boolean} + */ + checkHeaders(headers) { + for (const header of this.crawlerHeaders) { + const headerValue = headers[header]?.toLowerCase() + if (headerValue && (headerValue.includes('bot') || headerValue.includes('crawler'))) { + return true + } + } + return false + } + + /** + * 检查IP地址是否为已知爬虫IP + * @param {String} ip + * @returns {Boolean} + */ + checkIP(ip) { + // 这里可以添加已知爬虫IP段的检测 + // 需要定期更新爬虫IP列表 + return false + } + + /** + * 获取爬虫类型 + * @param {String} userAgent + * @returns {String} 爬虫类型 + */ + getCrawlerType(userAgent) { + const ua = userAgent.toLowerCase() + + if (ua.includes('baiduspider')) return 'baidu' + if (ua.includes('googlebot')) return 'google' + if (ua.includes('bingbot') || ua.includes('msnbot')) return 'bing' + if (ua.includes('360spider')) return '360' + if (ua.includes('sogou spider')) return 'sogou' + if (ua.includes('facebookexternalhit')) return 'facebook' + if (ua.includes('twitterbot')) return 'twitter' + if (ua.includes('linkedinbot')) return 'linkedin' + + return 'unknown' + } +} + +module.exports = CrawlerDetector diff --git a/server/generate-seo-templates.cjs b/server/generate-seo-templates.cjs new file mode 100644 index 0000000..39e61ff --- /dev/null +++ b/server/generate-seo-templates.cjs @@ -0,0 +1,245 @@ +/** + * SEO模板生成器 + * 根据 useSEO.js 的页面配置自动生成静态 HTML 模板,供爬虫访问时返回 + * 配置与 src/composables/useSEO.js 保持一致 + * + * 多站点:通过环境变量 SEO_BASE_URL 指定 canonical/og:url 域名后生成 + * 例:SEO_BASE_URL=https://www.tianyuandb.com node generate-seo-templates.cjs + */ + +const fs = require('fs') +const path = require('path') + +const BASE_URL = process.env.SEO_BASE_URL || 'https://www.tianyuandb.com' + +// 页面 SEO 配置(与 useSEO.js 的 routeConfigs 保持一致) +const pageSEOConfigs = { + 'index.html': { + title: '天远数据_背调报告代理加盟_个人风控系统搭建_合规数据服务平台', + description: '天远数据提供低成本的风控系统搭建服务。一键开通独立代理后台,支持自定义品牌与报告价格。平台基于公开合法数据,支持一键生成综合素质报告。诚邀行业合作伙伴,共享数字化风控红利,助力流量合规变现。', + keywords: '天远数据,职场背调,风险核验报告,家政背景核验,第三方背调,企业风控服务,数据报告分销', + url: BASE_URL + }, + 'historyQuery.html': { + title: '我的报告_历史查询记录_天远数据', + description: '天远数据用户个人中心,查看及下载历史查询报告。', + keywords: '我的报告,历史记录,天远数据', + url: `${BASE_URL}/historyQuery` + }, + 'inquire-personalData.html': { + title: '个人综合风险报告_个人履约评分_多维数据检测_天远数据', + description: '天远数据提供个人全维信用画像扫描。一键检测司法涉诉记录、历史履约情况、号码状态异常检测及个人消费等级。数据同步权威行业系统,采用银行级加密技术,保障信息安全,助您全面了解自身信用状况。', + keywords: '个人风险评估,信用状况评估,综合履约能力,司法风险自查,风险标签检测', + url: `${BASE_URL}/inquire/personalData` + }, + 'inquire-companyinfo.html': { + title: '企业信用风险评估_工商经营异常与司法诉讼核查_天远数据', + description: '天远数据提供全维度的企业商业画像。基于官方公示数据,核验目标企业的工商变更、经营异常名录、行政处罚、投融资背景及关联风险。深度评估商业履约能力,透视合作方真实状况,规避合同陷阱。', + keywords: '企业信用画像,公司经营风险,工商异常名录,企业履约评估,商业背景核验', + url: `${BASE_URL}/inquire/companyinfo` + }, + 'inquire-preloanbackgroundcheck.html': { + title: '综合履约评分检测_多平台履约记录分析_个人财务履约报告_天远数据', + description: '天远数据提供专业的个人履约健康度体检服务。基于多维大数据分析,检测您的综合评分波动、历史履约记录及潜在的风险标签。本服务旨在帮助用户优化个人数据画像,提升信用管理意识,不提供任何信贷金融服务。', + keywords: '综合评分检测,多重履约压力分析,履约能力评估,综合评分优化,个人数据画像', + url: `${BASE_URL}/inquire/preloanbackgroundcheck` + }, + 'inquire-marriage.html': { + title: '婚恋对象背景了解_司法诉讼与不良记录筛查_婚前风险评估_天远数据', + description: '天远数据提供专业的婚恋风险评估工具。基于合法的公开司法数据,深度排查法律诉讼记录、失信被执行信息及潜在的履约风险。数据来源合规,仅供个人防范参考,拒绝隐私泄露,为幸福保驾护航。', + keywords: '婚恋背景核验,婚前风险了解,司法记录核验,个人履约风险,背景核实', + url: `${BASE_URL}/inquire/marriage` + }, + 'inquire-backgroundcheck.html': { + title: '入职背景核验_候选人履历核验_职场信用与竞业排查_天远数据', + description: '天远数据职场风险报告助力企业构建防御体系。基于司法级大数据,一键筛查候选人司法涉诉记录、学历信息、商业利益冲突、历史违约记录及不良社会风险。官方数据,客观预警入职风险,辅助HR高效决策。', + keywords: '入职风险评估,候选人背景核验,简历真伪辨别,竞业限制核验,职场信用报告,员工风险预警', + url: `${BASE_URL}/inquire/backgroundcheck` + }, + 'inquire-homeservice.html': { + title: '家政人员背景核实_保姆月嫂司法风险筛查_用工安全评估_天远数据', + description: '天远数据家政风险报告,为家庭用人安全把关。通过合法大数据,快速筛查家政人员的司法诉讼、失信被执行记录及社会不良风险标签。有效识别潜在隐患,预防雇佣纠纷,让您找保姆、请月嫂更放心。', + keywords: '保姆背景核验,月嫂风险筛查,家政人员核验,育儿嫂背景核实,雇佣风险防范', + url: `${BASE_URL}/inquire/homeservice` + }, + 'agent.html': { + title: '天远数据代理 - 免费开通代理权限 | 大数据风险报告代理', + description: '天远数据代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。', + keywords: '天远数据代理, 免费代理, 大数据风险报告代理, 代理权限, 代理收益', + url: `${BASE_URL}/agent` + }, + 'agent-promote.html': { + title: '生成推广码_自定义价格_0成本代理查价系统_天远数据', + description: '天远数据推广中心支持代理自主设置报告价格。在此选择报告类型,自定义客户查询价,0成本生成专属推广链接或二维码。差价即为利润,实现个人风险报告的私域流量变现。', + keywords: '推广码生成,自定义查价系统,代理收益工具,代理推广链接,流量变现平台,天远数据推广', + url: `${BASE_URL}/agent/promote` + }, + 'agent-invitation.html': { + title: '邀请合作伙伴_发展代理享收益_推广返利计划_天远数据', + description: '天远数据推出合伙人邀请奖励机制。邀请好友注册成为合作伙伴,每单不仅可获得推广收益,还可叠加合作伙伴活跃奖励及定价差额收益。打造专属推广团队,实现收益持续增长。', + keywords: '渠道合作伙伴,商业收益管理,流量合规变现,业务推广系统,代理后台', + url: `${BASE_URL}/agent/invitation` + }, + 'help.html': { + title: '天远数据帮助中心_代理操作指南_推广收益计算常见问题', + description: '天远数据帮助中心提供全方位的代理操作指引。包含如何成为代理、推广报告生成教程、收益与成本计算规则及推广效率提升方案。', + keywords: '天远数据教程,代理新手指南,推广收益计算,报告推广', + url: `${BASE_URL}/help` + }, + 'help-guide.html': { + title: '使用指南 - 天远数据操作教程 | 功能说明', + description: '天远数据详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。', + keywords: '使用指南, 操作教程, 功能说明, 快速上手, 天远数据教程', + url: `${BASE_URL}/help/guide` + }, + 'example.html': { + title: '示例报告 - 天远数据报告展示 | 大数据风险报告样例', + description: '天远数据示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。', + keywords: '示例报告, 报告展示, 报告样例, 大数据风险报告, 婚姻查询报告', + url: `${BASE_URL}/example` + }, + 'service.html': { + title: '客服中心 - 天远数据在线客服 | 技术支持', + description: '天远数据客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。', + keywords: '客服中心, 在线客服, 技术支持, 问题反馈, 天远数据客服', + url: `${BASE_URL}/service` + } +} + +/** + * 规范化文案:统一为中文标点,避免乱码 + */ +function normalizeText(str) { + if (typeof str !== 'string') return str + return str + .replace(/\uFFFD/g, '') + .replace(/。/g, '。') + .replace(/、/g, '、') +} + +/** + * 转义 HTML 属性值 + */ +function escapeAttr(str) { + if (typeof str !== 'string') return '' + return str + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>') +} + +/** + * 生成单页 HTML 模板 + */ +function generateHTMLTemplate(config) { + const title = normalizeText(config.title) + const description = normalizeText(config.description) + const keywords = normalizeText(config.keywords) + const structuredData = { + '@context': 'https://schema.org', + '@type': 'WebPage', + name: title, + description: description, + url: config.url, + mainEntity: { + '@type': 'Organization', + name: '天远数据', + url: 'https://www.tianyuandb.com/', + description: '专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用' + } + } + + return ` + + + + + + + ${escapeAttr(title)} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

${escapeAttr(title)}

+
+

正在跳转到完整版网站...

+

如果浏览器没有自动跳转,请 点击这里

+
+

${escapeAttr(description)}

+
+

关于天远数据

+

天远数据提供背调报告代理加盟与个人风控系统搭建,合规数据服务平台。支持职场背调、家政背景核验、企业风控服务与数据报告分销。

+
+
+

核心服务

+
    +
  • 个人综合风险报告与履约评分
  • +
  • 企业信用风险评估与工商核查
  • +
  • 综合履约评分与贷前风险检测
  • +
  • 婚恋对象背景了解与婚前风险评估
  • +
  • 入职背景核验与职场信用排查
  • +
  • 家政人员背景核实与用工安全评估
  • +
+
+
+ +` +} + +function main() { + const outputDir = path.join(__dirname, '../public/seo-templates') + + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }) + console.log(`✓ 创建模板目录: ${outputDir}`) + } + + let successCount = 0 + Object.entries(pageSEOConfigs).forEach(([filename, config]) => { + const htmlContent = generateHTMLTemplate(config) + const filePath = path.join(outputDir, filename) + fs.writeFileSync(filePath, htmlContent, 'utf-8') + console.log(`✓ 生成模板: ${filename}`) + successCount++ + }) + + console.log(`\n✓ 成功生成 ${successCount} 个 SEO 模板文件`) + console.log(`📁 模板目录: ${outputDir}`) + console.log(`💡 配置与 useSEO.js 一致,当前域名: ${BASE_URL}`) +} + +main() diff --git a/server/middleware.js b/server/middleware.js new file mode 100644 index 0000000..0e5dc7e --- /dev/null +++ b/server/middleware.js @@ -0,0 +1,179 @@ +/** + * SEO中间件 + * 用于在Node.js服务器中检测爬虫并返回静态HTML + */ + +const fs = require('fs') +const path = require('path') +const CrawlerDetector = require('./crawler-detector') + +class SEOMiddleware { + constructor(options = {}) { + this.detector = new CrawlerDetector() + this.templateDir = options.templateDir || path.join(__dirname, '../public/seo-templates') + this.defaultTemplate = options.defaultTemplate || 'index.html' + this.fallbackToSPA = options.fallbackToSPA !== false + this.debug = options.debug || false + + // 路由到模板的映射(与 useSEO.js 及 generate-seo-templates.cjs 保持一致;子路径放前面以优先精确匹配) + this.routeTemplateMap = { + '/': 'index.html', + '/historyQuery': 'historyQuery.html', + '/agent/promote': 'agent-promote.html', + '/agent/invitation': 'agent-invitation.html', + '/agent': 'agent.html', + '/help/guide': 'help-guide.html', + '/help': 'help.html', + '/example': 'example.html', + '/service': 'service.html', + '/inquire/personalData': 'inquire-personalData.html', + '/inquire/companyinfo': 'inquire-companyinfo.html', + '/inquire/preloanbackgroundcheck': 'inquire-preloanbackgroundcheck.html', + '/inquire/marriage': 'inquire-marriage.html', + '/inquire/backgroundcheck': 'inquire-backgroundcheck.html', + '/inquire/homeservice': 'inquire-homeservice.html' + } + + // 初始化模板缓存 + this.templateCache = new Map() + this.cacheTemplates() + } + + /** + * 缓存所有模板文件 + */ + cacheTemplates() { + try { + if (!fs.existsSync(this.templateDir)) { + console.warn(`[SEOMiddleware] 模板目录不存在: ${this.templateDir}`) + return + } + + const files = fs.readdirSync(this.templateDir) + files.forEach(file => { + const filePath = path.join(this.templateDir, file) + if (fs.statSync(filePath).isFile()) { + this.templateCache.set(file, fs.readFileSync(filePath, 'utf-8')) + if (this.debug) { + console.log(`[SEOMiddleware] 已缓存模板: ${file}`) + } + } + }) + + console.log(`[SEOMiddleware] 已缓存 ${this.templateCache.size} 个模板文件`) + } catch (error) { + console.error('[SEOMiddleware] 缓存模板失败:', error) + } + } + + /** + * 获取对应的模板文件名 + * @param {String} path - 请求路径 + * @returns {String} 模板文件名 + */ + getTemplatePath(requestPath) { + // 完全匹配 + if (this.routeTemplateMap[requestPath]) { + return this.routeTemplateMap[requestPath] + } + + // 模糊匹配(处理动态路由) + const matchedKey = Object.keys(this.routeTemplateMap).find(route => { + return requestPath.startsWith(route) + }) + + return matchedKey ? this.routeTemplateMap[matchedKey] : this.defaultTemplate + } + + /** + * 获取模板内容 + * @param {String} templateName - 模板文件名 + * @returns {String|null} 模板内容 + */ + getTemplate(templateName) { + // 首先尝试缓存 + let content = this.templateCache.get(templateName) + + // 如果缓存中没有,尝试从磁盘读取 + if (!content) { + try { + const filePath = path.join(this.templateDir, templateName) + if (fs.existsSync(filePath)) { + content = fs.readFileSync(filePath, 'utf-8') + this.templateCache.set(templateName, content) + } + } catch (error) { + console.error(`[SEOMiddleware] 读取模板失败: ${templateName}`, error) + } + } + + return content || null + } + + /** + * Express中间件 + */ + express() { + return (req, res, next) => { + // 检测是否为爬虫 + if (this.detector.isCrawler(req)) { + const templateName = this.getTemplatePath(req.path) + const template = this.getTemplate(templateName) + + if (template) { + // 设置响应头 + res.setHeader('Content-Type', 'text/html; charset=utf-8') + res.setHeader('X-SEOMiddleware', 'prerendered') + + // 返回静态HTML + if (this.debug) { + console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${req.path}`) + } + + return res.send(template) + } + } + + // 不是爬虫或模板不存在,继续处理SPA + next() + } + } + + /** + * Koa中间件 + */ + koa() { + return async (ctx, next) => { + // 检测是否为爬虫 + if (this.detector.isCrawler(ctx.req)) { + const templateName = this.getTemplatePath(ctx.path) + const template = this.getTemplate(templateName) + + if (template) { + ctx.type = 'text/html; charset=utf-8' + ctx.set('X-SEOMiddleware', 'prerendered') + + if (this.debug) { + console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${ctx.path}`) + } + + ctx.body = template + return + } + } + + await next() + } + } + + /** + * 重新加载模板缓存 + */ + reloadCache() { + this.templateCache.clear() + this.cacheTemplates() + console.log('[SEOMiddleware] 模板缓存已重新加载') + } +} + +module.exports = SEOMiddleware diff --git a/server/nginx-www.tianyuandb.com.conf b/server/nginx-www.tianyuandb.com.conf new file mode 100644 index 0000000..adc20d3 --- /dev/null +++ b/server/nginx-www.tianyuandb.com.conf @@ -0,0 +1,141 @@ +# 天远数据 - www.tianyuandb.com 完整配置(含 SEO 爬虫检测) +# 使用前请将 public/seo-templates 上传到服务器:/www/sites/www.tianyuandb.com/index/seo-templates/ +# 生成 tianyuandb 用模板:SEO_BASE_URL=https://www.tianyuandb.com node generate-seo-templates.cjs + +server { + listen 80; + listen 443 ssl http2; + server_name www.tianyuandb.com tianyuandb.com; + index index.php index.html index.htm default.php default.htm default.html; + root /www/sites/www.tianyuandb.com/index; + + # ========== SEO 爬虫检测与模板映射(请勿删除) ========== + set $is_crawler 0; + if ($http_user_agent ~* "baiduspider|baiduspider-mobile|baiduspider-image|baiduspider-video|baiduspider-news|baiduboxapp") { + set $is_crawler 1; + } + if ($http_user_agent ~* "googlebot|googlebot-image|googlebot-news|googlebot-mobile|googlebot-video|google-web-snippet") { + set $is_crawler 1; + } + if ($http_user_agent ~* "bingbot|msnbot") { + set $is_crawler 1; + } + if ($http_user_agent ~* "360spider|soha-agent|haosouspider") { + set $is_crawler 1; + } + if ($http_user_agent ~* "sogou spider|sogou news spider|sogou orion spider|sogou-blog") { + set $is_crawler 1; + } + if ($http_user_agent ~* "slurp|sosospider|sosoimagespider|youdaobot|yodaobot") { + set $is_crawler 1; + } + if ($http_user_agent ~* "bytedance-spider|toutiaospider") { + set $is_crawler 1; + } + if ($http_user_agent ~* "facebookexternalhit|facebookcatalog|twitterbot|linkedinbot|whatsapp|telegrambot|viber|line") { + set $is_crawler 1; + } + + set $seo_file index.html; + if ($uri = '/') { set $seo_file index.html; } + if ($uri = '/historyQuery') { set $seo_file historyQuery.html; } + if ($uri = '/agent') { set $seo_file agent.html; } + if ($uri = '/agent/promote') { set $seo_file agent-promote.html; } + if ($uri = '/agent/invitation') { set $seo_file agent-invitation.html; } + if ($uri = '/help') { set $seo_file help.html; } + if ($uri = '/help/guide') { set $seo_file help-guide.html; } + if ($uri = '/example') { set $seo_file example.html; } + if ($uri = '/service') { set $seo_file service.html; } + if ($uri = '/inquire/personalData') { set $seo_file inquire-personalData.html; } + if ($uri = '/inquire/companyinfo') { set $seo_file inquire-companyinfo.html; } + if ($uri = '/inquire/preloanbackgroundcheck') { set $seo_file inquire-preloanbackgroundcheck.html; } + if ($uri = '/inquire/marriage') { set $seo_file inquire-marriage.html; } + if ($uri = '/inquire/backgroundcheck') { set $seo_file inquire-backgroundcheck.html; } + if ($uri = '/inquire/homeservice') { set $seo_file inquire-homeservice.html; } + # ========== SEO 配置结束 ========== + + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $http_connection; + + access_log /www/sites/www.tianyuandb.com/log/access.log main; + error_log /www/sites/www.tianyuandb.com/log/error.log; + + location ^~ /.well-known/acme-challenge { + allow all; + root /usr/share/nginx/html; + } + + # SEO:爬虫访问时返回静态 HTML 模板 + location /seo-templates/ { + internal; + add_header Content-Type "text/html; charset=utf-8"; + add_header X-SEOMiddleware "nginx-prerendered"; + } + + location / { + if ($is_crawler = 1) { + rewrite ^ /seo-templates/$seo_file break; + } + try_files $uri $uri/ /index.html; + } + + location /api/v1 { + proxy_pass http://127.0.0.1:21004; + proxy_set_header Host 127.0.0.1:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + add_header X-Cache $upstream_cache_status; + proxy_set_header X-Host $host:$server_port; + proxy_set_header X-Scheme $scheme; + proxy_connect_timeout 30s; + proxy_read_timeout 86400s; + proxy_send_timeout 30s; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location ^~ /api/v1/chat { + resolver 8.8.8.8 114.114.114.114 valid=10s; + resolver_timeout 5s; + set $backend "chat.guimiaokeji.com"; + rewrite ^/api/v1/(.*)$ /$1 break; + proxy_pass https://$backend; + proxy_set_header Host $backend; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_http_version 1.1; + add_header X-Cache $upstream_cache_status; + add_header Cache-Control no-cache; + proxy_ssl_server_name off; + proxy_buffering off; + } + + error_page 404 /404.html; + add_header Strict-Transport-Security "max-age=31536000"; + include /www/sites/www.tianyuandb.com/redirect/*.conf; + + if ($scheme = http) { + return 301 https://$host$request_uri; + } + + ssl_certificate /www/sites/www.tianyuandb.com/ssl/fullchain.pem; + ssl_certificate_key /www/sites/www.tianyuandb.com/ssl/privkey.pem; + ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1; + ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + error_page 497 https://$host$request_uri; + proxy_set_header X-Forwarded-Proto https; +} diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..dbb7c3e --- /dev/null +++ b/server/package.json @@ -0,0 +1,27 @@ +{ + "name": "tydata-seo-server", + "version": "1.0.0", + "description": "SPA SEO 优化 - 爬虫检测与静态 HTML 回退,与 useSEO.js 同步", + "main": "server-example-express.js", + "scripts": { + "start": "node server-example-express.js", + "dev": "node server-example-express.js", + "generate": "node generate-seo-templates.cjs", + "test": "node test-seo.js", + "test:crawler": "node test-crawler-detection.js" + }, + "keywords": [ + "seo", + "crawler", + "spa", + "prerender" + ], + "license": "MIT", + "dependencies": { + "express": "^4.18.2", + "compression": "^1.7.4" + }, + "devDependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/server/server-example-express.js b/server/server-example-express.js new file mode 100644 index 0000000..811d63e --- /dev/null +++ b/server/server-example-express.js @@ -0,0 +1,36 @@ +/** + * Express服务器示例 + * 展示如何集成SEO中间件 + */ + +const express = require('express') +const path = require('path') +const SEOMiddleware = require('./middleware') + +const app = express() +const port = process.env.PORT || 3000 + +// 初始化SEO中间件 +const seoMiddleware = new SEOMiddleware({ + templateDir: path.join(__dirname, '../public/seo-templates'), + debug: process.env.NODE_ENV === 'development' +}) + +// 应用SEO中间件(必须在静态文件服务之前) +app.use(seoMiddleware.express()) + +// 静态文件服务 +app.use(express.static(path.join(__dirname, '../dist'))) + +// SPA路由处理 +app.get('*', (req, res) => { + res.sendFile(path.join(__dirname, '../dist/index.html')) +}) + +// 启动服务器 +app.listen(port, () => { + console.log(`🚀 服务器运行在 http://localhost:${port}`) + console.log(`🔍 SEO中间件已启用`) +}) + +module.exports = app diff --git a/server/test-crawler-detection.js b/server/test-crawler-detection.js new file mode 100644 index 0000000..d494d78 --- /dev/null +++ b/server/test-crawler-detection.js @@ -0,0 +1,112 @@ +/** + * 爬虫检测测试脚本 + * 用于验证爬虫检测功能是否正常工作 + */ + +const CrawlerDetector = require('./crawler-detector') + +const detector = new CrawlerDetector() + +// 测试用例 +const testCases = [ + // 爬虫User-Agent + { userAgent: 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)', expected: true, description: '百度爬虫' }, + { userAgent: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', expected: true, description: 'Google爬虫' }, + { userAgent: 'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)', expected: true, description: '必应爬虫' }, + { userAgent: 'Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)', expected: true, description: '搜狗爬虫' }, + { userAgent: '360Spider', expected: true, description: '360爬虫' }, + { userAgent: 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)', expected: true, description: 'Facebook爬虫' }, + { userAgent: 'Twitterbot/1.0', expected: true, description: 'Twitter爬虫' }, + { userAgent: 'LinkedInBot/1.0 (compatible; Mozilla/5.0; +https://www.linkedin.com/help/linkedin/answer/8665)', expected: true, description: 'LinkedIn爬虫' }, + + // 正常浏览器User-Agent + { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', expected: false, description: 'Chrome浏览器' }, + { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0', expected: false, description: 'Firefox浏览器' }, + { userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15', expected: false, description: 'Safari浏览器' }, + { userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1', expected: false, description: 'iPhone Safari' }, + { userAgent: 'Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36', expected: false, description: 'Android Chrome' }, + { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0', expected: false, description: 'Edge浏览器' }, + + // 边界情况 + { userAgent: '', expected: false, description: '空User-Agent' }, + { userAgent: 'Mozilla/5.0 (compatible; MyBot/1.0)', expected: true, description: '包含bot关键词' }, + { userAgent: 'Mozilla/5.0 (compatible; Spider/1.0)', expected: true, description: '包含spider关键词' }, + { userAgent: 'Mozilla/5.0 (compatible; Crawler/1.0)', expected: true, description: '包含crawler关键词' } +] + +console.log('='.repeat(70)) +console.log('爬虫检测测试') +console.log('='.repeat(70)) +console.log() + +let passed = 0 +let failed = 0 + +testCases.forEach((testCase, index) => { + const req = { + headers: { + 'user-agent': testCase.userAgent + } + } + + const result = detector.isCrawler(req) + const success = result === testCase.expected + const status = success ? '✓ 通过' : '✗ 失败' + const crawlerType = result ? detector.getCrawlerType(testCase.userAgent) : 'N/A' + + if (success) { + passed++ + console.log(`${status} 测试 ${index + 1}: ${testCase.description}`) + } else { + failed++ + console.error(`${status} 测试 ${index + 1}: ${testCase.description}`) + console.error(` User-Agent: ${testCase.userAgent.substring(0, 80)}...`) + console.error(` 预期: ${testCase.expected}, 实际: ${result}`) + } + + if (result) { + console.log(` 识别为: ${crawlerType} 爬虫`) + } +}) + +console.log() +console.log('='.repeat(70)) +console.log(`测试结果: ${passed} 通过, ${failed} 失败, 共 ${testCases.length} 个测试`) +console.log('='.repeat(70)) +console.log() + +// 测试爬虫类型识别 +console.log('爬虫类型识别测试:') +console.log('-'.repeat(70)) + +const crawlerTypes = [ + { userAgent: 'Baiduspider', expected: 'baidu', description: '百度爬虫' }, + { userAgent: 'Googlebot', expected: 'google', description: 'Google爬虫' }, + { userAgent: 'bingbot', expected: 'bing', description: '必应爬虫' }, + { userAgent: '360spider', expected: '360', description: '360爬虫' }, + { userAgent: 'sogou spider', expected: 'sogou', description: '搜狗爬虫' }, + { userAgent: 'facebookexternalhit', expected: 'facebook', description: 'Facebook爬虫' }, + { userAgent: 'Twitterbot', expected: 'twitter', description: 'Twitter爬虫' }, + { userAgent: 'linkedinbot', expected: 'linkedin', description: 'LinkedIn爬虫' } +] + +let typePassed = 0 +crawlerTypes.forEach(test => { + const result = detector.getCrawlerType(test.userAgent) + const success = result === test.expected + + if (success) { + typePassed++ + console.log(`✓ ${test.description}: ${result}`) + } else { + console.error(`✗ ${test.description}: 预期 ${test.expected}, 实际 ${result}`) + } +}) + +console.log() +console.log('='.repeat(70)) +console.log(`爬虫类型识别: ${typePassed}/${crawlerTypes.length} 正确`) +console.log('='.repeat(70)) + +// 退出码 +process.exit(failed === 0 ? 0 : 1) diff --git a/server/test-seo.js b/server/test-seo.js new file mode 100644 index 0000000..209c1d7 --- /dev/null +++ b/server/test-seo.js @@ -0,0 +1,178 @@ +/** + * SEO 端到端检测脚本 + * 模拟爬虫与普通用户请求,验证是否返回正确的页面 + * + * 使用前请先启动服务器: npm run start + * 然后运行: npm run test 或 node test-seo.js + */ + +const http = require('http') +const https = require('https') + +const BASE_URL = process.env.SEO_TEST_URL || 'http://localhost:3000' + +// 要检测的路由及期望的 SEO 标题关键词(与 useSEO.js 一致,天远数据) +const ROUTES = [ + { path: '/', titleKeyword: '天远数据' }, + { path: '/agent', titleKeyword: '天远数据代理' }, + { path: '/help', titleKeyword: '天远数据帮助中心' }, + { path: '/inquire/personalData', titleKeyword: '个人综合风险报告' }, + { path: '/agent/promote', titleKeyword: '推广码' }, + { path: '/historyQuery', titleKeyword: '我的报告' } +] + +function request(url, userAgent) { + return new Promise((resolve, reject) => { + const lib = url.startsWith('https') ? https : http + const req = lib.get(url, { + headers: { 'User-Agent': userAgent }, + timeout: 10000 + }, res => { + const chunks = [] + res.on('data', chunk => chunks.push(chunk)) + res.on('end', () => { + resolve({ + statusCode: res.statusCode, + headers: res.headers, + body: Buffer.concat(chunks).toString('utf-8') + }) + }) + }) + req.on('error', reject) + req.on('timeout', () => { + req.destroy() + reject(new Error('请求超时')) + }) + }) +} + +function extractTitle(html) { + const match = html.match(/]*>([^<]+)<\/title>/i) + return match ? match[1].trim() : null +} + +function hasMetaDescription(html) { + return /`、``、``、`` +- 用 **普通浏览器 UA** 再请求一遍,确认仍是 200(SPA 正常) + +全部通过即说明:爬虫拿到的是 SEO 模板,普通用户拿到的是 SPA。 + +--- + +## 二、用 curl 手动检测 + +在服务器已启动的前提下,在终端执行: + +### 爬虫应拿到“带 TDK 的 HTML” + +```bash +# 模拟百度爬虫请求首页 +curl -s -A "Baiduspider/2.0" http://localhost:3000/ | findstr /i "title description keywords canonical" +``` + +应能看到包含「幸福查」的 title,以及 description、keywords、canonical 等标签。 + +```bash +# 看完整 HTML 前几行(含 ) +curl -s -A "Baiduspider/2.0" http://localhost:3000/ | more +``` + +### 普通用户应拿到 SPA(一般是带 script 的 index.html) + +```bash +# 不带爬虫 UA,相当于普通浏览器 +curl -s http://localhost:3000/ | findstr /i "script root app" +``` + +通常会有 `id="app"` 或大量 ` diff --git a/src/views/Promote.vue b/src/views/Promote.vue index 12b9b67..a2cfcfd 100644 --- a/src/views/Promote.vue +++ b/src/views/Promote.vue @@ -93,8 +93,8 @@ const reportTypes = [ { text: "个人大数据", value: "personaldata", id: 27 }, { text: '入职风险', value: 'backgroundcheck', id: 1 }, { text: '家政风险', value: 'homeservice', id: 3 }, - // { text: '婚恋风险', value: 'marriage', id: 4 }, - // { text: '租赁风险', value: 'rentalrisk', id: 6 }, + { text: '婚恋风险', value: 'marriage', id: 4 }, + { text: '租赁风险', value: 'rentalrisk', id: 6 }, ]; const showTypePicker = ref(false); diff --git a/vite.config.js b/vite.config.js index 4cf83c2..d0ebfb0 100644 --- a/vite.config.js +++ b/vite.config.js @@ -15,8 +15,8 @@ export default defineConfig({ strictPort: true, // 如果端口被占用则抛出错误而不是使用下一个可用端口 proxy: { "/api/v1": { - target: "http://127.0.0.1:8888", // 本地接口地址 - // target: "https://www.tianyuandb.com", // 本地接口地址 + // target: "http://127.0.0.1:8888", // 本地接口地址 + target: "https://www.tianyuandb.com", // 本地接口地址 changeOrigin: true, }, },