写点什么

用纯 Python 打造的轻量级 Excel 到 Markdown 转换工具

作者:申公豹
  • 2023-12-24
    内蒙古
  • 本文字数:3789 字

    阅读完需:约 12 分钟

用 Python 创建 Excel 转 Markdown 的 CLI 工具

在工作中,我们常常需要将 Excel 表格转换为 Markdown 格式,以便在文档、博客或其他支持 Markdown 的平台上分享。然而,一些 Markdown 编辑器对从 Excel 复制粘贴的内容支持并不理想,导致转换后的格式混乱。另外,如果需要频繁处理相同类型的文件,手动转换显得繁琐。因此,我决定创建一个 CLI 工具,用于自动化这一转换过程。

设计思路

为了确保工具的易用性和便携性,我决定使用 Python 编写这个 CLI 工具。由于我希望同事们也能方便地使用这个工具,我决定尽量减少对第三方库的依赖,使得工具更易于部署。

Excel 文件结构解析

在着手编写代码之前,我们需要了解 Excel 文件的结构。经过简单的研究,我们发现 Excel 文件实际上是一个 ZIP 压缩包,其中包含一系列 XML 文件。具体而言,我们主要关注 sharedStrings.xmlsheet1.xml 两个文件。前者包含表格中的字符串,后者包含表格的实际数据。



读取 Excel 文件

首先,我们需要解压 Excel 文件。Python 的标准库中提供了 zipfile 模块,可以方便地进行文件解压。解压后,我们可以读取 sharedStrings.xml 文件,将其中的共享字符串保存为数组,以便后续引用。


import xml.dom.minidomimport zipfileimport osimport shutil
output_path = 'data' # 解压 Excel 后的临时文件夹名称
file_path = input("请输入 Excel 文件路径:")md_path = file_path.split('.')[0] + ".md" # 输出的 Markdown 文件名
# 解压 Excel 文件with zipfile.ZipFile(file_path, 'r') as zip_ref: zip_ref.extractall(output_path)
strings = []
# 读取共享字符串shared_strings_path = os.path.join(output_path, "xl/sharedStrings.xml")if os.path.exists(shared_strings_path): with open(shared_strings_path, 'r') as data: # 将 XML 文件转化为 DOM 结构 dom = xml.dom.minidom.parse(data) # 找到所有 t 标签 for string in dom.getElementsByTagName('t'): # 将 t 标签中的字符串值加到 strings 数组中 strings.append(string.childNodes[0].nodeValue)
# 其他代码...
复制代码

解析表格数据

接下来,我们解析 sheet1.xml 文件,将表格数据保存为一个二维数组。注意,我们需要处理单元格中可能包含的字符串索引。


result = []
# 读取表格数据sheet_path = os.path.join(output_path, "xl/worksheets/sheet1.xml")if os.path.exists(sheet_path): with open(sheet_path, 'r') as data: dom = xml.dom.minidom.parse(data) # 遍历每一个 row 标签 for row in dom.getElementsByTagName('row'): row_data = [] # 遍历 row 标签中包含的每个 c 标签 for cell in row.getElementsByTagName('c'): value = '' # 如果该 c 标签的 t 属性值为 s,说明是字符串,需要到 strings 中获取其真实值 if cell.getAttribute('t') == 's': shared_string_index = int(cell.getElementsByTagName('v')[0].childNodes[0].nodeValue) value = strings[shared_string_index] # 否则直接读取其值 else: value = cell.getElementsByTagName('v')[0].childNodes[0].nodeValue # 将这一格的数据添加到 row_data 中 row_data.append(value) # 将这一行的数据添加到 result 中 result.append(row_data)# 其他代码...
复制代码

生成 Markdown 表格

最后,我们将表格数据转换为 Markdown 格式,并保存到 Markdown 文件中。


# 构建 Markdown 表格# 生成第一行markdown_table = "|"markdown_table += "|".join(result[0]) + "|"markdown_table += "\n"# 生成分隔行(第二行)markdown_table += "|"markdown_table += "|".join(["-" for _ in result[0]]) + "|"markdown_table += "\n"# 生成后续的行for row in result[1:]:    markdown_table += "|"    markdown_table += "|".join([value for value in row]) + "|"    markdown_table += "\n"# 去除多余的换行符markdown_table = markdown_table[:-1]
# 生成 Markdown 文件with open(md_path, 'w') as md_file: md_file.write(markdown_table)
# 其他代码...
复制代码

完整代码

最终的完整代码如下:


