本文内容为网友分享,存在未知的风险性,查阅使用过程请务必认真辨别!
![图片[1]-【Python实用教程】手机通讯录vcf转excel再转vcf-手机通讯录转换-云村集邮社](https://yuncunoss.wokewu.cn/2025/04/20250406135105128-1024x664.jpg)
前言
前几天突然要想批量导入一些电话到手机,发现大部分手机还需要下载相应的手机助手,麻烦好多,因此AI了下这个程序。思路:现把vcf转换成excel,编辑好excel后转成vcf再导入手机
vcf转excel表格(oppo为例)
import vobject
import pandas as pd
import quopri
from datetime import datetime
def decode_quoted_printable(s):
"""解码quoted-printable编码的字符串"""
try:
return quopri.decodestring(s).decode('utf-8')
except:
return s # 解码失败时返回原始字符串
def parse_vcard(vcard_str):
"""解析单个vCard"""
try:
vcard = vobject.readOne(vcard_str)
contact = {
'姓名': '',
'姓氏': '',
'名字': '',
'电话号码': [],
'邮箱': '',
'分组': '未分组',
'国家代码': 'CN',
'最后联系时间': '',
'备注': ''
}
# 处理姓名
if hasattr(vcard, 'fn'):
contact['姓名'] = decode_quoted_printable(vcard.fn.value)
# 处理N字段(结构化姓名)
if hasattr(vcard, 'n'):
name_parts = vcard.n.value
contact['姓氏'] = decode_quoted_printable(name_parts.family or "")
contact['名字'] = decode_quoted_printable(name_parts.given or "")
# 处理电话号码(优先排序)
pref_numbers = []
other_numbers = []
if hasattr(vcard, 'tel_list'):
for tel in vcard.tel_list:
num = tel.value.strip()
if 'PREF' in tel.params.get('TYPE', []):
pref_numbers.append(num)
else:
other_numbers.append(num)
contact['电话号码'] = ';'.join(pref_numbers + other_numbers) or ''
# 处理邮箱
if hasattr(vcard, 'email'):
contact['邮箱'] = vcard.email.value
# 处理分组 X-OPPO-GROUP可修改或者直接不要分组也可以
for x in vcard.getChildren():
if x.name == 'X-OPPO-GROUP':
contact['分组'] = decode_quoted_printable(x.value)
# 处理时间戳
if hasattr(vcard, 'latestdate'):
dt_str = vcard.latestdate.value
try:
dt = datetime.strptime(dt_str, "%Y%m%d%H%M")
contact['最后联系时间'] = dt.strftime("%Y-%m-%d %H:%M")
except:
contact['最后联系时间'] = dt_str
return contact
except Exception as e:
print(f"解析vCard失败: {str(e)}")
return None
def vcf_to_excel(input_path, output_path):
"""主转换函数"""
contacts = []
with open(input_path, 'r', encoding='utf-8') as f:
vcard_str = ""
for line in f:
vcard_str += line
if line.startswith("END:VCARD"):
contact = parse_vcard(vcard_str)
if contact: contacts.append(contact)
vcard_str = ""
# 生成DataFrame
df = pd.DataFrame(contacts)
# 列排序
columns = ['姓名', '姓氏', '名字', '电话号码', '邮箱', '分组', '国家代码', '最后联系时间', '备注']
df = df[columns]
# 保存Excel
df.to_excel(output_path, index=False)
print(f"成功转换 {len(contacts)} 个联系人至 {output_path}")
if __name__ == "__main__":
# 使用方法
vcf_to_excel(
input_path="Contacts-2025-04-03(1).vcf", # 输入文件路径
output_path="contacts1.xlsx" # 输出文件路径
)
excel转vcf
import pandas as pd
import quopri
from datetime import datetime
import re
def excel_to_vcard(input_excel, output_vcf):
# 读取时强制所有列为字符串类型
df = pd.read_excel(
input_excel,
dtype=str,
keep_default_na=False # 禁用自动NaN检测
)
with open(output_vcf, 'w', encoding='utf-8') as f:
for _, row in df.iterrows():
# ========== 电话号码处理 ==========
tel_str = str(row.get('电话号码', '')).strip()
# 阶段1:多号码分割(支持分号、逗号、斜线)
tels = re.split(r'[;,/]', tel_str) if tel_str else []
# 阶段2:清洗和格式化
cleaned_tels = []
for tel in tels:
tel = tel.strip()
# 处理科学计数法 (如 1.38e+10 → 13800000000)
if 'e+' in tel.lower():
tel = f"{float(tel):.0f}"
# 去除尾随的 .0
tel = tel.rstrip('.0')
if tel:
cleaned_tels.append(tel)
# ========== 基础字段构建 ==========
vcard = [
"BEGIN:VCARD",
"VERSION:2.1"
]
# ========== 编码处理优化 ==========
def qp_encode(s):
"""处理空值并添加折行符"""
encoded = quopri.encodestring(s.encode('utf-8')).decode('utf-8')
# 每72字符折行(vCard规范要求)
return '\r\n '.join([encoded[i:i + 72] for i in range(0, len(encoded), 72)])
# 姓名组件
last_name = qp_encode(row.get('姓氏', ''))
first_name = qp_encode(row.get('名字', ''))
vcard.append(f"N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{last_name};{first_name};;;")
# 显示名
full_name = qp_encode(row.get('姓名', ''))
vcard.append(f"FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{full_name}")
# ========== 电话号码处理 ==========
for i, tel in enumerate(cleaned_tels):
# 标记第一个号码为PREF
params = "CELL" + (",PREF" if i == 0 else "")
vcard.append(f"TEL;{params}:{tel}")
# ========== 邮箱处理 ==========
if email := row.get('邮箱', ''):
vcard.append(f"EMAIL;PREF;WORK:{email}")
# ========== 时间处理优化 ==========
if dt_str := row.get('最后联系时间', ''):
try:
# 支持多种时间格式解析
for fmt in ('%Y-%m-%d %H:%M', '%Y/%m/%d %H:%M', '%Y%m%d%H%M'):
try:
dt = datetime.strptime(dt_str, fmt)
break
except ValueError:
continue
vcard.append(f"LATESTDATE:{dt.strftime('%Y%m%d%H%M')}")
except:
pass # 忽略无效时间格式
# ========== 其他字段处理 ==========
if country := row.get('国家代码', ''):
vcard.append(f"COUNTRYISO:{country}")
if group := row.get('分组', ''):
encoded_group = qp_encode(group)
vcard.append(f"X-OPPO-GROUP;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{encoded_group}")
# 备注处理
remark = row.get('备注', 'NULL').replace('"', "'") # 防止引号冲突
vcard.append(f"OPPO_RECENT_CALL:{remark}")
# ========== 结束标记 ==========
vcard.append("END:VCARD")
# 写入时使用CRLF换行符
f.write('\r\n'.join(vcard) + '\r\n')
# 使用示例
excel_to_vcard('contacts1.xlsx', 'restored_contacts2.vcf')
© 版权声明
文章版权归作者所有,未经允许请勿转载。
全站免费资源免费下载,请微信扫一扫下载
THE END