前面说到,我写了一个能自动爬取对方网站,生成适合 Hexo 友链配置格式的脚本。
既然说到能添加友链的脚本,那我就来说一下我这个脚本的原理是什么。
为什么我们的浏览器能够精准地渲染一个网站的图标、网站的标题还有网站的个人介绍呢?这是因为实际上他们出现的位置特别地固定!
| 位置 |
描述 |
<title></title> 或 og:title |
网站的标题 |
og:image 或 twitter:image |
网站的图标 |
description 或 og:description |
网站的介绍 |
我们可以根据这些固定的位置,写一个简简单单的脚本,来用正则表达式和爬虫,爬取对应网站的首页,转换成我们需要的配置格式。
1 2 3 4
| - name: 网站的标题 link: 网站的链接 avatar: 网站的图标 descr: 网站的介绍
|
原理是不是听起来很简单?所以说我根据这个,找 AI 生成了一个 Python 脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
import sys import re import urllib.request from urllib.parse import urlparse import html
def get_webpage_content(url): """获取网页内容""" try: headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } req = urllib.request.Request(url, headers=headers) response = urllib.request.urlopen(req, timeout=10) content = response.read().decode('utf-8', errors='ignore') return content except Exception as e: print(f"获取网页内容失败: {e}") return None
def extract_title(html_content): """提取网页标题""" title_match = re.search(r'<title[^>]*>(.*?)</title>', html_content, re.IGNORECASE | re.DOTALL) if title_match: title = title_match.group(1).strip() title = re.sub(r'\s+', ' ', title) return html.unescape(title) og_title_match = re.search(r'<meta[^>]*property=["\']og:title["\'][^>]*content=["\']([^"\']+)["\']', html_content, re.IGNORECASE) if og_title_match: return html.unescape(og_title_match.group(1).strip()) return ""
def extract_og_image(html_content): """提取Open Graph图片""" og_image_match = re.search(r'<meta[^>]*property=["\']og:image["\'][^>]*content=["\']([^"\']+)["\']', html_content, re.IGNORECASE) if og_image_match: image_url = og_image_match.group(1).strip() return html.unescape(image_url) twitter_image_match = re.search(r'<meta[^>]*property=["\']twitter:image["\'][^>]*content=["\']([^"\']+)["\']', html_content, re.IGNORECASE) if twitter_image_match: image_url = twitter_image_match.group(1).strip() return html.unescape(image_url) return ""
def extract_description(html_content): """提取描述""" desc_match = re.search(r'<meta[^>]*name=["\']description["\'][^>]*content=["\']([^"\']+)["\']', html_content, re.IGNORECASE) if desc_match: desc = desc_match.group(1).strip() desc = re.sub(r'\s+', ' ', desc) return html.unescape(desc) og_desc_match = re.search(r'<meta[^>]*property=["\']og:description["\'][^>]*content=["\']([^"\']+)["\']', html_content, re.IGNORECASE) if og_desc_match: desc = og_desc_match.group(1).strip() desc = re.sub(r'\s+', ' ', desc) return html.unescape(desc) return ""
def format_yaml_entry(name, link, avatar, descr): """格式化YAML条目""" name = name.strip() if name else "" avatar = avatar.strip() if avatar else "" descr = descr.strip() if descr else "" yaml_entry = f"- name: {name}\n" yaml_entry += f" link: {link}\n" yaml_entry += f" avatar: {avatar}\n" yaml_entry += f" descr: {descr}" return yaml_entry
def main(): if len(sys.argv) != 2: print("使用方法: python3 get_links.py <URL>") print("示例: python3 get_links.py https://xiashuangjv123.github.io/") sys.exit(1) url = sys.argv[1].strip() parsed_url = urlparse(url) if not parsed_url.scheme or not parsed_url.netloc: print("错误: 无效的URL格式") sys.exit(1) print(f"正在处理: {url}") html_content = get_webpage_content(url) if not html_content: print("无法获取网页内容") sys.exit(1) name = extract_title(html_content) avatar = extract_og_image(html_content) descr = extract_description(html_content) if avatar and not avatar.startswith(('http://', 'https://')): if avatar.startswith('/'): base_url = f"{parsed_url.scheme}://{parsed_url.netloc}" avatar = base_url + avatar else: base_path = parsed_url.path if base_path.endswith('/'): base_url = f"{parsed_url.scheme}://{parsed_url.netloc}{base_path}" else: base_url = f"{parsed_url.scheme}://{parsed_url.netloc}{base_path.rsplit('/', 1)[0]}/" avatar = base_url + avatar yaml_output = format_yaml_entry(name, url, avatar, descr) print("\n生成的YAML格式:") print("=" * 50) print(yaml_output) print("=" * 50) try: import subprocess subprocess.run("pbcopy", universal_newlines=True, input=yaml_output) print("✓ 已复制到剪贴板") except: try: import win32clipboard win32clipboard.OpenClipboard() win32clipboard.EmptyClipboard() win32clipboard.SetClipboardText(yaml_output) win32clipboard.CloseClipboard() print("✓ 已复制到剪贴板") except: print("⚠ 无法自动复制到剪贴板,请手动复制上面的内容")
if __name__ == "__main__": main()
|
保存为 get_links.py。
这样每次收到评论有友链时,我就可以运行 python3 get_links.py 网站链接 生成网站配置了。