最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python批量調(diào)整Excel格式并排版導(dǎo)出PDF的幾種方案

 更新時(shí)間:2026年06月18日 08:36:11   作者:tsfy2003  
工作中遇到一個(gè)需求:批量處理個(gè)人所得稅扣繳申報(bào)表的Excel文件,一張表有幾十列,要調(diào)整列寬到一張A4上,文件太多了,一個(gè)個(gè)調(diào),累死也弄不完,乍一看需求不復(fù)雜,但實(shí)際開發(fā)過程中還是遇到不少問題,所以本文介紹了Python批量調(diào)整Excel格式并排版導(dǎo)出PDF的完整流程

背景

工作中遇到一個(gè)需求:批量處理個(gè)人所得稅扣繳申報(bào)表的Excel文件,一張表有幾十列,要調(diào)整列寬到一張A4上,文件太多了,一個(gè)個(gè)調(diào),累死也弄不完,要調(diào)整列寬、字號(hào)、自動(dòng)換行、行高等格式,然后導(dǎo)出為A4橫向PDF。6個(gè)年度文件夾,共63個(gè).xls文件。

乍一看需求不復(fù)雜,但實(shí)際開發(fā)過程中還是遇到不少問題。尤其是.xls老格式和合并單元格帶來的麻煩。一般用python處理excel數(shù)據(jù)比較經(jīng)常,但是用python處理表格格式,卻不是常見,所以本文記錄完整的開發(fā)歷程,希望對(duì)遇到類似需求的朋友有幫助。

需求梳理

先看看原始表格的結(jié)構(gòu):

Row 1-4:   標(biāo)題/公司信息
Row 5-7:   三級(jí)合并表頭(跨行跨列合并)
Row 8:     列序號(hào)行
Row 9起:   數(shù)據(jù)行(每個(gè)文件1~47行不等)
Row N:     合計(jì)行
Row N+1起: 聲明/簽章等

共51列,關(guān)鍵列包括:序號(hào)、姓名、身份證件類型、身份證件號(hào)碼、納稅人識(shí)別號(hào)、所得項(xiàng)目、以及大量金額/稅率列。由于要調(diào)整到A4橫向排版上,所有列都要顯示,所以我就先手動(dòng)調(diào)了一版,然后找其中的規(guī)律。

格式要求:

  1. 固定列寬:序號(hào)2.25、姓名4.5、身份證件類型4.84、身份證件號(hào)碼5.33、納稅人識(shí)別號(hào)5.81、是否為非居民個(gè)人2.5、所得項(xiàng)目5.04(單位:字符)
  2. 動(dòng)態(tài)列寬:其余列根據(jù)合計(jì)行值的字符長度決定,映射關(guān)系如下:
字符數(shù)45678910
寬度34.184.465.045.466.26.64
  1. 合計(jì)值為"-"時(shí),查數(shù)據(jù)行最長值來確定寬度;不足4字符統(tǒng)一寬3字符
  2. 字號(hào)9號(hào)+自動(dòng)換行:姓名、身份證件類型、身份證件號(hào)碼、納稅人識(shí)別號(hào)(僅數(shù)據(jù)行,表頭不改)
  3. 自動(dòng)換行(不改字號(hào)):所得項(xiàng)目列
  4. 行高:數(shù)據(jù)行33.8磅,合計(jì)行21磅
  5. 導(dǎo)出PDF:A4橫向,所有列縮放至一頁寬,左右邊距極限最小

技術(shù)選型:三方案對(duì)比

