本文目录导读:

我来为您编写一个完整的失效链接清理脚本,这个脚本可以扫描指定目录中的文件,检查文件中的链接是否有效,并提供清理功能。
基础版:检查文件中的URL链接
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
失效链接清理脚本
功能:扫描文件中的URL链接,检查是否有效
"""
import os
import re
import requests
import argparse
from urllib.parse import urlparse
from concurrent.futures import ThreadPoolExecutor, as_completed
class BrokenLinkChecker:
def __init__(self, directory, extensions=None, timeout=10, max_workers=10):
"""
初始化链接检查器
Args:
directory: 要扫描的目录
extensions: 要检查的文件扩展名列表
timeout: 请求超时时间
max_workers: 并发线程数
"""
self.directory = directory
self.extensions = extensions or ['.md', '.txt', '.html', '.rst', '.py']
self.timeout = timeout
self.max_workers = max_workers
self.broken_links = []
def find_links_in_file(self, filepath):
"""查找文件中的链接"""
links = []
url_pattern = re.compile(r'https?://[^\s\'\"<>\)]+')
try:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
links = url_pattern.findall(content)
except Exception as e:
print(f"读取文件 {filepath} 时出错: {e}")
return links
def check_link(self, url, filepath, line_number=0):
"""检测单个链接是否有效"""
try:
# 清理URL
url = url.rstrip('.,;:!?)>\'\"')
# 跳过某些常见但不需要检查的域名
skip_domains = ['localhost', '127.0.0.1', 'example.com']
parsed = urlparse(url)
if parsed.netloc in skip_domains:
return None
# 发送请求
response = requests.get(
url,
timeout=self.timeout,
allow_redirects=True,
headers={'User-Agent': 'Mozilla/5.0 (compatible; LinkChecker/1.0)'}
)
if response.status_code >= 400:
return {
'url': url,
'file': filepath,
'status': response.status_code,
'error': f'HTTP {response.status_code}'
}
except requests.exceptions.ConnectionError:
return {
'url': url,
'file': filepath,
'status': 'ERROR',
'error': '连接失败'
}
except requests.exceptions.Timeout:
return {
'url': url,
'file': filepath,
'status': 'ERROR',
'error': '超时'
}
except requests.exceptions.RequestException as e:
return {
'url': url,
'file': filepath,
'status': 'ERROR',
'error': str(e)
}
return None
def scan_files(self):
"""扫描目录中的文件"""
print(f"正在扫描目录: {self.directory}")
print(f"检查的文件类型: {', '.join(self.extensions)}")
print("=" * 60)
files_to_check = []
for root, dirs, files in os.walk(self.directory):
# 跳过隐藏目录和.git等
dirs[:] = [d for d in dirs if not d.startswith('.') and d != 'node_modules']
for file in files:
if any(file.endswith(ext) for ext in self.extensions):
files_to_check.append(os.path.join(root, file))
print(f"找到 {len(files_to_check)} 个文件需要检查")
# 使用线程池并发检查
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures = []
for filepath in files_to_check:
links = self.find_links_in_file(filepath)
for link in links:
future = executor.submit(self.check_link, link, filepath)
futures.append(future)
# 处理结果
completed = 0
for future in as_completed(futures):
completed += 1
if completed % 50 == 0:
print(f"已检查 {completed} 个链接...")
result = future.result()
if result:
self.broken_links.append(result)
return self.broken_links
def generate_report(self, output_file=None):
"""生成失效链接报告"""
if not self.broken_links:
print("✓ 没有发现失效链接!")
return
print(f"\n发现 {len(self.broken_links)} 个失效链接:")
print("-" * 80)
report_content = []
for link in sorted(self.broken_links, key=lambda x: (x['file'], x['url'])):
line = f"文件: {link['file']}\n链接: {link['url']}\n状态: {link['status']} - {link['error']}\n"
print(line)
report_content.append(line + "\n")
if output_file:
with open(output_file, 'w', encoding='utf-8') as f:
f.writelines(report_content)
print(f"报告已保存到: {output_file}")
class LinkCleaner(BrokenLinkChecker):
"""扩展版:支持清理失效链接"""
def clean_links(self, dry_run=True):
"""清理失效链接"""
if not self.broken_links:
print("没有需要清理的链接")
return
if dry_run:
print("\n预演模式 - 不会实际修改文件")
print("=" * 40)
# 按文件分组
links_by_file = {}
for link in self.broken_links:
if link['file'] not in links_by_file:
links_by_file[link['file']] = []
links_by_file[link['file']].append(link)
for filepath, links in links_by_file.items():
print(f"\n处理文件: {filepath}")
try:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
original_content = content
# 替换失效链接
for link in links:
old_url = link['url']
if not dry_run:
content = content.replace(old_url, f"[失效链接: {old_url}]")
print(f" - 已标记失效链接: {old_url[:50]}...")
else:
print(f" [预演] 将标记: {old_url[:50]}...")
# 写入文件
if not dry_run and content != original_content:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
print(f" ✓ 文件已更新")
except Exception as e:
print(f" ✗ 处理失败: {e}")
def main():
parser = argparse.ArgumentParser(description='失效链接检查与清理工具')
parser.add_argument('directory', help='要扫描的目录')
parser.add_argument('--extensions', '-e', nargs='+',
help='要检查的文件扩展名 (默认: .md .txt .html .rst .py)')
parser.add_argument('--timeout', '-t', type=int, default=10,
help='请求超时时间(秒)')
parser.add_argument('--workers', '-w', type=int, default=10,
help='并发线程数')
parser.add_argument('--report', '-r', help='输出报告文件')
parser.add_argument('--clean', '-c', action='store_true',
help='清理失效链接')
parser.add_argument('--dry-run', '-d', action='store_true',
help='预演模式,不实际修改文件')
args = parser.parse_args()
if not os.path.exists(args.directory):
print(f"错误: 目录 '{args.directory}' 不存在")
return
if args.clean:
cleaner = LinkCleaner(
args.directory,
args.extensions,
args.timeout,
args.workers
)
cleaner.scan_files()
if cleaner.broken_links:
cleaner.generate_report(args.report)
cleaner.clean_links(dry_run=args.dry_run)
else:
checker = BrokenLinkChecker(
args.directory,
args.extensions,
args.timeout,
args.workers
)
checker.scan_files()
checker.generate_report(args.report)
if __name__ == '__main__':
main()
使用方法
安装依赖
pip install requests
基本使用
# 检查当前目录 python broken_link_checker.py /path/to/your/directory # 检查特定文件类型 python broken_link_checker.py /path/to/your/directory -e .md .txt # 生成报告 python broken_link_checker.py /path/to/your/directory -r report.txt # 清理失效链接(预演模式) python broken_link_checker.py /path/to/your/directory -c -d # 实际清理失效链接 python broken_link_checker.py /path/to/your/directory -c # 自定义并发数和超时 python broken_link_checker.py /path/to/your/directory -w 20 -t 5
高级功能
添加白名单域名
# 在 check_link 方法中添加
whitelist_domains = ['github.com', 'stackoverflow.com']
if parsed.netloc in whitelist_domains:
return None # 跳过检查
支持更多文件类型
# 可以检查 Markdown 中的图片链接 img_pattern = re.compile(r'!\[.*?\]\((https?://[^\s\)]+)\)') # 检查 HTML 中的链接 html_pattern = re.compile(r'<a\s+(?:[^>]*?\s+)?href="(https?://[^"]+)"')
批量替换方案
# 添加自动替换功能
replacements = {
'old-domain.com': 'new-domain.com',
'http://': 'https://'
}
注意事项
- 网络请求限制:避免发送过多请求导致被屏蔽
- 文件备份:清理前建议先备份文件
- URL编码:有些URL可能包含特殊字符
- :JavaScript生成的链接可能无法检测
这个脚本可以根据您的具体需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播