You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Putty(Unix)运行Python脚本遇openpyxl缺失报错求替代方案

问题描述

通过Putty在Unix环境运行Python脚本时触发ImportError: Missing optional dependency 'openpyxl',但脚本在Jupyter中运行正常;因权限限制无法安装openpyxl库,需无需额外安装依赖即可读取xlsx文件的替代方案。

报错栈:

Model Spec ILD_Distributeur_xxx.xlsx ERROR: Traceback (most recent call last): 
File "/iri/local/stat-prd/infoscan/code_recensement/code_recensement_geo_retailers_prod_test.py", line 63, in <module> 
VGH_detailed = pd.read_excel("{}/{}".format(path,file), sheet_name="VGH_detailed", header=1) 
File "/usr/local/lib/python3.7/site-packages/pandas/util/_decorators.py", line 311, in wrapper 
return func(*args, **kwargs) 
File "/usr/local/lib/python3.7/site-packages/pandas/io/excel/_base.py", line 364, in read_excel 
io = ExcelFile(io, storage_options=storage_options, engine=engine) 
File "/usr/local/lib/python3.7/site-packages/pandas/io/excel/_base.py", line 1233, in __init__ 
self._reader = self._engines[engine](self._io, storage_options=storage_options) 
File "/usr/local/lib/python3.7/site-packages/pandas/io/excel/_openpyxl.py", line 521, in __init__ 
import_optional_dependency("openpyxl") 
File "/usr/local/lib/python3.7/site-packages/pandas/compat/_optional.py", line 118, in import_optional_dependency 
raise ImportError(msg) from None 
ERROR: Traceback (most recent call last): 
ImportError: Missing optional dependency 'openpyxl'.  Use pip or conda to install openpyxl.

关键代码片段:

try:   
    import os
    from re import search, IGNORECASE
    import pandas as pd
    import datetime
    import math
    import numpy as np
    import traceback
    import sys
    
        
    path = "//server/path1/" 
    list_dossier = []
    time = []
    patho = "//server/path2/"
           
    for dossier in os.listdir(path):
        
        if search( "File_name", dossier,  IGNORECASE) and search( "xlsx", dossier, IGNORECASE) and not search( "copie", dossier, IGNORECASE) and not search( "dev", dossier, IGNORECASE) and not search( "provisoire", dossier, IGNORECASE) and not search( "temporaire", dossier, IGNORECASE) :
            if "~" in dossier or "$" in dossier:
                pass
            else:
                list_dossier.append(dossier)

    for i in list_dossier:        
        pathi = "{}/{}".format(path,i)
        modification_time = os.path.getmtime(pathi)
        time.append(modification_time)

    last_time = time
    last_time.sort()
    last_time = last_time[-1]


    result = list_dossier[time.index(last_time)]
    print(result)

    file = [file]
    file = str(file[-1])


    # nous importons les feuilles VGH_detailed et Geographies
    VGH_detailed = pd.read_excel("{}/{}".format(path,file), sheet_name="VGH_detailed",  header=1)
    Geographies = pd.read_excel("{}/{}".format(path,file), sheet_name="Geographies",  header=1)

    # on declare la table 
    table = pd.DataFrame(index=np.arange(len(VGH_detailed)), columns=["Model","Super Folder","Folder","Level","Geography Label","ILD Code","Legacy Code","Drill Down to Store Level"])

已尝试修改语法、检查文件、测试Unix代码等方法,均未解决问题。


解决方案

方案1:使用xlrd引擎(需环境预装xlrd<2.0)

pandas默认优先用openpyxl读取xlsx,若Unix环境已安装xlrd 1.2.0及以下版本(该版本支持xlsx格式),可直接指定engine='xlrd'绕过openpyxl:

修改关键代码中的pd.read_excel调用:

# 读取VGH_detailed工作表
VGH_detailed = pd.read_excel("{}/{}".format(path,file), sheet_name="VGH_detailed", header=1, engine='xlrd')
# 读取Geographies工作表
Geographies = pd.read_excel("{}/{}".format(path,file), sheet_name="Geographies", header=1, engine='xlrd')

