diff options
| author | Eltrac <hi@guhub.cn> | 2025-05-23 19:32:43 +0800 |
|---|---|---|
| committer | Eltrac <hi@guhub.cn> | 2025-05-23 19:32:43 +0800 |
| commit | c5ecf0d1ddc27e42c83ddfcd50d2cc2b9b108694 (patch) | |
| tree | 17dadd07a52dd64459bd138cb65bc254465049bb /scripts | |
| parent | 3bb1e46b2a4a91bdc7480fd43528757cde9d7820 (diff) | |
chore: comebine two link analysis script
Former-commit-id: e50c574d8d969a38eb1c3068b537fa220503adb7
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/analyze_links.py (renamed from scripts/extractLinks.py) | 91 | ||||
| -rw-r--r-- | scripts/listExternalLinks.py | 53 |
2 files changed, 37 insertions, 107 deletions
diff --git a/scripts/extractLinks.py b/scripts/analyze_links.py index eb172353..598f4a94 100644 --- a/scripts/extractLinks.py +++ b/scripts/analyze_links.py @@ -1,15 +1,18 @@ import os import re import json +from urllib.parse import urlparse +from collections import Counter content_dir = "content" internal_link_pattern = re.compile(r"\[[^\]]*\]\((/[^)]+)\)") +markdown_link_re = re.compile(r"\[.*?\]\((http.*?)\)") url_map = {} # file path -> canonical url alias_map = {} # alias url -> canonical url link_graph = {} # canonical url -> list of canonical urls title_map = {} # canonical url -> title - +external_links = Counter() def parse_frontmatter(filepath): with open(filepath, encoding="utf-8") as f: @@ -19,12 +22,8 @@ def parse_frontmatter(filepath): return {}, 0 frontmatter = {} - aliases = [] - slug = None - draft = False - title = None - related_cards = [] - mentioned_books = [] + aliases, related_cards, mentioned_books = [], [], [] + slug, draft, title = None, False, None i = 1 while i < len(lines): line = lines[i].strip() @@ -39,8 +38,7 @@ def parse_frontmatter(filepath): aliases = [] i += 1 while i < len(lines) and lines[i].startswith(" - "): - alias = lines[i].strip()[3:].strip() - aliases.append(alias) + aliases.append(lines[i].strip()[3:].strip()) i += 1 continue elif key == "slug": @@ -74,24 +72,18 @@ def parse_frontmatter(filepath): "mentioned_books": mentioned_books }, i + 1 - def get_canonical_url(filepath, frontmatter): rel_path = os.path.relpath(filepath, content_dir) dirname, filename = os.path.split(rel_path) name = os.path.splitext(filename)[0] slug = frontmatter.get("slug") or name parts = dirname.split(os.sep) - if parts == [""]: - return f"/{slug}/" - return f"/{'/'.join(parts)}/{slug}/" - + return f"/{'/'.join(parts)}/{slug}/" if parts != [""] else f"/{slug}/" def resolve_url(url): return alias_map.get(url, url) - def resolve_url_from_dir(link, subdir): - """Only search for link in a specific content subdir (like 'cards', 'library')""" target_dir = os.path.join(content_dir, subdir) for path, canonical in url_map.items(): if path.startswith(target_dir): @@ -100,21 +92,14 @@ def resolve_url_from_dir(link, subdir): return canonical return None - def get_icon(url): - if url.startswith("/cards/"): - return "📄" - elif url.startswith("/posts/"): - return "📜" - elif url.startswith("/library/"): - return "📖" - elif url.startswith("/fictions/"): - return "🧙♀️" - elif url.startswith("/en/"): - return "🇬🇧" + if url.startswith("/cards/"): return "📄" + if url.startswith("/posts/"): return "📜" + if url.startswith("/library/"): return "📖" + if url.startswith("/fictions/"): return "🧙♀️" + if url.startswith("/en/"): return "🇬🇧" return "📁" - def collect_urls(): for root, _, files in os.walk(content_dir): for file in files: @@ -134,54 +119,52 @@ def collect_urls(): for alias in frontmatter.get("aliases", []): alias_map[alias] = canonical_url - -def build_link_graph(): +def build_link_graph_and_external_links(): for path, canonical_url in url_map.items(): with open(path, encoding="utf-8") as f: content = f.read() - # markdown links + # 内部链接 for match in internal_link_pattern.finditer(content): link = match.group(1) normalized = resolve_url(link) if normalized and normalized in link_graph: link_graph[canonical_url].append(normalized) - frontmatter, _ = parse_frontmatter(path) + # 外部链接 + for match in markdown_link_re.findall(content): + domain = urlparse(match).netloc + if domain and domain not in {"image.guhub.cn", "www.geedea.pro"}: + external_links[domain] += 1 - # related_cards → only from cards + # 相关卡片和图书 + frontmatter, _ = parse_frontmatter(path) for card in frontmatter.get("related_cards", []): target = resolve_url_from_dir(card, "cards") if target and target in link_graph: link_graph[canonical_url].append(target) - - # mentioned_books → only from library for book in frontmatter.get("mentioned_books", []): target = resolve_url_from_dir(book, "library") if target and target in link_graph: link_graph[canonical_url].append(target) - def main(): collect_urls() - build_link_graph() - - nodes = [ - {"id": url, "label": title_map[url], "url": url} - for url in link_graph - ] - - edges = [] - for source, targets in link_graph.items(): - for target in targets: - edges.append({"from": source, "to": target}) - - graph = {"nodes": nodes, "edges": edges} - - output_path = os.path.join("public", "link-graph.json") - with open(output_path, "w", encoding="utf-8") as f: - json.dump(graph, f, indent=2, ensure_ascii=False) - print(f"✅ Link graph generated: {output_path}") + build_link_graph_and_external_links() + + # 写入内部链接图 + os.makedirs("public", exist_ok=True) + nodes = [{"id": url, "label": title_map[url], "url": url} for url in link_graph] + edges = [{"from": src, "to": tgt} for src, targets in link_graph.items() for tgt in targets] + with open("public/link-graph.json", "w", encoding="utf-8") as f: + json.dump({"nodes": nodes, "edges": edges}, f, indent=2, ensure_ascii=False) + print("✅ Link graph generated: public/link-graph.json") + + # 写入外部链接统计 + os.makedirs("data", exist_ok=True) + with open("data/externallinks.json", "w", encoding="utf-8") as f: + json.dump(external_links.most_common(), f, indent=2, ensure_ascii=False) + print("✅ External link data written to data/externallinks.json") if __name__ == "__main__": main() diff --git a/scripts/listExternalLinks.py b/scripts/listExternalLinks.py deleted file mode 100644 index 89df0605..00000000 --- a/scripts/listExternalLinks.py +++ /dev/null @@ -1,53 +0,0 @@ -import os -from urllib.parse import urlparse -from collections import Counter -import json -import re - -content_dir = "content" -external_links = Counter() - -# 匹配 Markdown 中的 URL 链接 [text](url) -markdown_link_re = re.compile(r'\[.*?\]\((http.*?)\)') - -def extract_front_matter_and_content(path): - with open(path, 'r', encoding='utf-8') as f: - lines = f.readlines() - - if not lines or lines[0].strip() != '---': - return {}, ''.join(lines) - - front_matter = {} - end_index = None - for i in range(1, len(lines)): - if lines[i].strip() == '---': - end_index = i - break - key_value = lines[i].split(':', 1) - if len(key_value) == 2: - key, value = key_value - front_matter[key.strip()] = value.strip() - - content = ''.join(lines[end_index+1:]) if end_index else ''.join(lines) - return front_matter, content - -def extract_links_from_file(path): - _, content = extract_front_matter_and_content(path) - - # 提取 Markdown 格式链接 - for match in markdown_link_re.findall(content): - domain = urlparse(match).netloc - if domain and domain != 'image.guhub.cn' and domain != 'www.geedea.pro': - external_links[domain] += 1 - -for root, dirs, files in os.walk(content_dir): - for file in files: - if file.endswith(".md"): - extract_links_from_file(os.path.join(root, file)) - -# 写入 JSON -os.makedirs("data", exist_ok=True) -with open("data/externallinks.json", "w", encoding="utf-8") as f: - json.dump(external_links.most_common(), f, indent=2, ensure_ascii=False) - -print("✅ External link data written to data/externallinks.json") |
