好久没有写 Python 脚本了。最近遇到的一个实际33需求就是:如何将 Excel 表格中的单元
格数据提取出成一个 vCard 文件?表格内容看起来是这样的:
ID | Address | Name | Phone Number |
---|---|---|---|
在 Python 数目众多的第三方库中搜索,我找到了 | |||
vobject. |
安装 openpyxl 和 vobject 库
直接 pip 安装,对于 Linux 用户可以在 pip 后加上 --user
参数安装到用户目录下。
1 | pip install --user openpyxl vobject |
使用openpyxl 提取数据
openpyxl 是一个读取/写入 Excel 2010 xlsx/xlsm/xltx/xltm 文件的 Python 库,很容易上手,官方的文档写得很详细,项目也在活跃开发中。不过我碰到的最大的缺点是在一次性写入大量数据的时候比较耗 CPU. 这里简要介绍一下如何读取 Excel 单元格数据。
打开并读取 excel 文件, 获取所需 sheet:
1 | wb = load_workbook('mydata.xlsx') |
读取制定列元素. openpyxl 的语法和 Excel 函数很像:
- 获取一整列或者一整行单元格
1
2colA = ws['A']
row10 = ws['10'] - 获取制定范围内(类似于矩形选择)的单元格
1
2
3DataRange = ws['A3':'G5']
# 获取制定的一个单元格
Cell = ws['G6']调用
cell.value
获取单元格值1
2c.value = 'hello, world'
print(c.value).vcf 文件格式介绍
FileInfo 网站上面的介绍是这样的:VCF 文件是一种存储联系人信息的标准文件格式,文件内通常包括姓名、地址、电话、电子邮箱等联系人信息。VCF 文件同样也可以存储制定域、图像和其它媒体信息。手机用户可以直接由联系人应用导入VCF文件。
.vcf 文件是纯文本文件,这也意味着你可以直接使用文本编辑器查看和编辑它,这也为我们使用 python 的字符串拼接写入文本信息提供了可能。用文本编辑器打开它会显示成这个样子:
如图片中显示的那样,vCard 文件首先以 BEGIN VCARD
开始,以 END:VCARD
结束。 VERSION:3.0
表示采用 3.0 版本的标准。详细的标准可以参看 vCard Format Specification 手册。这里我们要用到的就是以下几个:
FN: Full Name 注意一个vCard 文件必须包含 FN 类型
Purpose: To specify the formatted text corresponding to the name of the object the vCard represents.
Value type: A single text value.TEL: Telephone Number
Purpose: To specify the telephone number for telephony communication with the object the vCard represents.
Value type: By default, it is a single free-form text value
利用vobject 写入 .vcf 文件
- 创建 vCard 对象:
1
2import vobject
j = vobject.vCard() - 添加MIME 信息
1
2j.add('fn').value = yourname
j.add('tel').value = yourtel - Serializing, 自动补全所有其它需要的属性。
1
2
3j.serialize()
# 打印输出测试
j.prettyPrint()遇到的问题
在写这个很简易的脚本中,最困扰我的问题就是添加联系人地址。如果你简单地写那么当运行1
j.add('add').value = some_string
j.serialize()
的时候,会出现报错:为了解决这个问题,我查了一下源码:1
vobject.base.NativeError: "In transformFromNative, unhandled exception on line None <class 'AttributeError'>: 'str' object has no attribute 'box'"
出现这个问题的的原因是 vobject 默认地址包含 box、code、country 等附加完整信息,解决的方法也很简单,直接制定1
2
3
4
5
6
7
8
9
10
11
12
13class Address(object):
def __init__(self, street='', city='', region='', code='',
country='', box='', extended=''):
"""
Each name attribute can be a string or a list of strings.
"""
self.box = box
self.extended = extended
self.street = street
self.city = city
self.region = region
self.code = code
self.country = countryadr
为vobject.vcard.Address('some)_place')
即可避免报错。正确的方式参看官方测试实例:1
2
3
4# 传递多个值
card.add('adr').value = vobject.vcard.Address(u'5\u1234 Nowhere, Apt 1', 'Berkeley', 'CA', '94704', 'USA')
# 传递单个值也是可以的
j.add('adr').value = vobject.vcard.Address(‘A Simple Address‘)