# bookmark-classfiy **Repository Path**: xiaohelikesleep/bookmark-classfiy ## Basic Information - **Project Name**: bookmark-classfiy - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-02-05 - **Last Updated**: 2026-02-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 浏览器书签智能分类工具 ## 项目简介 本工具用于自动整理浏览器书签,通过AI智能分类技术,将杂乱的书签按照主题自动归类,并且重新生成结构化的书签文件。 ## 功能特性 - 自动提取书签信息 - 智能分类书签内容 - 生成HTML格式书签文件,可直接导入浏览器 - 自动清理临时文件 ## 使用说明 ### 准备工作 1. 获取智谱AI API密钥 2. 准备浏览器导出的书签HTML文件 ### 快速开始 1. 下载脚本 2. 修改`CONFIG`配置中的`INPUT_FILE`和`OUTPUT_FILE` 3. 修改`CONFIG`配置中的API_KEY 4. 运行脚本: ```bash python 浏览器书签文件重新分类.py ``` 5. 查看生成的分类结果文件`bookmarks.html` ### 配置文件说明 在脚本开头的`CONFIG`字典中可配置以下参数: - `API_KEY`: 智谱AI API密钥(必填) - `INPUT_FILE`: 输入的书签HTML文件路径 - `EXTRACTED_FILE`: 提取的临时文件路径 - `CLASSIFIED_FILE`: 分类结果Markdown文件路径 - `OUTPUT_FILE`: 最终输出的HTML书签文件路径 - `DEFAULT_CATEGORIES`: 默认分类列表 ## 代码结构 ```python # 主要功能模块 1. 配置参数 (CONFIG) 2. AI客户端初始化 (zhipu_client) 3. 书签提取 (extract_bookmark_info) 4. 书签分类 (classify_bookmark) 5. 分类创建 (create_new_category) 6. 格式转换 (md_to_netscape) 7. 文件清理 (cleanup_temp_files) ``` ## 脚本代码详细说明 ### 浏览器书签文件重新分类脚本详细说明 #### 1. **配置参数** ```python CONFIG = { 'API_KEY': "9e2458a8acf46274d1c1b9418eec500c.oBojpibVHt3IyXnz", # 智谱API密钥,必填 'INPUT_FILE': 'bookmarks_2025_1_3.html', # 输入文件,必填 'EXTRACTED_FILE': 'extracted_bookmarks.txt', # 提取的临时文件 'CLASSIFIED_FILE': 'classified_bookmarks.md', # 分类结果文件 'OUTPUT_FILE': 'bookmarks.html', # 最终输出文件 'DEFAULT_CATEGORIES': [ # 默认分类 '编程语言', '人工智能', '数据科学', ] } ``` - **API_KEY**: 用于调用智谱AI API的密钥。 - **INPUT_FILE**: 输入的HTML格式浏览器书签文件路径。 - **EXTRACTED_FILE**: 提取的书签信息保存为文本文件的路径。 - **CLASSIFIED_FILE**: 分类后的书签信息保存为Markdown文件的路径。 - **OUTPUT_FILE**: 最终生成的HTML格式书签文件路径。 - **DEFAULT_CATEGORIES**: 预定义的默认分类列表。 #### 2. **初始化客户端** ```python zhipu_client = ZhipuAI(api_key=CONFIG['API_KEY']) ``` - 使用提供的API密钥初始化智谱AI客户端,用于后续与AI模型交互。 #### 3. **获取AI响应** ```python def get_llm_response(sysPrompt, questionPrompt): response = zhipu_client.chat.completions.create( model="GLM-4-Plus", # 填写需要调用的模型编码 messages=[ {"role": "user", "content": sysPrompt}, {"role": "assistant", "content": "你好,请告诉我你需要分类的书签?"}, {"role": "user", "content": questionPrompt}, ], ) return response.choices[0].message.content ``` - 定义一个函数`get_llm_response`,用于向AI模型发送系统提示和用户问题,并返回模型的响应内容。 #### 4. **读取并解析HTML文件** ```python with open(CONFIG['INPUT_FILE'], 'r', encoding='utf-8') as file: html_content = file.read() soup = BeautifulSoup(html_content, 'html.parser') bookmarks = soup.find_all('a') bookmark_info = [] for bookmark in bookmarks: href = bookmark.get('href') add_date = bookmark.get('add_date') icon = bookmark.get('icon') text = bookmark.text.strip().replace('\n', '').replace('\t', '').replace('\r', '').replace(' ', '') bookmark_info.append({ 'URL': href, 'Text': text }) with open(CONFIG['EXTRACTED_FILE'], 'w', encoding='utf-8') as f: for info in bookmark_info: f.write(f"Name: {info['Text']}, URL: {info['URL']}\n") ``` - 读取输入的HTML书签文件内容。 - 使用BeautifulSoup解析HTML,提取所有的``标签作为书签。 - 将每个书签的URL和名称保存到`bookmark_info`列表中。 - 将提取的书签信息保存到临时文件`EXTRACTED_FILE`中。 #### 5. **分类书签** ```python def extract_bookmark_info(line): name_match = re.search(r'Name: ([^,]+)', line) url_match = re.search(r'URL: (https?://[^\s]+)', line) if not name_match or not url_match: return None, None return name_match.group(1), url_match.group(1) def classify_bookmark(bookmark_name, bookmark_url, categories): system_prompt = ( "你是一个智能助手,任务是根据提供的书签名称和URL从给定的分类列表中选择最合适的分类返回给用户。仅返回分类名称。\n" "请根据书签的内容和性质选择最适合的分类。如果没有合适的分类,请回答'无法分类'。\n" "给定分类: {categories_str}\n" "请选择最合适的分类。\n" "示例:" "user: 书签名称:Python官方文档\n" "书签URL:https://docs.python.org/3/\n" "assistant: 编程语言\n" ).format(categories_str=", ".join(categories)) user_prompt = ( "书签名称: {bookmark_name}\n" "书签URL: {bookmark_url}\n" ).format(bookmark_name=bookmark_name, bookmark_url=bookmark_url) try: response = get_llm_response(system_prompt, user_prompt) except Exception as e: response = "其他" if response == "无法分类": return None return response def create_new_category(name, url): system_prompt = ( "你是一个智能助手,任务是根据提供的书签名称和URL给定一个合适的书签分类。仅返回分类名称。\n" "请根据书签的内容和性质给定分类。\n" "示例:" "user: 书签名称:Python官方文档\n" "书签URL:https://docs.python.org/3/\n" "assistant: 编程语言\n" ) user_prompt = ( "书签名称: {name}\n" "书签URL: {url}\n" ).format(name=name, url=url) response = get_llm_response(system_prompt, user_prompt) return response ``` - `extract_bookmark_info`: 从临时文件中每行提取书签名称和URL。 - `classify_bookmark`: 根据书签名称和URL,使用AI模型从预定义分类中选择最合适的分类。如果无法分类,则返回`None`。 - `create_new_category`: 如果书签无法归入现有分类,则创建新分类。 #### 6. **处理书签分类** ```python categories = CONFIG['DEFAULT_CATEGORIES'] with open(CONFIG['EXTRACTED_FILE'], 'r', encoding='utf-8') as f: bookmarks = f.readlines() classified = defaultdict(list) for line in bookmarks: if not line.strip(): continue name, url = extract_bookmark_info(line) if not name or not url: continue category = classify_bookmark(name, url, categories) if not category: category = create_new_category(name, url) categories.append(category) print(f'分类书签: {name} -> {category}') classified[category].append(line) with open(CONFIG['CLASSIFIED_FILE'], 'w', encoding='utf-8') as f: f.write('# 书签\n\n') for category, items in classified.items(): f.write(f'## {category}\n') for item in items: name, url = extract_bookmark_info(item) if name and url: f.write(f'- [{name}]({url})\n') f.write('\n') ``` - 从临时文件中读取所有书签信息。 - 对每个书签进行分类,如果无法归入现有分类则创建新分类。 - 将分类结果保存到Markdown文件`CLASSIFIED_FILE`中。 #### 7. **将分类结果转换为HTML书签文件** ```python def md_to_netscape(md_content): html = ''' Bookmarks

