效率工具

把浏览器里保存的密码迁移到 Bitwarden

把浏览器里保存的密码迁移到 Bitwarden:先从 Chrome/Edge 导出 CSV,用脚本合并重复条目、按网站分文件夹、转成 Bitwarden 官方 CSV 格式,同时列出“多个网站共用同一个密码”和“短于 12 位”的账号作为改密清单;导入后删除明文 CSV 并关闭浏览器的密码保存。

BINBHO · 图文教程

把浏览器里保存的密码迁移到 Bitwarden:先从 Chrome/Edge 导出 CSV,用脚本合并重复条目、按网站分文件夹、转成 Bitwarden 官方 CSV 格式,同时列出“多个网站共用同一个密码”和“短于 12 位”的账号作为改密清单;导入后删除明文 CSV 并关闭浏览器的密码保存。

先看清成品

转换脚本 4 个测试通过;样例 4 行转换为 3 条(合并 1 条重复),报告找出 1 组重复密码、1 个过短密码,且报告里不显示密码本身。输出表头与 Bitwarden 官方文档中的个人保险库 CSV 表头一致。没有导入到真实 Bitwarden 账号。

注意:计划和价格以 Bitwarden 官方价格页为准。不要共享个人账号或主密码,团队共享请用组织和集合。只导入、导出你自己有权管理的凭据。

安全提示:导出的 CSV 是明文,所有密码一览无余。只在自己的电脑上操作,不要放进网盘、不要发给别人,导入完成立即删除(也清空回收站)。

做完之后你会得到什么?

成果 说明
Bitwarden CSV 可直接以 Bitwarden (csv) 格式导入
去重 同网站同用户名只保留一条
文件夹 按主域名分组,如 taobao.com
改密清单 重复使用、过短的密码

需要准备哪些环境?

项目 要求 说明
浏览器 Chrome / Edge 设置 → 密码管理器 → 导出密码
Bitwarden 账号 个人保险库 免费版即可导入
Python 3.9 以上 只用标准库

说明:Bitwarden 本身支持直接导入 Chrome 的 CSV。用本文脚本的好处是导入前去重、分文件夹,并得到改密清单。

文件结构

24-bitwarden-C-src/
├── chrome_to_bitwarden.py
├── sample_chrome.csv       # 虚构样例
└── test_convert.py

第 1 步:导出浏览器密码

Chrome:设置 → 自动填充和密码 → Google 密码管理工具 → 设置 → 导出密码(菜单名称随版本变化,以浏览器为准),验证系统密码后保存 CSV。样例格式:

name,url,username,password,note
taobao.com,https://login.taobao.com/,buyer01,Tb-2026-long-pass!,
www.taobao.com,https://www.taobao.com/,buyer01,,
github.com,https://github.com/login,dev@example.com,Tb-2026-long-pass!,
mail.example.com,https://mail.example.com/,me@example.com,123456,旧邮箱

第 2 步:转换脚本

chrome_to_bitwarden.py:

"""把浏览器导出的密码 CSV(Chrome/Edge:name,url,username,password,note)整理成 Bitwarden 个人保险库 CSV。
- 同一网站 + 同一用户名只保留一条(保留密码非空的那条)
- 按主域名放入文件夹,方便导入后整理
- 输出安全报告:重复使用的密码、短于 12 位的密码(报告里不显示密码本身)
"""
import csv, sys
from collections import defaultdict
from urllib.parse import urlparse

HEADER = ["folder", "favorite", "type", "name", "notes", "fields", "reprompt",
          "login_uri", "login_username", "login_password", "login_totp"]

# 常见二级后缀;完整规则见 Public Suffix List,这里只做简化处理
TWO_LEVEL = {"com.cn", "net.cn", "org.cn", "gov.cn", "edu.cn", "com.hk", "co.uk", "co.jp"}

def site(url):
    host = (urlparse(url if "://" in url else "https://" + url).hostname or "").lower()
    parts = host.removeprefix("www.").split(".")
    n = 3 if ".".join(parts[-2:]) in TWO_LEVEL else 2
    return ".".join(parts[-n:]) if len(parts) >= n else host

