【问题标题】:How to print a chart from an Excel Chartsheet using Python如何使用 Python 从 Excel 图表表中打印图表
【发布时间】:2021-02-14 19:13:32
【问题描述】:

我对编码完全陌生(只是为了好玩,希望能节省一些工作时间),我一直在努力让我的第一行代码正常工作。
具体来说,我希望我的代码打开某个 Excel 工作簿,找到某些实际上是图表的工作表(每个工作表中只有一个图表)并将它们打印为特定文件夹中的 pdf/jpeg 文件。我选择了 ExportAsFixedFormat,但遇到了以下错误。

AttributeError: 'Chartsheet' object has no attribute 'ExportAsFixedFormat'

你能帮帮我吗?有什么方法可以打印/保存图表吗?
我浏览了 Chartsheet 对象的方法,但找不到任何有用的东西。我确定我错过了什么。

关于我的配置的一些信息:
Windows 10 家庭版 x64
Excel for Microsoft 365 MSO (16.0.13628.20318) 64 位
Python 3.8 32 位
Pywin32版本227

在我遇到问题的代码块下方。
[编辑]:在我编写的整个代码下方,可能错误不在我认为的位置。
提前谢谢你,对不起我的英语不好。

首先,我已经导入了大量的东西,我知道我很可能只需要其中的一半。

import plotly
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import win32com.client as win32
import openpyxl
import os, sys
import math
import openpyxl
from openpyxl import Workbook, load_workbook
from openpyxl import chart
from openpyxl import chartsheet
from openpyxl.chartsheet.publish import WebPublishItem, WebPublishItems
from openpyxl.drawing.spreadsheet_drawing import SpreadsheetDrawing
#from .drawings import find_images
from openpyxl.chartsheet import Chartsheet
import openpyxl.chart
import win32com.client
from pdf2image import convert_from_path
from pathlib import Path
import xlsxwriter

这是我写的代码:

path_filePy = Path(__file__).resolve()
current_folder = path_filePy.parent

image_folder_name = "Immages"
image_folder_path = os.path.join(current_folder, image_folder_name)  
try:  
    os.mkdir(image_folder_path)  
except OSError:
    files = os.listdir(image_folder_path)
    for f in files:
        os.remove(image_folder_path + '\\'+ f)

folder_list = os.listdir(current_folder)
excel_list=[]
for l in folder_list:
    if l.endswith('.xlsx'):
        excel_list.append(l)

chartsheets_names=['Chartsheet1', 'Chartsheet2', 'Chartsheet3', 'Chartsheet4']

excel = win32.gencache.EnsureDispatch('Excel.Application')

for excelfile in excel_list:    
    wb = load_workbook(os.path.join(current_folder, excelfile))      
    for sheet in chartsheets_names:    
        ws=wb[sheet]   
        image_file_name = excelfile[:-5]+'_'+sheet+'.pdf'        
        image_file_path = os.path.join(image_folder_path,image_file_name)        
        ws.ExportAsFixedFormat(0, image_file_path)                     
        convert_from_path(image_file_path, dpi=300, output_folder=image_folder_path,fmt='jpeg')
    wb.Close()

【问题讨论】:

  • 这可能会对您有所帮助:win32 ExportAsFixedFormat Error.
  • 感谢您的帮助,但其他帖子中的链接已过期。无论如何,我发现 Worksheet 对象上的操作也会给我带来错误,就像我首先提到的那样。例如“AttributeError: 'Workbook' 对象没有属性 'SaveAs'”
  • 感谢@ack,非常感谢您对此提供的帮助。我根据您链接的第二篇文章尝试了一些东西,但仍然没有...我收到此错误:“AttributeError:'' object has no attribute 'WorkSheets' "
  • 请更新您的问题:Windows 版本、Office (Excel) 版本、python(32b?64b?)和 win32com 版本。

标签: python excel printing worksheet


【解决方案1】:

我最终得到了我想要的。下面是我现在使用的代码,也许它对其他人也有帮助。 我想我在搞乱与 win32com 相关的代码和与 openpxl 相关的代码。

现在我希望我的 Chartsheets 在打印之前拉伸整个打印区域(我尝试将边距设置为零,但它不起作用)。我想我应该使用 wb_sheet.PageSetup.ChartSize 和值 FullPage,但我不知道如何分配它。

import os
import sys  
from pathlib import Path  
import win32com.client as w3c
from pdf2image import convert_from_path

# find the parent folder of the .py file
path_filePy = Path(__file__).resolve()
current_folder = path_filePy.parent
print(current_folder)

# create the destination folder or empty it if existing
image_folder_name = "Immages"
image_folder_path = os.path.join(current_folder, image_folder_name)  
#print(image_folder_path)
try:  
    os.mkdir(image_folder_path)  
except OSError:
    files = os.listdir(image_folder_path)
    for f in files:
        os.remove(image_folder_path + '\\'+ f)

# list of file in the folder
folder_list = os.listdir(current_folder)

# list of only *.xlsx files
excel_list=[]
for l in folder_list:
    if l.endswith('.xlsx'):
        excel_list.append(l)

# listof sheets' names I want to print
chartsheets_names=['Sheet1', 'Sheet2', 'Sheet3', 'Sheet4']

o = w3c.Dispatch("Excel.Application")
o.Visible = False

# for each sheet names as in my list, in each xlsx file, it prints in both pdf and jpeg
for excel_file in excel_list:
    try:
        wb_path = os.path.join(os.path.abspath(current_folder), excel_file)    
        wb = o.Workbooks.Open(wb_path)            
        for wb_sheet in wb.Sheets: 
            if wb_sheet.Name in chartsheets_names:
                path_to_pdf = os.path.join(os.path.abspath(image_folder_path), excel_file[:-5] + ' - ' + str(wb_sheet.Name) + '.pdf') 
                wb_sheet.SaveAs(path_to_pdf, FileFormat=57)
                convert_from_path(
                    path_to_pdf, # the input pdf file
                    dpi=300, 
                    output_folder=image_folder_path, 
                    fmt='jpeg',
                    output_file=str(excel_file[:-5] + ' - ' + str(wb_sheet.Name)),               
                    poppler_path = r"C:\where\your\poppler\bin folder is", 
                    use_pdftocairo=False)  
            else: next
        wb.Close(False) 
    except OSError:
        next
o.Quit