Bookmarks

''' lines = md_content.split('\n') stack = [] current_level = 0 for line in lines: if line.startswith('#'): level = line.count('#') title = line.lstrip('#').strip() while stack and stack[-1] >= level: html += '

\n' stack.pop() html += f'

{title}

\n' html += '

\n' stack.append(level) current_level = level elif line.startswith('-'): match = re.match(r'-\s*\[(.*?)\]\((.*?)\)', line) if match: name, url = match.groups() html += f'

{name}\n' while stack: html += '

\n' stack.pop() return html with open(CONFIG['CLASSIFIED_FILE'], 'r', encoding='utf-8') as f: md_content = f.read() html_content = md_to_netscape(md_content) with open(CONFIG['OUTPUT_FILE'], 'w', encoding='utf-8') as f: f.write(html_content) ``` - 定义`md_to_netscape`函数,将Markdown格式的分类结果转换为Netscape Bookmark HTML格式。 - 读取分类结果文件`CLASSIFIED_FILE`,将其转换为HTML格式并保存到`OUTPUT_FILE`。 #### 8. **清理临时文件** ```python def cleanup_temp_files(): temp_files = [ CONFIG['EXTRACTED_FILE'], CONFIG['CLASSIFIED_FILE'] ] for file in temp_files: if os.path.exists(file): os.remove(file) print(f"已删除临时文件: {file}") if __name__ == '__main__': try: # 主逻辑代码... cleanup_temp_files() print("脚本执行完成,临时文件已清理") except Exception as e: print(f"脚本执行出错: {str(e)}") ``` - 定义`cleanup_temp_files`函数,清理脚本运行过程中产生的临时文件。 - 在主程序执行完成后调用此函数,确保临时文件被删除。 ### 总结 该脚本通过以下步骤实现了对浏览器书签文件的重新分类: 1. **读取和解析**:从HTML文件中提取书签信息。 2. **分类**:使用AI模型对书签进行分类,必要时创建新分类。 3. **保存结果**:将分类结果保存为Markdown文件。 4. **转换格式**:将Markdown格式的分类结果转换为HTML格式。 5. **清理**:删除临时文件以保持工作环境整洁。 这个过程不仅简化了书签管理,还利用AI技术提高了分类的准确性和效率。 ## 注意事项 1. 确保API密钥有效 2. 输入文件格式需为标准Netscape书签格式 3. 分类结果可能受AI模型影响,建议人工复核 4. 脚本运行后会清理临时文件,请及时保存结果 ## 完整代码 ```python # 浏览器书签文件重新分类.py from zhipuai import ZhipuAI from bs4 import BeautifulSoup import re import os from collections import defaultdict from datetime import datetime # 配置参数 CONFIG = { 'API_KEY': "9e2458a8acf46274d1c1b9418eec500c.oBojpibVHt3IyXnz", # 智谱API密钥,必填 'INPUT_FILE': 'bookmarks_2025_1_3.html', # 输入文件,必填 'EXTRACTED_FILE': 'extracted_bookmarks.txt', # 提取的临时文件 'CLASSIFIED_FILE': 'classified_bookmarks.md', # 分类结果文件 'OUTPUT_FILE': 'bookmarks.html', # 最终输出文件 'DEFAULT_CATEGORIES': [ # 默认分类 '编程语言', '人工智能', '数据科学', ] } # 初始化客户端 zhipu_client = ZhipuAI(api_key=CONFIG['API_KEY']) def get_llm_response(sysPrompt, questionPrompt): response = zhipu_client.chat.completions.create( model="GLM-4-Plus", # 填写需要调用的模型编码 messages = [ {"role": "user", "content": sysPrompt}, {"role": "assistant", "content": "你好,请告诉我你需要分类的书签?"}, {"role": "user", "content": questionPrompt}, ], ) return response.choices[0].message.content # 读取HTML文件内容 with open(CONFIG['INPUT_FILE'], 'r', encoding='utf-8') as file: html_content = file.read() # 使用BeautifulSoup解析HTML soup = BeautifulSoup(html_content, 'html.parser') # 查找所有的标签 bookmarks = soup.find_all('a') # 提取书签信息 bookmark_info = [] for bookmark in bookmarks: href = bookmark.get('href') add_date = bookmark.get('add_date') icon = bookmark.get('icon') text = bookmark.text.strip().replace('\n', '').replace('\t', '').replace('\r', '').replace(' ', '') bookmark_info.append({ 'URL': href, 'Text': text }) # 打印提取的书签信息 for info in bookmark_info: print(info) # 保存提取的书签信息 with open(CONFIG['EXTRACTED_FILE'], 'w', encoding='utf-8') as f: for info in bookmark_info: f.write(f"Name: {info['Text']}, URL: {info['URL']}\n") def extract_bookmark_info(line): """从书签行中提取名称和URL""" name_match = re.search(r'Name: ([^,]+)', line) url_match = re.search(r'URL: (https?://[^\s]+)', line) if not name_match or not url_match: return None, None return name_match.group(1), url_match.group(1) def classify_bookmark(bookmark_name, bookmark_url, categories): system_prompt = ( "你是一个智能助手,任务是根据提供的书签名称和URL从给定的分类列表中选择最合适的分类返回给用户。仅返回分类名称。\n" "请根据书签的内容和性质选择最适合的分类。如果没有合适的分类,请回答'无法分类'。\n" "给定分类: {categories_str}\n" "请选择最合适的分类。\n" "示例:" "user: 书签名称:Python官方文档\n" "书签URL:https://docs.python.org/3/\n" "assistant: 编程语言\n" ).format(categories_str=", ".join(categories)) user_prompt = ( "书签名称: {bookmark_name}\n" "书签URL: {bookmark_url}\n" ).format(bookmark_name=bookmark_name, bookmark_url=bookmark_url) try: response = get_llm_response(system_prompt, user_prompt) except Exception as e: response = "其他" if response == "无法分类": return None return response def create_new_category(name, url): """ 创建新分类 :param name: 书签名称 :param url: 书签URL :return: 新分类名 """ system_prompt = ( "你是一个智能助手,任务是根据提供的书签名称和URL给定一个合适的书签分类。仅返回分类名称。\n" "请根据书签的内容和性质给定分类。\n" "示例:" "user: 书签名称:Python官方文档\n" "书签URL:https://docs.python.org/3/\n" "assistant: 编程语言\n" ) user_prompt = ( "书签名称: {name}\n" "书签URL: {url}\n" ).format(name=name, url=url) response = get_llm_response(system_prompt, user_prompt) return response # 使用配置中的分类规则 categories = CONFIG['DEFAULT_CATEGORIES'] with open(CONFIG['EXTRACTED_FILE'], 'r', encoding='utf-8') as f: bookmarks = f.readlines() classified = defaultdict(list) for line in bookmarks: if not line.strip(): continue name, url = extract_bookmark_info(line) if not name or not url: continue # 分类书签 category = classify_bookmark(name, url, categories) if not category: # 创建新分类 category = create_new_category(name, url) categories.append(category) print(f'分类书签: {name} -> {category}') classified[category].append(line) # 将分类结果保存为文件 with open(CONFIG['CLASSIFIED_FILE'], 'w', encoding='utf-8') as f: f.write('# 书签\n\n') for category, items in classified.items(): f.write(f'## {category}\n') for item in items: name, url = extract_bookmark_info(item) if name and url: f.write(f'- [{name}]({url})\n') f.write('\n') from datetime import datetime # 将分类结果重新转为HTML书签文件 def md_to_netscape(md_content): # 初始化HTML结构 html = ''' Bookmarks