def convert(rows):
    seen, out = {}, []
    for r in rows:
        url, user, pw = r.get("url", "").strip(), r.get("username", "").strip(), r.get("password", "")
        key = (site(url), user.lower())
        if key in seen:
            if not out[seen[key]]["login_password"] and pw: out[seen[key]]["login_password"] = pw
            continue
        seen[key] = len(out)
        out.append({"folder": site(url) or "未分类", "favorite": "", "type": "login",
                    "name": r.get("name", "").strip() or site(url) or url, "notes": r.get("note", ""),
                    "fields": "", "reprompt": "0", "login_uri": url, "login_username": user,
                    "login_password": pw, "login_totp": ""})
    return out, len(rows) - len(out)

def report(items):
    by_pw = defaultdict(list)
    for it in items:
        if it["login_password"]: by_pw[it["login_password"]].append(f'{it["name"]}({it["login_username"]})')
    lines = [f"重复使用:{', '.join(v)}" for v in by_pw.values() if len(v) > 1]
    lines += [f'过短({len(it["login_password"])} 位):{it["name"]}({it["login_username"]})'
              for it in items if 0 < len(it["login_password"]) < 12]
    return lines

if __name__ == "__main__":
    src, dst = sys.argv[1], sys.argv[2]
    with open(src, encoding="utf-8-sig", newline="") as f:
        items, dups = convert(list(csv.DictReader(f)))
    with open(dst, "w", encoding="utf-8", newline="") as f:
        w = csv.DictWriter(f, fieldnames=HEADER); w.writeheader(); w.writerows(items)
    print(f"写出 {dst}:{len(items)} 条,合并重复 {dups} 条")
    for line in report(items): print("⚠", line)

Bitwarden 个人保险库 CSV 的表头(大小写必须一致):

folder,favorite,type,name,notes,fields,reprompt,login_uri,login_username,login_password,login_totp

第 3 步:运行

python chrome_to_bitwarden.py 浏览器导出.csv bitwarden_import.csv

样例的本机实际输出(本机运行时输出文件名用的是 out.csv):

写出 out.csv:3 条,合并重复 1 条
⚠ 重复使用:taobao.com(buyer01), github.com(dev@example.com)
⚠ 过短(6 位):mail.example.com(me@example.com)

把报告存下来,导入后按清单去各网站改密码(改完在 Bitwarden 里更新)。测试:python -m pytest -q → 4 passed。

第 4 步:导入 Bitwarden

网页版 工具 → 导入数据,文件格式选 Bitwarden (csv),选择 bitwarden_import.csv,导入。

检查结果:条目数等于脚本输出的条数,左侧出现 taobao.com、github.com 等文件夹。

第 5 步:清理

shred -u 浏览器导出.csv bitwarden_import.csv   # Linux;macOS/Windows 删除后清空回收站

然后在浏览器设置中关闭“提议保存密码”,并删除浏览器里已保存的密码,避免两边不同步。

调试示例

最初 site() 只取域名最后两段,www.shop.com.cn 会被归到 com.cn 文件夹。加了常见二级后缀表后返回 shop.com.cn,测试 test_site 覆盖了这个情况。完整规则见 Public Suffix List,脚本只处理常见情况,个别网站分组不准不影响导入。

出错了怎么办?

现象 原因 解决
导入报格式错误 表头大小写或列数不对 用脚本输出,不要在 Excel 里改表头
中文乱码 用 Excel 保存改成了 GBK 不要用 Excel 另存;脚本输出为 UTF-8
条目重复 之前已经导入过一次 导入前清空测试数据,或在 Bitwarden 里删除重复
文件夹太多 每个网站一个文件夹 把 folder 列改成空,或按“工作/生活”手动分
漏掉了某些密码 浏览器不同配置文件分别保存 每个配置文件分别导出

模板规则

  • 明文 CSV 用完即删。
  • 迁移的同时处理改密清单。
  • 迁移后关闭浏览器密码保存,只用一个密码管理器。

项目资源

用途 地址
导入自定义格式文件(CSV 表头) https://bitwarden.com/help/condition-bitwarden-import/
从 Chrome 导入 https://bitwarden.com/help/import-from-chrome/
导入数据 https://bitwarden.com/help/import-data/
Public Suffix List https://publicsuffix.org/
Bitwarden 价格 https://bitwarden.com/pricing/

迁移密码管理器是清理密码的最好时机。顺手把重复和过短的密码换掉,比单纯换个地方存要有价值得多。