晋江文学城 SEO 实测:3419 万条 URL,0 条 canonical
晋江文学城交出一份 3,486 个子图、3,419 万条 URL 的站点地图,lastmod 全部停在 2020-10-15,每条作品写三遍;六个模板的 canonical 数量为 0,分类页塞了 16 个 H1。三个维度的实测与十条按优先级排序的改法。
晋江文学城 2003 年上线,站内作品数以十万计,是中文网络文学里体量最大的老站之一。本文实测它的六个页面模板与整份站点地图,结论与内容规模无关:爬虫能拿到的地址比真实页面多出两倍,而页面之间没有一条 canonical 说明谁是谁。
一、三组数字对不上,问题不在内容量
先说实测口径。本次用桌面 UA 匿名抓取六类模板:首页、作品页(《魔道祖师》)、章节页(第 1 章)、言情分类页、移动作品页,以及一个不存在的作品 ID(99999999999)。站点地图取索引文件,并完整解析其中一个子图。全程未登录。
另外用百度、Googlebot、必应三种蜘蛛 UA 复测首页与作品页,四组响应字节数完全一致——没有 UA 分流,所以下面的结论可以外推到引擎侧,不是只对浏览器成立。
三个数字摆在一起,矛盾就出来了:站点地图声明了 34,197,660 条 URL,六个模板的 canonical 数量是 0,分类页一个页面用了 16 个 H1。
站点地图的三层结构
一份 518 KB 的索引文件,指向 3,486 个子图;每个子图 690 KB,含 9,810 条地址;乘起来 3,420 万条,全量下载约 2.24 GB。
| 层级 | 实测规模 | 关键观察 |
|---|---|---|
| 索引文件 | 518,505 B,3,486 条 <sitemap> | 全部 http:// 开头,lastmod 统一为 2020-10-15 |
| 单个子图 | 690,301 B,9,810 条 <loc> | 3,270 个实体 × 3 条地址,子图内 0 条 lastmod |
| 合计 | 34,197,660 条,约 2.24 GB | 唯一实体 11,399,220,重复率 66.7% |
重复率是怎么算出来的
单个子图 9,810 条地址拆开看:http://www.jjwxc.net/oneauthor.php?authorid=N 3,270 条,https://m.jjwxc.net/wapauthor/N 3,270 条,https://wap.jjwxc.net/wapauthor/N 3,270 条。
同一作者被写成三条地址,分别落在三个域名上。3,270 × 3 = 9,810,一个不多一个不少。

图 1 · 索引层给的是 3,486 个入口,条目层给的是三份同一实体;lastmod 只有一个 2020 年的取值
二、3,420 万条 URL 的乘法
索引层:3,486 条地址全是 http
站点早已全站 https,任意 http://www.jjwxc.net/... 都会 301 到 https 版本。但索引文件里 3,486 条子图地址,100% 写的是 http://。
爬虫取一个子图就要多付一次 301。3,486 个子图,就是每轮 3,486 次额外跳转,而这份地图本身没有任何内容更新带动它重取。
条目层:3,420 万条里有 1,139 万条注定被跳转
按上面的三域名结构推,34,197,660 条里恰好三分之一是 http:// 地址。也就是说,仅完成一轮全量抓取,就要多付 11,399,220 次 301,每一次都是没有新信息的往返。
时间戳:3,486 个子图共用一个 2020-10-15
索引层每条 <sitemap> 都带 lastmod,取值只有一个:2020-10-15T13:30:00+08:00。子图内部的 <url> 条目则完全没有 lastmod。
两件事叠起来的后果是:引擎只知道「这 3,486 份地图 6 年前动过」,不知道哪本书昨天更新了。日更数十万字的站点,交出去的是一份静态快照。
三、六个模板,0 条 canonical
六类页面的量化结果如下。体积解码后实测,字符数按去标签、去空白统计。
| 模板 | HTML 体积 | 正文字符 | 字节/字符 | H1 | H2 | canonical | 链接数 | 本站 http:// |
|---|---|---|---|---|---|---|---|---|
| 首页 | 71,927 B | 1,190 | 60.4 | 0 | 5 | 无 | 182 | 1 |
| 作品页 | 372,535 B | 8,208 | 45.4 | 1 | 1 | 无 | 185 | 63 |
| 章节页 | 124,422 B | 5,554 | 22.4 | 1 | 1 | 无 | 137 | 12 |
| 言情分类页 | 1,043,556 B | 19,329 | 54.0 | 16 | 0 | 无 | 2,026 | 7 |
| 移动作品页 | 30,981 B | 1,684 | 18.4 | 0 | 1 | 无 | 66 | 0 |
| 不存在的作品 ID | 39,424 B | 1,039 | 37.9 | 0 | 0 | 无 | 113 | 7 |

