# 擷取PDF單一頁面的表格
```python=
import pdfplumber
import pandas as pd
# 打開PDF文件
with pdfplumber.open("study_list.pdf") as pdf:
# 獲取PDF的第一頁
first_page = pdf.pages[0]
# 提取表格
table = first_page.extract_table()
# 將表格轉換為DataFrame
df = pd.DataFrame(table[1:], columns=table[0])
# 儲存成CSV文件
df.to_csv("output.csv", index=False)
print("Table extracted and saved to output.csv")
```
* study_list.pdf

* output.csv

# 從多頁的PDF擷取指定表格
```python=
import pdfplumber
import pandas as pd
# 獲得輸入的頁碼和表格索引
page_number = int(input("请輸入要提取表格的頁碼(從1開始):"))
table_index = int(input("请輸入要提取表格的索引(從1開始):"))
# 打開PDF文件
with pdfplumber.open("Test_Fake_File.pdf") as pdf:
# 檢查頁碼是否有效
if page_number > len(pdf.pages) or page_number < 1:
raise ValueError("無效的頁碼")
# 獲得頁碼對應的頁面
page = pdf.pages[page_number - 1]
# 提取頁面中所有表格
tables = page.extract_tables()
# 檢查表格索引是否有效
if table_index > len(tables) or table_index < 1:
raise ValueError("無效的表格索引")
# 抓取指定的表格
specific_table = tables[table_index -1]
# 將表格轉換為DataFrame
df = pd.DataFrame(specific_table[1:], columns=specific_table[0])
# 儲存成Excel文件
df.to_excel("output.xlsx", index=False)
print("Table extracted and saved to output.xlsx")
```
* Test_Fake_File.pdf



* output.xlsx
(擷取條件:第2頁第2個表格)


# 處理具有合併儲存格的表格
```python=
import pdfplumber
import pandas as pd
from openpyxl import Workbook
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font, Alignment
def extract_table_from_pdf(pdf_path, page_number, table_index):
# 打開 PDF 文件
with pdfplumber.open(pdf_path) as pdf:
# 檢查頁碼是否有效
if page_number > len(pdf.pages) or page_number < 1:
raise ValueError("無效的頁碼")
# 獲取指定頁
page = pdf.pages[page_number - 1] # 頁碼從1開始,索引從0開始
# 提取頁面中的所有表格
tables = page.extract_tables()
# 檢查表格索引是否有效
if table_index > len(tables) or table_index < 1:
raise ValueError("無效的表格索引")
# 獲取指定表格
specific_table = tables[table_index - 1] # 表格索引從1開始,索引從0開始
return specific_table
def create_excel_with_merged_cells(table_data, output_path, merge_index):
wb = Workbook()
ws = wb.active
# 填充表格數據
for i, row in enumerate(table_data):
for j, cell in enumerate(row):
if cell is not None:
ws.cell(row=i+1, column=j+1, value=cell)
# 自動調整欄寬
for col in ws.columns:
max_length = 0
column = col[0].column # 取得列字母
for cell in col:
try:
if len(str(cell.value)) > max_length:
max_length = len(cell.value)
except:
pass
adjusted_width = (max_length + 2) # 可以調整加的寬度
ws.column_dimensions[get_column_letter(column)].width = adjusted_width
# 將合併的儲存格加粗 & 置中
ws.merge_cells(merge_index)
mergecell = ws[merge_index.split(':')[0]]
mergecell.font = Font(bold=True) # 設定字型為粗體
mergecell.alignment = Alignment(horizontal='center', vertical='center') # 設定置中對齊
# 保存 Excel 文件
wb.save(output_path)
def main():
# 獲取使用者輸入的頁碼和表格索引
pdf_path = "Text_Fake_File_combine.pdf"
page_number = int(input("請輸入要提取表格的頁碼(從1開始):"))
table_index = int(input("請輸入要提取表格的索引(從1開始):"))
merge_index = str(input("請輸入合併的儲存格座標(例如A1:A4、或B1:C2等格式):"))
# 提取表格
table_data = extract_table_from_pdf(pdf_path, page_number, table_index)
# 保存為 Excel 文件
output_path = "output_combine.xlsx"
create_excel_with_merged_cells(table_data, output_path, merge_index)
print(f"Table extracted and saved to {output_path}")
if __name__ == "__main__":
main()
```
* Text_Fake_File_combine.pdf



## 情境1:表頭在最上方
==(擷取條件:第1頁第1個表格,表頭在第一行)==


## 情境2:表頭在中間
==(擷取條件:第2頁第1個表格,表頭在第二行)==


## 情境3:表頭在奇怪的位置
==(擷取條件:第3頁第1個表格,表頭在第中間跨行,約是B1:C2)==