方案一:xlrd + xlwt(? 失?。?/h3>

最先想到的是經(jīng)典的xlrd讀取 + xlwt寫入方案,畢竟.xls是老格式,這兩個(gè)庫是標(biāo)配。

結(jié)果,問題來了:

首先遇到的是中文編碼問題——xlrd讀取的中文在控制臺(tái)輸出亂碼。解決辦法是寫入到UTF-8文件而不是直接print。

但真正的坑是樣式復(fù)制。xlrd讀取的Font對(duì)象和xlwtFont對(duì)象屬性不完全兼容:

# xlrd Font 有的屬性,xlwt Font 沒有:
old_font.charset      # xlwt.Font 不支持
old_font.indent       # xlrd XFAlignment 也沒有

# 類型不匹配:
old_font.underline_type  # xlrd 用這個(gè)
new_font.underline       # xlwt 用這個(gè)

更嚴(yán)重的問題是:xlwt寫入時(shí)無法保留原有樣式。即便你小心翼翼地復(fù)制每一個(gè)樣式屬性,合并單元格的邊框、背景色、對(duì)齊方式等也很容易丟失。對(duì)于這種有三級(jí)合并表頭、大量邊框的報(bào)表,樣式丟失是不可接受的。

# 典型報(bào)錯(cuò)
AttributeError: 'Font' object has no attribute 'charset'
AttributeError: 'XFAlignment' object has no attribute 'indent'

結(jié)論:xlrd/xlwt適合簡單表格的讀寫,但需要精確保留原有樣式的場景,坑太多,果斷放棄。

方案二:openpyxl(? 不可行)

openpyxl是處理.xlsx格式的利器,API友好,樣式控制完善。但問題是——它不支持.xls格式

從所得稅系統(tǒng)里導(dǎo)出來的格式是xls的,如果先把.xls轉(zhuǎn)成.xlsx再處理?引入了額外的轉(zhuǎn)換步驟,且轉(zhuǎn)換過程同樣可能丟失格式。

方案三:win32com(Excel COM接口)(? 成功)

最終選擇用pywin32調(diào)用Excel的COM接口。本質(zhì)上就是用Python操控Excel應(yīng)用程序本身,和手動(dòng)在Excel里操作一樣。

核心優(yōu)勢(shì):

  • 原生支持.xls格式讀寫
  • 格式零丟失——因?yàn)榫褪荅xcel自己在操作
  • 精確控制每一個(gè)格式屬性
  • 最后直接調(diào)用ExportAsFixedFormat導(dǎo)出PDF
import win32com.client as win32

excel = win32.Dispatch('Excel.Application')
excel.Visible = False
excel.DisplayAlerts = False

wb = excel.Workbooks.Open(r'D:\path\to\file.xls')
ws = wb.Worksheets(1)

# 設(shè)置列寬——就是一行代碼
ws.Cells(1, col).EntireColumn.ColumnWidth = 4.5

# 設(shè)置字號(hào)和自動(dòng)換行——也是一行
cell.Font.Size = 9
cell.WrapText = True

# 導(dǎo)出PDF
ws.ExportAsFixedFormat(Type=0, Filename=pdf_path)

簡潔到不可思議。

開發(fā)過程中遇到的關(guān)鍵問題

問題1:UsedRange在合并單元格上翻車

最初用ws.UsedRange.Rows.Countws.UsedRange.Columns.Count來獲取行數(shù)和列數(shù),但合并單元格會(huì)導(dǎo)致這些屬性行為異常(返回值不準(zhǔn)或直接報(bào)錯(cuò))。

解決方案:Cells(65536, 1).End(-4162).Row(等價(jià)于Excel里的Ctrl+↑)來定位最后一行,或者直接遍歷查找。

def get_total_row(ws):
    """查找合計(jì)行(列A含'合'和'計(jì)')"""
    for row in range(1, 100):
        val = ws.Cells(row, 1).Value
        if val is not None and '合' in str(val) and '計(jì)' in str(val):
            return row
    return None

問題2:DisplayAlerts在某些Excel版本上報(bào)錯(cuò)

excel.DisplayAlerts = False  # 部分環(huán)境下拋異常

解決方案: try/except包裹,不影響核心功能。

問題3:PDF只導(dǎo)出了第一頁(最隱蔽的Bug)

這個(gè)Bug是處理完后核對(duì)數(shù)據(jù)時(shí)才發(fā)現(xiàn),多頁的Excel文件導(dǎo)出PDF后,只有第一頁內(nèi)容。

原因是在ExportAsFixedFormat里多寫了兩個(gè)參數(shù):

# ? 錯(cuò)誤寫法——只導(dǎo)出第1頁到第1頁
ws.ExportAsFixedFormat(
    Type=0,
    Filename=pdf_path,
    From=1,    # ← 罪魁禍?zhǔn)?
    To=1,      # ← 罪魁禍?zhǔn)?
    ...
)

