📋 整個流程一目了然
你只需要:書本問題截圖 + 答案文字,Claude 幫你完成以下全部步驟:
| 你要做的 | Claude 做的 |
|---|---|
| 拍書本截圖,貼給 Claude | 讀圖,提取問題文字 |
| 確認問題和答案正確 | 用 python-docx 生成排版好的 .docx |
| 等印表機出紙 | 確認頁數 → 設雙面 → 發送打印 |
基督生平第二冊第四單元課後複習:測驗 4A / 4B / 4C,共 16 題,最終排版成剛好 2 頁 A4,雙面打印到 Brother MFC-L2770DW。
🔧 前置準備
確認以下套件已安裝在 D:\Backup\Downloads\.venv\:
source /d/Backup/Downloads/.venv/Scripts/activate pip install python-docx pywin32
確認印表機名稱(一次就夠,記住名字):
PYTHONUTF8=1 py -c "
import win32print
for p in win32print.EnumPrinters(
win32print.PRINTER_ENUM_LOCAL | win32print.PRINTER_ENUM_CONNECTIONS):
print(p[2])
"
輸出範例:Brother MFC-L2770DW series Printer — 記住這個名字,後面會用到。
📄 用 Python 建立排版好的 Word 文件
核心套件是 python-docx。以下是排版規格和對應代碼:
| 排版設定 | 值 | 代碼 |
|---|---|---|
| 紙張 | A4 | section.page_height = Cm(29.7) |
| 上下邊距 | 2.2 cm | section.top_margin = Cm(2.2) |
| 左右邊距 | 2.5 cm | section.left_margin = Cm(2.5) |
| 正文字體 | 11pt,行距 15pt | run.font.size = Pt(11) |
| 問題 | 11pt 斜體 | run.font.italic = True |
| 答案 | 11pt 粗體,藍色 | run.font.color.rgb = RGBColor(0x1F,0x49,0x7D) |
from docx import Document
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
doc = Document()
BLUE = RGBColor(0x1F, 0x49, 0x7D)
# ① 設 A4 邊距
for s in doc.sections:
s.page_height = Cm(29.7)
s.page_width = Cm(21.0)
s.top_margin = Cm(2.2)
s.bottom_margin = Cm(2.2)
s.left_margin = Cm(2.5)
s.right_margin = Cm(2.5)
# ② 加標題
p = doc.add_paragraph()
p.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p.add_run('課程名稱 — 第X單元複習 2026-XX-XX')
r.font.size = Pt(14); r.font.bold = True
# ③ 加區塊標題(帶底線)
def section_header(title):
para = doc.add_paragraph()
para.paragraph_format.space_before = Pt(10)
run = para.add_run(title)
run.font.size = Pt(12); run.font.bold = True
run.font.color.rgb = BLUE
# 加底線
pPr = para._p.get_or_add_pPr()
pBdr = OxmlElement('w:pBdr')
bottom = OxmlElement('w:bottom')
bottom.set(qn('w:val'), 'single')
bottom.set(qn('w:sz'), '4')
bottom.set(qn('w:color'), '1F497D')
pBdr.append(bottom); pPr.append(pBdr)
# ④ 加問題+答案
def qa(q_text, a_text):
# 問題(斜體)
pq = doc.add_paragraph()
pq.paragraph_format.space_before = Pt(5)
rq = pq.add_run(q_text)
rq.font.size = Pt(11); rq.font.italic = True
# 答案(粗體藍色,縮排)
pa = doc.add_paragraph()
pa.paragraph_format.left_indent = Cm(0.6)
ra = pa.add_run(a_text)
ra.font.size = Pt(11); ra.font.bold = True
ra.font.color.rgb = BLUE
# ⑤ 使用
section_header('測驗 4A — 耶穌的受洗')
qa('Q1. 在耶穌受洗時,祂大約多少歲?', 'a) 祂的受洗 b) 大約 30 歲(4A.2b)')
# ⑥ 儲存
doc.save('D:/tmp/學習筆記.docx')
print('完成!')
填空題:問題用「___」表示空白,答案用「」括起來
qa('填寫申6:4:"___ 啊,你要聽!"', '「以色列」啊,你要聽!')
選擇題:選項用 □ 開頭,答案行寫「答:x, y」
📏 用 win32com 確認剛好 2 頁
存完 .docx 後,用以下代碼確認頁數。如果不是 2 頁,調整字體大小再重試。
import win32com.client, os
path = os.path.abspath('D:/tmp/學習筆記.docx')
word = win32com.client.Dispatch('Word.Application')
word.Visible = False
doc = word.Documents.Open(path)
pages = doc.ComputeStatistics(2) # 2 = wdStatisticPages
print(f'頁數: {pages}')
doc.Close(False)
word.Quit()
| 結果 | 調整方法 |
|---|---|
| pages = 1 | 把字體從 11pt 改 12pt,或把 space_before 從 5pt 改 8pt |
| pages = 2 ✅ | 完美,直接打印 |
| pages = 3 | 把字體從 11pt 改 10pt,或把邊距從 2.5 改 2.0 |
🖨️ 雙面打印到 Brother(正確方法)
以下寫法一定會報錯(TypeError: unexpected keyword argument 'Duplex'):
doc.PrintOut(Duplex=True) ❌
doc.PrintOut(Duplex=1) ❌
doc.PrintOut(Printer='Brother...') ❌
正確方法是:先用 win32print 修改 DevMode,再調用 PrintOut。
正確的三步流程:
import win32print, win32com.client, os
PRINTER = 'Brother MFC-L2770DW series Printer'
PATH = os.path.abspath('D:/tmp/學習筆記.docx')
# ── Step 1:設雙面 ─────────────────────────────
h = win32print.OpenPrinter(PRINTER,
{'DesiredAccess': win32print.PRINTER_ALL_ACCESS})
s = win32print.GetPrinter(h, 2)
s['pDevMode'].Duplex = 2 # 2 = 長邊翻頁(標準雙面)
win32print.SetPrinter(h, 2, s, 0)
win32print.ClosePrinter(h)
# ── Step 2:打印 ───────────────────────────────
old = win32print.GetDefaultPrinter()
win32print.SetDefaultPrinter(PRINTER)
word = win32com.client.Dispatch('Word.Application')
word.Visible = False
doc = word.Documents.Open(PATH)
doc.PrintOut(False, False, 0, '', '', '', 0, 1) # 全部位置參數!
doc.Close(False)
word.Quit()
# ── Step 3:恢復 ───────────────────────────────
h2 = win32print.OpenPrinter(PRINTER,
{'DesiredAccess': win32print.PRINTER_ALL_ACCESS})
s2 = win32print.GetPrinter(h2, 2)
s2['pDevMode'].Duplex = 1 # 改回關閉
win32print.SetPrinter(h2, 2, s2, 0)
win32print.ClosePrinter(h2)
win32print.SetDefaultPrinter(old)
print('已發送到 Brother 印表機 ✅')
看到「已發送到 Brother 印表機 ✅」後,走去印表機等出紙。Brother 會自動翻面,只需放入一張 A4 紙(正反面自動打印)。
🚀 完整整合腳本(存成 .py 文件用)
把以上所有步驟整合成一個完整腳本。每次要做新課程時,只需改 問題和答案部分,其餘不用動。
儲存到 D:/tmp/build_study_notes.py,然後執行:
PYTHONUTF8=1 py D:/tmp/build_study_notes.py
# -*- coding: utf-8 -*-
# ══════════════════════════════════════════════
# 學習筆記排版 + 雙面打印模板
# 使用方法:修改 「問題和答案」 區塊,其餘不動
# ══════════════════════════════════════════════
from docx import Document
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import win32print, win32com.client, os
# ── 設定 ──────────────────────────────────────
OUTPUT = 'D:/tmp/學習筆記.docx' # 輸出路徑
PRINTER = 'Brother MFC-L2770DW series Printer'
BLUE = RGBColor(0x1F, 0x49, 0x7D)
GREY = RGBColor(0x55, 0x55, 0x55)
# ── 建立文件 ──────────────────────────────────
doc = Document()
for s in doc.sections:
s.page_height = Cm(29.7); s.page_width = Cm(21.0)
s.top_margin = Cm(2.2); s.bottom_margin = Cm(2.2)
s.left_margin = Cm(2.5); s.right_margin = Cm(2.5)
def section_header(title):
p = doc.add_paragraph()
p.paragraph_format.space_before = Pt(10)
p.paragraph_format.space_after = Pt(3)
p.paragraph_format.line_spacing = Pt(16)
r = p.add_run(title); r.font.size = Pt(12)
r.font.bold = True; r.font.color.rgb = BLUE
pPr = p._p.get_or_add_pPr()
pBdr = OxmlElement('w:pBdr')
b = OxmlElement('w:bottom')
b.set(qn('w:val'), 'single'); b.set(qn('w:sz'), '4')
b.set(qn('w:color'), '1F497D')
pBdr.append(b); pPr.append(pBdr)
def qa(q_text, a_text):
pq = doc.add_paragraph()
pq.paragraph_format.space_before = Pt(5)
pq.paragraph_format.space_after = Pt(1)
pq.paragraph_format.line_spacing = Pt(15)
rq = pq.add_run(q_text)
rq.font.size = Pt(11); rq.font.italic = True
pa = doc.add_paragraph()
pa.paragraph_format.space_before = Pt(0)
pa.paragraph_format.space_after = Pt(2)
pa.paragraph_format.line_spacing = Pt(15)
pa.paragraph_format.left_indent = Cm(0.6)
ra = pa.add_run(a_text)
ra.font.size = Pt(11); ra.font.bold = True
ra.font.color.rgb = BLUE
# ══════════════════════════════════════════════
# ↓↓↓ 修改這裡:標題、問題、答案 ↓↓↓
# ══════════════════════════════════════════════
# 標題
pt = doc.add_paragraph()
pt.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
pt.paragraph_format.space_after = Pt(6)
r1 = pt.add_run('課程名稱 — 第X單元複習')
r1.font.size = Pt(14); r1.font.bold = True
r2 = pt.add_run(' 2026-XX-XX')
r2.font.size = Pt(10); r2.font.color.rgb = GREY
# 測驗 A
section_header('測驗 A — 主題名稱')
qa('Q1. 問題文字...', 'a) 答案一 b) 答案二(參考頁碼)')
qa('Q2. 填空:"___"', '「填入答案」')
# 測驗 B
section_header('測驗 B — 主題名稱')
qa('Q1. 問題...', '答案(參考頁碼)')
# ══════════════════════════════════════════════
# ↑↑↑ 修改到這裡為止 ↑↑↑
# ══════════════════════════════════════════════
# 頁腳
pf = doc.add_paragraph()
pf.paragraph_format.space_before = Pt(10)
pf.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER
rf = pf.add_run('★ = 課程重點必背 | 括號內為教材參考頁碼')
rf.font.size = Pt(9); rf.font.color.rgb = GREY
doc.save(OUTPUT)
print(f'✅ 文件已儲存:{OUTPUT}')
# ── 確認頁數 ──────────────────────────────────
word = win32com.client.Dispatch('Word.Application')
word.Visible = False
d = word.Documents.Open(os.path.abspath(OUTPUT))
pages = d.ComputeStatistics(2)
print(f'📄 頁數:{pages}')
d.Close(False); word.Quit()
if pages != 2:
print(f'⚠️ 不是 2 頁!請調整字體大小再重跑。')
exit(1)
# ── 雙面打印 ──────────────────────────────────
h = win32print.OpenPrinter(PRINTER, {'DesiredAccess': win32print.PRINTER_ALL_ACCESS})
s = win32print.GetPrinter(h, 2)
s['pDevMode'].Duplex = 2
win32print.SetPrinter(h, 2, s, 0)
win32print.ClosePrinter(h)
old = win32print.GetDefaultPrinter()
win32print.SetDefaultPrinter(PRINTER)
word2 = win32com.client.Dispatch('Word.Application')
word2.Visible = False
d2 = word2.Documents.Open(os.path.abspath(OUTPUT))
d2.PrintOut(False, False, 0, '', '', '', 0, 1)
d2.Close(False); word2.Quit()
h2 = win32print.OpenPrinter(PRINTER, {'DesiredAccess': win32print.PRINTER_ALL_ACCESS})
s2 = win32print.GetPrinter(h2, 2)
s2['pDevMode'].Duplex = 1
win32print.SetPrinter(h2, 2, s2, 0)
win32print.ClosePrinter(h2)
win32print.SetDefaultPrinter(old)
print(f'🖨️ 已發送到 {PRINTER}')
⚡ 做成 Claude 技能:/print-study-notes
把這個流程保存為 Claude 技能,下次只需一句話就能啟動:
繼續基督生平第五單元任務 (附上書本問題截圖)
技能文件位置:D:\Backup\Downloads\.claude\commands\print-study-notes.md
Claude 有持久記憶,會記住每個單元的文件路徑和已完成狀態。
只需說「繼續第X單元任務」,Claude 就會找到對應文件繼續工作。