import xml.dom.minidomimport zipfileimport osimport shutil
output_path = 'data' # 解压 Excel 后的临时文件夹名称
file_path = input("请输入 Excel 文件路径:")md_path = file_path.split('.')[0] + ".md" # 输出的 Markdown 文件名
# 解压 Excel 文件with zipfile.ZipFile(file_path, 'r') as zip_ref: zip_ref.extractall(output_path)
strings = []
# 读取共享字符串shared_strings_path = os.path.join(output_path, "xl/sharedStrings.xml")if os.path.exists(shared_strings_path): with open(shared_strings_path, 'r') as data: # 将 XML 文件转化为 DOM 结构 dom = xml.dom.minidom.parse(data) # 找到所有 t 标签 for string in dom.getElementsByTagName('t'): # 将 t 标签中的字符串值加到 strings 数组中 strings.append(string.childNodes[0].nodeValue)
result = []
# 读取表格数据sheet_path = os.path.join(output_path, "xl/worksheets/sheet1.xml")if os.path.exists(sheet_path): with open(sheet_path, 'r') as data: dom = xml.dom.minidom.parse(data) # 遍历每一个 row 标签 for row
in dom.getElementsByTagName('row'): row_data = [] # 遍历 row 标签中包含的每个 c 标签 for cell in row.getElementsByTagName('c'): value = '' # 如果该 c 标签的 t 属性值为 s,说明是字符串,需要到 strings 中获取其真实值 if cell.getAttribute('t') == 's': shared_string_index = int(cell.getElementsByTagName('v')[0].childNodes[0].nodeValue) value = strings[shared_string_index] # 否则直接读取其值 else: value = cell.getElementsByTagName('v')[0].childNodes[0].nodeValue # 将这一格的数据添加到 row_data 中 row_data.append(value) # 将这一行的数据添加到 result 中 result.append(row_data)
# 删除临时文件夹shutil.rmtree(output_path)
# 构建 Markdown 表格# 生成第一行markdown_table = "|"markdown_table += "|".join(result[0]) + "|"markdown_table += "\n"# 生成分隔行(第二行)markdown_table += "|"markdown_table += "|".join(["-" for _ in result[0]]) + "|"markdown_table += "\n"# 生成后续的行for row in result[1:]: markdown_table += "|" markdown_table += "|".join([value for value in row]) + "|" markdown_table += "\n"# 去除多余的换行符markdown_table = markdown_table[:-1]
# 生成 Markdown 文件with open(md_path, 'w') as md_file: md_file.write(markdown_table)
复制代码


当你运行这个 Python 脚本时,它会提示你输入 Excel 文件的路径,然后它将在同一目录下生成一个相应的 Markdown 文件。


接下来,我们可以进一步改进这个 CLI 工具,增加一些功能,例如:

1. 参数化文件路径:

将文件路径作为脚本的参数传递,而不是在运行时手动输入。


import sys
if len(sys.argv) < 2: print("请提供 Excel 文件路径作为参数") sys.exit(1)
file_path = sys.argv[1]
复制代码


然后你可以通过命令行运行脚本:


python excel_to_markdown.py path/to/your/excel/file.xlsx
复制代码

2. 处理不同的工作表:

当前脚本仅处理第一个工作表(sheet1.xml)。你可以扩展脚本以允许用户选择或处理所有工作表。

3. 改进 Markdown 表格生成:

目前的 Markdown 表格生成方法非常基础。你可以考虑使用更先进的库,如 tabulatepandas,以提高表格生成的灵活性和美观性。

4. 错误处理:

添加更多的错误处理,以确保在解析文件时能够容错并给出有用的错误信息。

5. 打包为可执行文件:

你可以使用诸如 PyInstallercx_Freezepy2exe 等工具,将脚本打包为可执行文件,使得用户无需安装 Python 解释器即可运行。

6. 增加日志:

在脚本中添加日志功能,以记录程序运行的关键步骤,便于调试和追踪问题。

7. 进一步优化性能:

如果处理大型 Excel 文件时性能成为问题,可以考虑优化代码以更有效地处理数据。


以上是一些可以考虑的改进和扩展点,具体取决于你的需求和使用场景。希望这个简单的工具对你有帮助,如果有任何问题或进一步的需求,请随时提出。

总结

通过这个简单的 Python CLI 工具,我们可以方便地将 Excel 文件转换为 Markdown 格式。该工具减少了对第三方库的依赖,使得代码更加轻量、易读。你可以根据需要扩展该工具,添加更多功能,以适应不同的使用场景。

发布于: 刚刚阅读数: 4
用户头像

申公豹

关注

申公豹本豹-这是新号,原号已废弃 2023-06-05 加入

InfoQ签约作者

评论

发布
暂无评论
用纯 Python 打造的轻量级 Excel 到 Markdown 转换工具_Python_申公豹_InfoQ写作社区