图 2 · 体积最大的分类页,也是标题结构最乱的一页;最后一列从上到下都是「无」
三列数字值得单独看:canonical 一列全是「无」;H1 从 0 跳到 16;字节/字符普遍在 40 以上,最重的首页是 60.4。
首页 0 个 H1,分类页 16 个
首页 71,927 B,正文 1,190 字符,没有 H1,5 个 H2 全是导航标签(「完结文库>>」「晋江论坛>>」)。title 是五个字:晋江文学城。
言情分类页反过来:1,043,556 B 一个页面,19,329 字符,同时存在 16 个 H1——「vip金榜」「最新公告」「古代言情」「论坛热贴」各自占了一个。这一页还挂了 2,026 条链接、1,079 本不同的书。
作品页:364 KB 装 127 章
《魔道祖师》作品页 372,535 B,正文 8,208 字符,页面里 127 条章节链接一章不落地铺在同一页,另加 45 张图(其中 20 张没有 alt)。
这页还有 63 条写死的 http:// 本站链接,占全部链接的 34.1%。每一个章节入口点下去,先付一次 301。章节页自己也不轻:124,422 B 换 5,554 字符,另有 12 条明文 http 链接。
两条移动域名,返回同一份字节
m.jjwxc.net 与 wap.jjwxc.net 对同一作者页返回的字节数、MD5 完全相同(20,198 B)。两个主机名、一份内容、两边都没有 canonical,也没有指回 www 的 alternate。
移动作品页有 viewport,桌面模板没有;移动页 H1 数量为 0。适配是做了的,但两个版本之间没有任何声明把它们绑成同一个实体。
四、协议层三处漏点,与十条改法
三种不该出现的响应
未声明即压缩。 作品页与章节页在请求完全不带 Accept-Encoding 的情况下,仍返回 content-encoding: gzip,响应体以 1f 8b 08 开头。首页则明文返回。同一站点两套压缩策略,且两边都没有 Vary: Accept-Encoding,共享缓存无法区分。
软 404 返回 200。 随机路径 /zzz-not-exist-98765 正确返回 404(474 B)。但 /onebook.php?novelid=99999999999 返回 200,39,424 B,页面里连 <title> 都没有,0 个 H1,正文只写「不存在」。状态码 200 让死链在引擎侧成了活页。
robots.txt 的第二组没有主。 文件 93 字节,第一组是 User-agent: * + Allow: / + Sitemap 行;空行之后单独出现两行 Disallow: /sp,没有 User-agent 行。按分组规则,这一组没有适用对象,两条规则不会被任何引擎采纳。实测 /sp/ 返回 403,所以后果有限,但规则本身是废的。
十条改法一览
先给一张总表,按优先级、成本与预期影响排列。后面三节逐条展开。
| 序 | 动作 | 优先级 | 实施成本 | 预期影响 |
|---|---|---|---|---|
| ① | 站点地图去重,每实体保留一条 | P0 | 低,脚本改一次 | 高:3,420 万降至 1,140 万 |
| ② | 子图补 lastmod,写到日粒度 | P0 | 低 | 高:恢复「哪本书刚更新」 |
| ③ | 四个模板补 canonical | P0 | 低,加一行标签 | 高:三重地址有归属 |
| ④ | 作品页拆出独立目录页 | P1 | 中,需新模板 | 中高:单页 364 KB 降到约三分之一 |
| ⑤ | 统一 H1 层级 | P1 | 中 | 中:标题结构可判读 |
| ⑥ | 明文 http 链接改协议相对 | P1 | 低,纯字符串替换 | 中:两页共省 75 次 301 |
| ⑦ | 合并 m 与 wap 双移动域名 | P2 | 高,涉及跳转与备案 | 中高:消灭成对重复 |
| ⑧ | 压缩策略统一并补 Vary | P2 | 低 | 低 |
| ⑨ | 软 404 改成真 404 | P2 | 中 | 中:死链不再冒充活页 |
| ⑩ | robots 补 UA 行,响应头补 charset | P2 | 低 | 低 |
P0:两周内,三件事
① 站点地图去重。 每个实体只保留 https://www. 一条,删掉 m 与 wap 的重复写入。URL 总量从 3,420 万降到 1,140 万,同一份抓取预算覆盖的实体数直接翻三倍。成本最低、收益最大,先做这一件。
② 子图补 lastmod。 按作品最后更新时间写到日粒度即可。3,486 个子图共用 2020-10-15 的写法,等于主动放弃了「哪本书刚更新」这个信号。
③ 补 canonical。 至少覆盖首页、作品页、章节页、分类页四个模板,统一指向自身 https 绝对地址;移动站反过来指回 www。这一条同时解决双移动域名与章节参数页的归属问题。
P1:改模板,一个月内
④ 作品页拆目录。 127 章链接塞进一页,让 364 KB 的单页承担了目录职责。拆出独立目录页(保留前 20 章 + 分页入口),作品页体积可降到三分之一。
⑤ 统一 H1。 首页补一个 H1(站名或核心品类),分类页 16 个 H1 全部降为 H2,目标每页 1 个 H1、H2 落在 2 到 6 个之间。现状是首页没有主标题、分类页有 16 个主标题。
⑥ 明文链接改协议相对。 作品页 63 条、章节页 12 条 http:// 改成 // 或 https 绝对地址。纯字符串替换,不涉及逻辑改动。
P2:结构性,按季度排
⑦ 合并双移动域名。 两者响应字节完全一致,保留一条、另一条 301,或先加 canonical 止血。
⑧ 统一压缩策略并补 Vary。 只对声明支持 gzip 的客户端压缩,响应头补 Vary: Accept-Encoding。
⑨ 软 404 改成真 404。 同时给那个没有 <title> 的 39 KB 壳页补上标题,它现在连错误页都算不上。
⑩ 顺手修 robots,并补 charset。 给 /sp 规则补 User-agent 行、Sitemap 改 https;响应头 Content-Type 补 charset=gb18030,现在全靠页面 meta 兜底。
十条里,P0 三项都不动模板,只改数据与标签,是性价比最高的部分。P1 与 P2 才涉及模板拆分和域名收敛。

图 3 · ①②③ 成本最低、影响最大;⑦ 合并双移动域名影响不小,但排在最后
同类问题在别处也出现过:游民星空那篇实测里,44 万条资讯的发现链同样断在第一页之后;途虎养车则是整站换壳后 21 条路径返回同一份字节。三家的共同点不是内容不够,而是交给爬虫的地址与真实页面之间没有对齐。
抓取预算到底怎么被消耗掉的,这份 117 万次抓取的记录给出了另一种解释:配额从来不是短板,页面的独立价值才是。
登录后可点赞、收藏与反馈。