谷歌SEO 内链地图脚本:Python 画出权重分发,揪出孤岛页
内链是独立站最容易"做了但没做对"的环节。本篇给一个可运行的内链拓扑分析脚本:抓取页面间的链接关系,输出孤岛页、权重黑洞、深链页三类问题清单,帮你把权重分发画成一张可执行的地图。官方规范见搜索中心内链文档。
一、先说明:内链分析为什么要"脚本化"
手动看内链只能看到"有没有",看不到"分布合不合理"。三个典型问题必须靠数据发现:
| 问题 | 表现 | 后果 |
|---|---|---|
| 孤岛页 | 没有任何页面向它链接 | 权重无法流入,难以收录 |
| 权重黑洞 | 大量页面链向同一低价值页 | 权重被吸走,核心页分不到 |
| 深链页 | 需要 5+ 次点击才能到达 | 爬虫难到达,收录延迟 |
脚本思路:抓取站内页面 → 提取页面里的站内链接 → 构建"谁指向谁"的关系 → 统计入链数、出链数、最深路径。
二、脚本准备
urls.txt:每行一个站内 URL(从 sitemap 导出全量)。- Python 3.8+,仅标准库(urllib + re + collections)。
- 只抓本站域名,避免外链干扰。
三、内链地图脚本
python
import re
import urllib.request
import urllib.error
from urllib.parse import urlparse
from collections import defaultdict
DOMAIN = "example.com" # 换成你的域名
START_URLS = [u.strip() for u in open("urls.txt", encoding="utf-8") if u.strip()]
def fetch(url):
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
try:
with urllib.request.urlopen(req, timeout=10) as resp:
return resp.read().decode("utf-8", "ignore")
except Exception:
return ""
def extract_internal_links(html, page_url):
links = set()
for m in re.finditer(r'href=["\']([^"\']+)["\']', html, re.I):
href = m.group(1).strip()
if href.startswith("#") or href.startswith("mailto:") or href.startswith("javascript:"):
continue
if href.startswith("/"):
href = f"https://{DOMAIN}{href}"
elif href.startswith("http"):
parsed = urlparse(href)
if parsed.netloc != DOMAIN:
continue # 外链跳过
else:
continue
links.add(href.split("#")[0].split("?")[0])
return links
# 构建关系
incoming = defaultdict(set) # 目标页 -> 来源页集合
outgoing = defaultdict(set) # 来源页 -> 目标页集合
pages = set(START_URLS)
for page in START_URLS:
html = fetch(page)
targets = extract_internal_links(html, page)
pages.update(targets)
for t in targets:
incoming[t].add(page)
outgoing[page].add(t)
print(f"抓取页面数: {len(START_URLS)} 发现站内链接目标: {len(pages)}")
# 1. 孤岛页:没有入链
orphans = [p for p in pages if len(incoming.get(p, set())) == 0 and p not in START_URLS]
print(f"\n=== 孤岛页(无入链,{len(orphans)})===")
for p in orphans[:15]:
print(f" {p[:90]}")
# 2. 权重黑洞:入链多但页面价值低(这里用入链数>10 且 出链数==0 近似)
print(f"\n=== 权重黑洞候选(入链多且无出链,{len(pages)} 页中)===")
for p, srcs in incoming.items():
if len(srcs) >= 10 and len(outgoing.get(p, set())) == 0:
print(f" 入链{len(srcs)}个 {p[:90]}")
# 3. 入链排名:核心页是否获得足够权重
print(f"\n=== 入链 Top 15 ===")
for p, srcs in sorted(incoming.items(), key=lambda x: -len(x[1]))[:15]:
print(f" 入链{len(srcs):>3}个 {p[:80]}")
四、输出解读与动作
| 输出 | 判定 | 动作 |
|---|---|---|
| 孤岛页 | 无入链 = 权重进不去 | 从相关核心页加 1-2 条自然链接 |
| 权重黑洞 | 入链多但本身无价值 | 给黑洞页加 nofollow 或减少指向它的链接 |
| 入链 Top | 核心页应排在前列 | Top 页不是核心页时,调整内链布局 |
硬决策规则:核心转化页/核心内容页的入链数应该排在全站前 20%;孤岛页超过全站 10%,说明导航结构有问题,先改导航再补单向链接。
五、常见坑
| 坑 | 后果 | 正解 |
|---|---|---|
| 只抓首页开始 | 漏掉深链页面 | 从 sitemap 导全量 URL |
| 把外链算进内链 | 关系图失真 | 只保留本站域名 |
| 只看数量不看路径 | 深链页被忽略 | 结合导航层级判断 |
| 改完不复查 | 内链又乱 | 每月重跑对比 |
六、FAQ
Q1:脚本能处理动态页面吗?
能抓静态 HTML;JS 渲染页面(SPA)需要预渲染或浏览器工具,脚本结果只作参考。
Q2:入链多少算健康?
没有固定数字,看结构:核心页 > 分类页 > 文章页 > 分页页。重点看相对分布,不看绝对值。
Q3:孤岛页一定要处理吗?
看价值:高价值内容页必须处理;低价值索引垃圾页建议 noindex 或删除,别为链接而链接。
七、行动清单
- 从 sitemap 导出全量 URL 生成 urls.txt,跑内链地图脚本。
- 处理孤岛页:核心内容补入链,垃圾页清理。
- 检查权重黑洞:低价值高入链页收敛权重。
- 每月重跑一次,对比入链分布变化。
- 配合官方内链最佳实践文档逐项核对。
完整版内链地图脚本(含深链层级计算、导航结构分析、可视化输出)我整理成了 PDF,评论区扣「内链」或私信我,免费发你。也欢迎一起交流谷歌SEO实战问题。