注意:xlrd 2.0及以上版本仅支持xls格式,若环境中xlrd为高版本,此方案不可用。

方案2:Jupyter中转xlsx为CSV,Unix读取CSV

利用Jupyter可正常运行脚本的特性,先在Jupyter中将目标xlsx的指定工作表导出为CSV,再在Unix环境用pd.read_csv读取(无需额外依赖):

步骤1:Jupyter中执行导出代码

import pandas as pd

# 读取目标xlsx的指定工作表
VGH_detailed = pd.read_excel("//server/path1/目标文件名.xlsx", sheet_name="VGH_detailed", header=1)
Geographies = pd.read_excel("//server/path1/目标文件名.xlsx", sheet_name="Geographies", header=1)

# 导出为CSV保存到同服务器路径
VGH_detailed.to_csv("//server/path1/VGH_detailed.csv", index=False, encoding='utf-8')
Geographies.to_csv("//server/path1/Geographies.csv", index=False, encoding='utf-8')

步骤2:修改Unix脚本读取逻辑

替换原pd.read_excel为pd.read_csv:

# 读取CSV文件
VGH_detailed = pd.read_csv("{}/VGH_detailed.csv".format(path))
Geographies = pd.read_csv("{}/Geographies.csv".format(path))

若需自动处理最新文件,可在Jupyter中设置定时导出任务,或在Unix脚本中添加CSV存在性检查,缺失时提示手动导出。

方案3:Python标准库手动解析xlsx(无第三方依赖)

xlsx本质是ZIP压缩包,内部用XML存储表格数据,可通过标准库zipfile和xml.etree.ElementTree解析:

以下是读取指定工作表的工具函数,可直接集成到脚本中:

import zipfile
import xml.etree.ElementTree as ET
import pandas as pd

def read_xlsx_without_openpyxl(file_path, sheet_name, header_row=1):
    # 定义xlsx内部XML命名空间
    ns = {'main': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'}
    
    # 打开xlsx压缩包
    with zipfile.ZipFile(file_path, 'r') as zf:
        # 查找目标工作表对应的资源ID
        with zf.open('xl/workbook.xml') as f:
            tree = ET.parse(f)
            root = tree.getroot()
            sheet_rId = None
            for sheet in root.findall('.//main:sheet', ns):
                if sheet.attrib['name'] == sheet_name:
                    sheet_rId = sheet.attrib['r:id']
                    break
            if not sheet_rId:
                raise ValueError(f"工作表 {sheet_name} 不存在")
        
        # 获取工作表XML文件路径
        with zf.open('xl/_rels/workbook.xml.rels') as f:
            tree = ET.parse(f)
            root = tree.getroot()
            sheet_path = None
            for rel in root.findall('.//Relationship'):
                if rel.attrib['Id'] == sheet_rId:
                    sheet_path = rel.attrib['Target']
                    break
            if not sheet_path:
                raise ValueError(f"无法找到工作表 {sheet_name} 的文件路径")
        
        # 提取单元格数据
        with zf.open(f'xl/{sheet_path}') as f:
            tree = ET.parse(f)
            root = tree.getroot()
            data = []
            for row in root.findall('.//main:row', ns):
                row_data = []
                for cell in row.findall('.//main:c', ns):
                    cell_value = cell.find('.//main:v', ns)
                    row_data.append(cell_value.text if cell_value is not None else '')
                data.append(row_data)
        
        # 转换为DataFrame并跳过指定表头行
        df = pd.DataFrame(data[header_row:], columns=data[header_row-1])
        return df

修改脚本中的读取代码:

# 使用自定义函数读取xlsx
file_path = "{}/{}".format(path,file)
VGH_detailed = read_xlsx_without_openpyxl(file_path, sheet_name="VGH_detailed", header_row=1)
Geographies = read_xlsx_without_openpyxl(file_path, sheet_name="Geographies", header_row=1)

注意:该函数仅处理基础单元格数据,若xlsx包含合并单元格、公式计算值等复杂格式,需额外适配逻辑。


内容的提问来源于stack exchange,提问作者Soukayna Ben Moh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 13:55:08