`

【讨论】:

  • 很高兴听到您找到了解决方案 - 赞成。
  • 谢谢@ack :) 我实际上做了很多改进(使用 tkinter、字典等,学习曲线陡峭)但它们不在问题的主题范围内,所以我没有添加它们。
【解决方案2】:

进一步查看更新答案。 请参阅下面的进一步更新

pip install comtypes 之后这对我有用:

import os
import comtypes.client

SOURCE_DIR = r'C:\Users\xyz\SO-samples'  # adjust to your needs
TARGET_DIR = r'C:\Users\xyz\SO-samples'  # adjust to your needs

app = comtypes.client.CreateObject('Excel.Application')
app.Visible = False

infile = os.path.join(os.path.abspath(SOURCE_DIR), 'an-excel-file.xlsx')
outfile = os.path.join(os.path.abspath(TARGET_DIR), 'an-excel-file.pdf')

doc = app.Workbooks.Open(infile)
doc.ExportAsFixedFormat(0, outfile, 1, 0)
doc.Close()

app.Quit()

更新答案 - 可选择的表格:

import os
import win32com.client

SOURCE_DIR = r'C:\Users\xyz\SO-samples'  # adjust
TARGET_DIR = r'C:\Users\xyz\SO-samples'  # adjust

wb_path = os.path.join(os.path.abspath(SOURCE_DIR), 'xyzzy.xlsx')
wb = o.Workbooks.Open(wb_path)

o = win32com.client.Dispatch("Excel.Application")
o.Visible = False

# print 1 sheet to 1 file
path_to_pdf = os.path.join(os.path.abspath(TARGET_DIR), 'xyzzy2.pdf')
ws_index_list = [2]  # say you want to print this sheet
wb.WorkSheets(ws_index_list).Select()
wb.ActiveSheet.ExportAsFixedFormat(0, path_to_pdf)

# print 2 sheets to 1 file
path_to_pdf = os.path.join(os.path.abspath(TARGET_DIR), 'xyzzy-1-3.pdf')
ws_index_list = [1,3]  # say you want to print these sheets
wb.WorkSheets(ws_index_list).Select()
wb.ActiveSheet.ExportAsFixedFormat(0, path_to_pdf)

# print 3 sheets to 1 file each
ws_index_list = [1,2,3]  # say you want to print these sheets
for ws_index in ws_index_list:
    path_to_pdf = os.path.join(os.path.abspath(TARGET_DIR), 'xyzzy-' + str(ws_index) + '.pdf')
    wb.WorkSheets([ws_index]).Select()
    wb.ActiveSheet.ExportAsFixedFormat(0, path_to_pdf)

# select sheet by name, print 1 sheet to 1 file
ws_sheet_name = 'named_sheet'
path_to_pdf = os.path.join(os.path.abspath(TARGET_DIR), 'xyzzy-' + ws_sheet_name + '.pdf')
wb.WorkSheets(ws_sheet_name).Select()
wb.ActiveSheet.ExportAsFixedFormat(0, path_to_pdf)

进一步更新 - 打印工作表名称,按名称选择工作表:

import win32com.client as w3c
import os, sys

SOURCE_DIR = r'C:\Users\xyz\SO-samples'
TARGET_DIR = r'C:\Users\xyz\SO-samples'

wb_path = os.path.join(os.path.abspath(SOURCE_DIR), 'xyzzy.xlsx')

o = w3c.Dispatch("Excel.Application")
o.Visible = False

wb = o.Workbooks.Open(wb_path) 

for wb_sheet in wb.Sheets:
    print(wb_sheet.Name)

### this works
ws_sheet_name = [1,3]

path_to_pdf = os.path.join(os.path.abspath(TARGET_DIR), 'xyzzy' + '.pdf')
wb.Worksheets(ws_sheet_name).Select()
wb.ActiveSheet.ExportAsFixedFormat(0, path_to_pdf)

### this works
ws_sheet_name = 'xyzzy'

path_to_pdf = os.path.join(os.path.abspath(TARGET_DIR), 'xyzzy-xyzzy' + '.pdf')
wb.Worksheets(ws_sheet_name).Select()
wb.ActiveSheet.ExportAsFixedFormat(0, path_to_pdf)

wb.Close()

【讨论】:

  • 好的,首先:非常感谢!它也适用于我,我没有收到任何错误,我想这是个好消息。问题是我不想打印整个 Excel 文件,而只想打印其中的几张选定的表格。我尝试使用“ws=wb[sheet]”保持 for 循环,但出现此错误:“TypeError: 'POINTER(_Workbook)' object is not subscriptable”
  • @Vastem - 现在有可选择的工作表
  • 谢谢@ack,我实际上尝试了 WorkSheet(xxx).Select() 选项(按索引,按名称...),但它仍然不起作用。我一直有这个错误:AttributeError:''对象没有属性'WorkSheets'。这是一个小小的噩梦......
  • 我发现了这个:link。对我来说这是“工作表”,而不是“工作表”。现在,如果我给出一个特定的索引,代码就可以工作,但如果我给出工作表的名称,它就不行了。我正在尝试这个link,但它不起作用......
  • 您是否从我的答案中复制并粘贴了代码?它在这里工作正常。发布您实际尝试的失败代码的minimal reproducible example
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-09
  • 2017-04-27
  • 1970-01-01
相关资源
最近更新 更多