# ? 正確寫法——去掉From和To,默認(rèn)導(dǎo)出全部頁面
ws.ExportAsFixedFormat(
    Type=0,
    Filename=pdf_path,
    IgnorePrintAreas=False,
    OpenAfterPublish=False
)

教訓(xùn):復(fù)制粘貼API示例代碼時(shí),一定要理解每個(gè)參數(shù)的含義。 FromTo看起來像是"起始頁"的設(shè)定,但默認(rèn)行為就是導(dǎo)出全部,不需要顯式指定。

問題4:.bat啟動(dòng)腳本的中文亂碼

腳本寫好后,把程序文件放在需要處理的表格文件夾,雙擊.py文件運(yùn)行——閃退。后來發(fā)現(xiàn)原因是代碼開發(fā)是在虛擬環(huán)境寫的,但放到文件夾中直接運(yùn)行,啟動(dòng)的是系統(tǒng)默認(rèn)的python,因?yàn)橄到y(tǒng)默認(rèn)Python沒有安裝pywin32

為了省事,也懶的再裝了,干脆直接寫一個(gè).bat文件,思路是指定已裝好依賴的Python路徑。但第一個(gè)版本全用中文寫注釋和echo,結(jié)果:

'嚭閿欙紒璇鋒鏌ラ敊璇俊鎭悧' 不是內(nèi)部或外部命令

原因: Windows的cmd.exe默認(rèn)使用GBK編碼,而.bat文件被寫入為UTF-8編碼,中文全部變成亂碼被當(dāng)成命令執(zhí)行。

解決方案: .bat文件只使用純英文/ASCII字符,徹底避免編碼問題。

@echo off
"%~dp0process_excel.py" 換成:
"C:\Users\...\python.exe" "%~dp0process_excel.py"

問題5:合計(jì)行值的類型不統(tǒng)一

同樣是數(shù)字列,有的合計(jì)值是float類型(如10754.93),有的是str類型(如'10754.93'),還有的是"-"字符串。需要統(tǒng)一處理才能正確計(jì)算字符長度,自定義一個(gè)處理數(shù)字格式的函數(shù),以后還可以復(fù)用。

def compute_width(total_val, ws, col_1based, data_rows):
    s = str(total_val).strip()
    
    if s == '' or s == '-':
        # 查數(shù)據(jù)行最長值
        max_len = max(len(str(ws.Cells(r, col_1based).Value or ''))
                      for r in data_rows)
    else:
        # 統(tǒng)一格式化為兩位小數(shù)
        formatted = f'{float(total_val):.2f}'  # 0 → "0.00",10754.93 → "10754.93"
        char_count = len(formatted)
    
    return WIDTH_MAP.get(char_count, 3)

經(jīng)驗(yàn)總結(jié)

場景推薦方案
簡單讀寫xlsx,不需保留樣式openpyxl
簡單讀寫xls,不需保留樣式xlrd + xlwt
需精確保留樣式 + 修改格式win32com (COM)
需導(dǎo)出PDFwin32com (COM)
跨平臺(tái)需求openpyxl (僅xlsx)