# 使用OCR辨識單一圖片內的表格內容
透過`pytesseract`套件對圖片進行光學辨識,首先要去[tesseract的GitHub](https://github.com/tesseract-ocr/tesseract?tab=readme-ov-file)下載驅動程式:



```python=
import pytesseract
from PIL import Image
import pandas as pd
ocrpath = "Your tesseract path."
# 如果你使用的是Windows,設置Tesseract的路徑
pytesseract.pytesseract.tesseract_cmd = ocrpath
# 打開圖片
img_path = 'table_image.png' # 圖片文件的路徑
image = Image.open(img_path)
# 使用OCR識別圖片中的表格文本
ocr_result = pytesseract.image_to_string(image, lang='chi_tra')
# 將OCR的結果進行處理,將文本轉換為列表
lines = ocr_result.split("\n")
data = []
for line in lines:
# 根據圖片中的排版,通過分隔符(如空格、Tab)來拆分表格行
row = line.split()
if row: # 如果該行有內容
data.append(row)
# 使用pandas將數據轉換為表格格式
df = pd.DataFrame(data)
# 將表格數據保存為Excel文件
df.to_excel("output_ocr.xlsx", index=False, header=False)
print("表格已成功轉換並保存至 'output_ocr.xlsx'")
```
* table_image.png

==但是中文辨識的成效並不太好......==

# 處理被旋轉過的PDF表格
這邊以聯詠2023年的年報為範例(LY_2023.pdf):

首先,把被旋轉過的頁面轉回來。
```python=
import fitz # PyMuPDF
# 打開 PDF 文件
pdf_file = "LY_2023.pdf" # 替換成你的 PDF 檔案
output_pdf = "rotated_output_LY.pdf" # 保存結果的文件名稱
doc = fitz.open(pdf_file)
# 要旋轉的頁面列表 (頁碼從 1 開始)
pages_to_rotate = [19, 20, 21, 22]
rotation_angle = 90 # 順時針旋轉 90 度
# 針對每個指定頁面進行旋轉
for page_num in pages_to_rotate:
page = doc.load_page(page_num - 1) # PDF 頁碼從 0 開始
page.set_rotation(rotation_angle) # 設定旋轉角度
# 保存旋轉後的 PDF 文件
doc.save(output_pdf)
doc.close()
print(f"Rotated pages saved to '{output_pdf}'")
```
* rotated_output_LY.pdf

:::warning
rotation_angle在少數情況下需要設定成45度,才會轉動頁面,原理目前還不清楚。
:::
然後,重新用pdfplumber讀取表格資料:
```python=
import pdfplumber
import pandas as pd
# 打開PDF文件
with pdfplumber.open("rotated_output_LY.pdf") as pdf:
# 獲取PDF的第一頁
first_page = pdf.pages[12]
# 提取表格
table = first_page.extract_table()
# 將表格轉換為DataFrame
df = pd.DataFrame(table[1:])
print(df)
# 儲存成CSV文件
df.to_csv("output_GY.csv", index=False)
print("Table extracted and saved to output.csv")
```

# 處理斜線標題表格

其實pdfplumber也可以正常讀取資料,但這邊想呈現的效果,是用箭頭指出橫向標題是"條件",縱向標題是"姓名":
```python=
import pdfplumber
import pandas as pd
# 打開PDF文件
with pdfplumber.open("LY_2023.pdf") as pdf:
# 獲取PDF的第一頁
first_page = pdf.pages[15]
# 提取表格
table = first_page.extract_table()
# 將表格轉換為DataFrame
df = pd.DataFrame(table[0:])
# 取得 [0, 0] 的欄位內容
cell_content = df.iloc[0, 0]
# 使用 '\n' 切割內容
title = cell_content.split('\n')
# 覆寫 [0, 0] 的內容為新的格式 "{title[0]}→\\n{title[1]↓}"
if len(title) > 1:
df.iloc[0, 0] = f"{title[0]}→\n{title[1]}↓"
else:
print("The content does not contain a '\\n' to split.")
print(df)
# 儲存成CSV文件
df.to_csv("output_slope.csv", index=False)
print("Table extracted and saved to output.csv")
```

# 小工具:PDF頁面擷取
可以將指定頁數的PDF頁面截圖存檔。
```python=
import fitz # PyMuPDF
# 打開 PDF 文件
pdf_file = 'LY_2023.pdf' # 替換成你的 PDF 檔案路徑
doc = fitz.open(pdf_file)
# 需要截圖的頁面
pages_to_screenshot = [13]
# 針對每個頁面進行截圖並保存
for page_num in pages_to_screenshot:
page = doc.load_page(page_num - 1) # PyMuPDF 的頁面是從 0 開始計算
pix = page.get_pixmap() # 將頁面轉換為圖像
image_file = f'pdf_ss_{page_num}.png'
pix.save(image_file) # 保存為 PNG 檔案
print(f'Saved: {image_file}')
# 關閉 PDF 文件
doc.close()
```
:::danger
**★ 關於PDF複製內容後出現亂碼**
在複製聚陽(1477)的年報內容時出現以下亂碼,檢查後發現文件有內嵌以下字體:


* DFKaiShu-SB-Estd-Bf-ETen-B5-H
* Helvetica-Bold
* PMingLiU-ETen-B5-H
* PalatinoLinotype-Bold
* PalatinoLinotype-Roman
* TimesNewRomanPS-BoldMT
* TimesNewRomanPSMT
PDF檔案會正常顯示,不過當複製貼上、以及用程式讀取PDF內容時,就會變成亂碼,下載字體後仍無法正常讀取,將PDF轉成圖片進行OCR效果不好,Google文件、文件轉換程式、修改檔案編碼等方法只能得到充滿亂碼的新文件,目前仍不知道該如何處理。
- [字型為「DFKAI-sb 標楷體」,pdf中的字型會變成破字](https://forum.aspose.com/t/aspose-pdf-html-pdf-dfkai-sb-pdf/169286)
- [How to solve no unicode mapping error from PDFBox?](https://stackoverflow.com/questions/58829597/how-to-solve-no-unicode-mapping-error-from-pdfbox)