核心功能与解决的实际问题

这段代码的核心功能是解析从手机导出的VCF格式通讯录文件,并将其中的联系人信息(如姓名、电话号码、邮箱等)转换并保存为结构清晰、易于编辑的Excel表格。它专门解决了VCF文件(vCard格式)用文本编辑器查看杂乱无章、无法直接筛选或批量编辑的痛点,使得备份的通讯录数据变得可读、可管理。

完整的联系人信息提取与导出流程

程序能够系统性地遍历VCF文件,识别每个以"BEGIN:VCARD"开始、“END:VCARD"结束的联系人数据块,并从中提取关键字段。解析出的信息会结构化地存入数据集合,最后利用pandas库生成包含"姓名”、“电话”、"邮箱"等列的Excel文件(.xlsx格式),确保所有联系信息一目了然,方便后续的查找、编辑或导入其他设备。

实现代码

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

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

import vobject

import chardet

import pandas as pd

import os

def debug_vcf_file(file_path):

    """

    调试VCF文件:检查编码、文件结构和内容

    """

    print("=== 开始调试VCF文件 ===")

     

    # 检查文件是否存在

    if not os.path.exists(file_path):

        print(f"错误:文件 '{file_path}' 不存在")

        return False

     

    # 检查文件大小

    file_size = os.path.getsize(file_path)

    print(f"文件大小: {file_size} 字节")

     

    if file_size == 0:

        print("错误:文件为空")

        return False

     

    # 读取原始字节数据

    with open(file_path, 'rb') as f:

        raw_data = f.read()

     

    # 检测编码

    encoding_result = chardet.detect(raw_data)

    detected_encoding = encoding_result['encoding']

    confidence = encoding_result['confidence']

     

    print(f"检测到的编码: {detected_encoding} (置信度: {confidence:.2f})")

     

    # 尝试不同编码

    encodings_to_try = [detected_encoding, 'gbk', 'gb2312', 'utf-8', 'iso-8859-1']

     

    for encoding in encodings_to_try:

        if not encoding:

            continue

        try:

            content = raw_data.decode(encoding)

            print(f"✓ 成功使用 {encoding} 编码解码")

             

            # 检查VCF基本结构

            if 'BEGIN:VCARD' in content and 'END:VCARD' in content:

                vcard_count = content.count('BEGIN:VCARD')

                print(f"找到 {vcard_count} 个联系人卡片")

                 

                # 显示前500个字符作为样本

                sample = content[:500]

                print("文件内容样本:")

                print("---" + sample + "---")

                 

                return True, content, encoding

            else:

                print(f"× 使用 {encoding} 解码但未找到VCARD结构")

                 

        except UnicodeDecodeError as e:

            print(f"× {encoding} 编码解码失败: {e}")

        except Exception as e:

            print(f"× {encoding} 处理过程中出错: {e}")

     

    # 最后尝试忽略错误模式

    try:

        content = raw_data.decode('utf-8', errors='ignore')

        print("最后尝试:使用UTF-8忽略错误模式解码")

        return True, content, 'utf-8 (errors ignored)'

    except Exception as e:

        print(f"最终解码失败: {e}")

        return False, None, None

def parse_vcf_with_debug(file_path):

    """

    解析VCF文件并生成Excel表格

    """

    # 调试文件

    debug_result, vcf_content, used_encoding = debug_vcf_file(file_path)

     

    if not debug_result:

        print("文件调试失败,无法继续解析")

        return []

     

    contacts = []

    print(f"\n=== 开始解析VCF内容(使用编码: {used_encoding})===")

     

    try:

        # 分割vCard块

        vcard_blocks = vcf_content.split('BEGIN:VCARD')

         

        for i, block in enumerate(vcard_blocks):

            if not block.strip() or 'END:VCARD' not in block:

                continue

                 

            # 重新构建完整的vCard

            vcard_text = 'BEGIN:VCARD' + block

             

            try:

                vcard = vobject.readOne(vcard_text)

                contact_info = {'序号': i}

                 

                # 提取姓名

                if hasattr(vcard, 'fn') and vcard.fn:

                    contact_info['姓名'] = str(vcard.fn.value)

                    print(f"联系人 {i}: 找到姓名 - {vcard.fn.value}")

                else:

                    contact_info['姓名'] = '未知'

                    print(f"联系人 {i}: 未找到姓名字段")

                 

                # 提取电话

                contact_info['电话'] = ''

                if hasattr(vcard, 'tel'):

                    phones = []

                    if isinstance(vcard.tel, list):

                        for tel in vcard.tel:

                            if hasattr(tel, 'value') and tel.value:

                                phones.append(str(tel.value))

                    elif hasattr(vcard.tel, 'value') and vcard.tel.value:

                        phones.append(str(vcard.tel.value))

                     

                    if phones:

                        contact_info['电话'] = '; '.join(phones)

                        print(f"联系人 {i}: 找到电话 - {phones}")

                    else:

                        print(f"联系人 {i}: 找到TEL字段但值为空")

                 

                # 提取其他信息

                if hasattr(vcard, 'email'):

                    emails = []

                    if isinstance(vcard.email, list):

                        for email in vcard.email:

                            if email.value:

                                emails.append(str(email.value))

                    elif vcard.email.value:

                        emails.append(str(vcard.email.value))

                    contact_info['邮箱'] = '; '.join(emails) if emails else ''

                 

                contacts.append(contact_info)

                print(f"✓ 成功解析联系人 {i}: {contact_info['姓名']}")

                 

            except Exception as e:

                print(f"× 解析联系人 {i} 时出错: {e}")

                # 打印出错的vCard内容前200字符用于调试

                print(f"错误vCard样本: {vcard_text[:200]}")

                continue

                 

    except Exception as e:

        print(f"解析过程中出现严重错误: {e}")

     

    return contacts

def save_contacts_to_excel(contacts, output_file='contacts.xlsx'):

    """

    将联系人保存到Excel文件

    """

    if not contacts:

        print("没有联系人数据可保存")

        return False

     

    try:

        # 创建DataFrame

        df = pd.DataFrame(contacts)

         

        # 重新排列列顺序

        columns_order = ['序号', '姓名', '电话', '邮箱']

        existing_columns = [col for col in columns_order if col in df.columns]

        df = df[existing_columns]

         

        # 保存到Excel

        df.to_excel(output_file, index=False, engine='openpyxl')

        print(f"✓ 成功生成Excel文件: {output_file}")

        print(f"✓ 共保存 {len(contacts)} 个联系人")

         

        # 显示前几行作为预览

        print("\n前5个联系人预览:")

        print(df.head())

         

        return True

         

    except Exception as e:

        print(f"× 生成Excel文件时出错: {e}")

        return False

# 主执行函数

def main():

    vcf_file_path = "你的通讯录.vcf"  # 请替换为您的VCF文件路径

     

    print("手机VCF联系人解析工具")

    print("=" * 50)

     

    # 解析VCF文件

    contacts_list = parse_vcf_with_debug(vcf_file_path)

     

    if contacts_list:

        # 生成Excel文件

        save_contacts_to_excel(contacts_list)

         

        print(f"\n解析完成!成功处理 {len(contacts_list)} 个联系人")

    else:

        print("\n解析失败,未找到有效联系人")

if __name__ == "__main__":

    main()

效果如下:

以上就是Python实现获取手机通讯录文件并导出为excel的详细内容


 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