核心心得:

  1. 選對(duì)工具比寫對(duì)代碼更重要。 xlrd/xlwt折騰了半天樣式問題,換成COM接口后代碼量減半,功能反而更可靠。
  2. COM接口的隱含優(yōu)勢(shì)。 用Python操控Excel本身就是最高保真的方案,因?yàn)槟阏{(diào)用的就是Excel自己的能力。
  3. .bat文件慎用中文。 在Windows環(huán)境下,批處理文件和中文編碼是天敵,純英文最安全。
  4. PDF導(dǎo)出要驗(yàn)證多頁場景。 單頁測試通過不代表多頁也沒問題,一定要用數(shù)據(jù)量大的文件做回歸測試。

寫在最后

其實(shí)在開始寫這個(gè)程序之前,我是準(zhǔn)備手動(dòng)調(diào)格式并導(dǎo)出pdf的,我想著應(yīng)該很快,寫代碼還得研究半天,調(diào)試半天。結(jié)果手動(dòng)改了10來個(gè),實(shí)在改不動(dòng)了,要放到A4紙上,字很小,眼都看花了,索性還是偷個(gè)懶,用程序解決吧。所以再次告訴我們,但凡是簡單重復(fù)性的工作,都可以用技術(shù)解決,能用技術(shù)解決的,決不動(dòng)手!

以上就是Python批量調(diào)整Excel格式并排版導(dǎo)出PDF的幾種方案的詳細(xì)內(nèi)容,更多關(guān)于Python調(diào)整Excel格式并導(dǎo)出PDF的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python3 常見解密加密算法實(shí)例分析【base64、MD5等】

    python3 常見解密加密算法實(shí)例分析【base64、MD5等】

    這篇文章主要介紹了python3 常見解密加密算法,結(jié)合實(shí)例形式分析了Python的base64模塊加密,以及基于pycrypto模塊的MD5加密等相關(guān)操作技巧,需要的朋友可以參考下
    2019-12-12
  • 使用python opencv對(duì)目錄下圖片進(jìn)行去重的方法

    使用python opencv對(duì)目錄下圖片進(jìn)行去重的方法

    今天小編就為大家分享一篇使用python opencv對(duì)目錄下圖片進(jìn)行去重的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • Python word2vec訓(xùn)練詞向量實(shí)例分析講解

    Python word2vec訓(xùn)練詞向量實(shí)例分析講解

    這篇文章主要介紹了Python word2vec訓(xùn)練詞向量實(shí)例分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • Python 單元測試(unittest)的使用小結(jié)

    Python 單元測試(unittest)的使用小結(jié)

    Python中有一個(gè)自帶的單元測試框架是unittest模塊,用它來做單元測試,本篇文章主要介紹了Python 單元測試(unittest)的使用小結(jié),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • pandas將DataFrame的幾列數(shù)據(jù)合并成為一列

    pandas將DataFrame的幾列數(shù)據(jù)合并成為一列

    本文主要介紹了pandas將DataFrame的幾列數(shù)據(jù)合并成為一列,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Python+seaborn實(shí)現(xiàn)聯(lián)合分布圖的繪制

    Python+seaborn實(shí)現(xiàn)聯(lián)合分布圖的繪制

    聯(lián)合分布(Joint Distribution)圖是一種查看兩個(gè)或兩個(gè)以上變量之間兩兩相互關(guān)系的可視化圖,在數(shù)據(jù)分析操作中經(jīng)常需要用到。本文將通過seaborn實(shí)現(xiàn)繪制聯(lián)合分布圖,需要的可以參考一下
    2023-02-02
  • Python異常處理例題整理

    Python異常處理例題整理

    在本篇文章里
    2019-07-07
  • Python中np.where()用法具體實(shí)例

    Python中np.where()用法具體實(shí)例

    這篇文章主要給大家介紹了關(guān)于Python中np.where()用法的相關(guān)資料,np.where()是NumPy庫中的一個(gè)函數(shù),主要用于根據(jù)條件從數(shù)組中選擇元素,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-08-08
  • python中模塊的__all__屬性詳解

    python中模塊的__all__屬性詳解

    這篇文章主要介紹了python中模塊的__all__屬性詳解,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • Python使用Matplotlib繪制多個(gè)Y軸刻度的代碼示例

    Python使用Matplotlib繪制多個(gè)Y軸刻度的代碼示例

    Matplotlib是一個(gè)功能強(qiáng)大的Python庫,在它的幫助下,我們可以繪制條形圖,圖表,繪圖,比例等,在本文中,我們將嘗試在Matplotlib中繪制多個(gè)Y軸刻度,感興趣的小伙伴跟著小編一起來看看吧
    2025-01-01

最新評(píng)論

夏邑县| 黑龙江省| 阳曲县| 建宁县| 芮城县| 合水县| 平定县| 崇阳县| 阿拉善左旗| 山东省| 德令哈市| 金华市| 乐昌市| 平度市| 富顺县| 荣成市| 于都县| 河池市| 军事| 唐海县| 奉化市| 蕲春县| 鄱阳县| 万山特区| 华安县| 定州市| 宣武区| 上杭县| 宝清县| 五常市| 肥东县| 泽普县| 宁蒗| 古浪县| 光泽县| 铜梁县| 乌拉特后旗| 法库县| 奉节县| 平顶山市| 彭州市|