Bookmarks

''' # 解析MD内容 lines = md_content.split('\n') stack = [] current_level = 0 for line in lines: # 处理标题 if line.startswith('#'): level = line.count('#') title = line.lstrip('#').strip() # 关闭之前的DL while stack and stack[-1] >= level: html += '

\n' stack.pop() # 添加H3标签 html += f'

{title}

\n' html += '

\n' stack.append(level) current_level = level # 处理链接 elif line.startswith('-'): match = re.match(r'-\s*\[(.*?)\]\((.*?)\)', line) if match: name, url = match.groups() html += f'

{name}\n' # 关闭所有打开的DL while stack: html += '

\n' stack.pop() return html with open(CONFIG['CLASSIFIED_FILE'], 'r', encoding='utf-8') as f: md_content = f.read() html_content = md_to_netscape(md_content) with open(CONFIG['OUTPUT_FILE'], 'w', encoding='utf-8') as f: f.write(html_content) # 清理临时文件 def cleanup_temp_files(): """清理脚本运行过程中产生的临时文件""" temp_files = [ CONFIG['EXTRACTED_FILE'], CONFIG['CLASSIFIED_FILE'] ] for file in temp_files: if os.path.exists(file): os.remove(file) print(f"已删除临时文件: {file}") # 主程序执行 if __name__ == '__main__': try: # 原有主逻辑代码... # 脚本执行完成后清理临时文件 cleanup_temp_files() print("脚本执行完成,临时文件已清理") except Exception as e: print(f"脚本执行出错: {str(e)}") ```