์๋ ํ์ธ์, ์ฝ๋ฉ ์น๊ตฌ ์ฌ๋ฌ๋ถ! ๐ ๋ณต์กํด ๋ณด์ด๋ PDF ํ์ผ ์ฒ๋ฆฌ, ํ์ด์ฌ์ ์ด์ฉํ๋ฉด ์๊ฐ๋ณด๋ค ์ฝ๊ณ ์ฌ๋ฏธ์๊ฒ ํ ์ ์๋ค๋ ์ฌ์ค, ์๊ณ ๊ณ์ จ๋์? ๐ง ์ค๋ ์ฐ๋ฆฌ๋ ์ด๋ณด์๋ ์ฝ๊ฒ ๋ฐ๋ผ ํ ์ ์๋ ์์ ์ค์ฌ์ PDF ์ฒ๋ฆฌ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณผ ๊ฑฐ์์. ์ด ๊ฐ์ด๋๋ง ์๋ค๋ฉด, ์ง๋ฃจํ๋ PDF ๋ฌธ์ ์์ ์ด ์์๊ฐ์ ์๋ํ๋ ์ ์์ต๋๋ค! ๐
1. ์ ํ์ด์ฌ์ผ๋ก PDF๋ฅผ ์ฒ๋ฆฌํด์ผ ํ ๊น์? ๐ค
PDF(Portable Document Format)๋ ๋ฌธ์์ ๋ ์ด์์์ ์ ์งํ๋ฉฐ ๊ณต์ ํ๊ธฐ ์ํ ํ์ค ํ์์ ๋๋ค. ๋ณด๊ณ ์, ๊ณ์ฝ์, ๋ ผ๋ฌธ ๋ฑ ์ ๋ง ๋ค์ํ ๊ณณ์์ ์ฌ์ฉ๋์ฃ . ํ์ง๋ง ์ด ๋ง์ ๋ฌธ์๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฑด ์ ๋ง ๊ณ ๋ ์ผ์ ๋๋ค.
⚡️ ์๋ํ: ์๋ฐฑ ์ฅ์ PDF์์ ํน์ ์ ๋ณด๋ฅผ ์ถ์ถํ๊ฑฐ๋, ์ฌ๋ฌ ํ์ผ์ ํ๋๋ก ํฉ์น๋ ์์ ์ ์์๊ฐ์ ์ฒ๋ฆฌํ ์ ์์ด์.
๐ ️ ๋ฐ์ดํฐ ์ถ์ถ: PDF๋ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ(JSON, CSV ๋ฑ)๊ฐ ์๋๊ธฐ ๋๋ฌธ์, ํ์ด์ฌ์ ์ด์ฉํด ํ์ํ ํ ์คํธ๋ ํ๋ฅผ ์ ํํ๊ฒ ๋ฝ์๋ผ ์ ์์ต๋๋ค.
๐ ์ผ๊ด ์ฒ๋ฆฌ: ์ฌ๋ฌ ๊ฐ์ PDF ํ์ผ์ ๋์์ ์์ ํ๊ฑฐ๋ ๋ณํํ๋ ๊ฒ์ด ๊ฐ๋ฅํฉ๋๋ค.
ํ์ด์ฌ์๋ PDF ์ฒ๋ฆฌ๋ฅผ ์ํ ๊ฐ๋ ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ด ๋ง์ง๋ง, ์ค๋์ ๊ฐ์ฅ ๋์ค์ ์ด๊ณ ์ฌ์ฉํ๊ธฐ ์ฌ์ด **PyPDF2**์ ํ
์คํธ ์ถ์ถ์ ์ ์ฉํ **pdfminer.six**๋ฅผ ์ค์ฌ์ผ๋ก ์์๋ณผ๊ฒ์!
2. ์ค๋น๋ฌผ: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์นํ๊ธฐ ๐ฅ
๊ฐ์ฅ ๋จผ์ ํฐ๋ฏธ๋์ด๋ ๋ช ๋ น ํ๋กฌํํธ์์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ค์นํด์ผ ํฉ๋๋ค.
pip install PyPDF2
pip install pdfminer.six
3. PDF ํฉ์น๊ธฐ: ๊ฒฐํผ์ ํ๋๋ก! ๐ (PyPDF2)
์ฌ๋ฌ ๊ฐ์ ๋ณด๊ณ ์๋ ์ฅ์ ํ๋์ ์ต์ข
PDF ํ์ผ๋ก ํฉ์ณ์ผ ํ ๋๊ฐ ๋ง์ต๋๋ค. PyPDF2์ PdfMerger ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๋จํ๊ฒ ํด๊ฒฐ๋ผ์!
import PyPDF2
# PdfMerger ๊ฐ์ฒด ์์ฑ
merger = PyPDF2.PdfMerger()
# ํฉ์น ํ์ผ๋ค์ ๋ฆฌ์คํธ (์์ ํ์ผ๋ช
)
file_list = ['chapter1.pdf', 'chapter2.pdf', 'appendix.pdf']
for filename in file_list:
# ๊ฐ ํ์ผ์ merger์ ์ถ๊ฐ
try:
merger.append(filename)
except FileNotFoundError:
print(f"๊ฒฝ๊ณ : ํ์ผ {filename}์ ์ฐพ์ ์ ์์ต๋๋ค. ๊ฑด๋๋๋๋ค.")
continue
# ์๋ก์ด ํ์ผ๋ก ์ ์ฅ
# 'wb'๋ Write Binary (๋ฐ์ด๋๋ฆฌ ์ฐ๊ธฐ) ๋ชจ๋๋ฅผ ์๋ฏธํฉ๋๋ค.
with open("combined_document.pdf", "wb") as output_file:
merger.write(output_file)
merger.close()
print("๐ PDF ํ์ผ ํฉ์น๊ธฐ ์๋ฃ! 'combined_document.pdf'๋ฅผ ํ์ธํ์ธ์.")
✅ ์ ๊น ํ! merger.append(filename, pages=(0, 2)) ์ ๊ฐ์ด pages ์ธ์๋ฅผ ์ฌ์ฉํ๋ฉด, ํ์ผ์ ์ฒซ ํ์ด์ง๋ถํฐ 3๋ฒ์งธ ํ์ด์ง (์ธ๋ฑ์ค 2 ์ง์ ) ๊น์ง๋ง ๊ฐ์ ธ์ ํฉ์น ์๋ ์์ต๋๋ค.
4. PDF์์ ํ ์คํธ ์ถ์ถํ๊ธฐ: ์ ๋ณด๋ ์์คํ๋๊น! ๐ต️♀️ (PyPDF2 & pdfminer.six)
PDF์์ ํ
์คํธ๋ฅผ ์ถ์ถํ๋ ๊ฒ์ ๋ฐ์ดํฐ ๋ถ์์ ์ฒซ๊ฑธ์์
๋๋ค. ๊ฐ๋จํ ์ถ์ถ์ PyPDF2๋ก ์ถฉ๋ถํ์ง๋ง, ๋ณต์กํ ๋ ์ด์์์ ํ
์คํธ๋ฅผ ์ ํํ๊ฒ ์ถ์ถํ๋ ค๋ฉด pdfminer.six๊ฐ ๋ ๊ฐ๋ ฅํ ์ ์์ต๋๋ค.
A. ๊ฐ๋จํ ํ ์คํธ ์ถ์ถ (PyPDF2)
ํ์ด์ง ๋ฒํธ, ์ ๋ชฉ ๋ฑ ๊ฐ๋จํ ์ ๋ณด๋ง ํ์ํ ๋ ์ ์ฉํฉ๋๋ค.
import PyPDF2
# ํ์ผ์ ๋ฐ์ด๋๋ฆฌ ์ฝ๊ธฐ ๋ชจ๋('rb')๋ก ์ฝ๋๋ค.
try:
with open('report.pdf', 'rb') as file:
reader = PyPDF2.PdfReader(file)
# ์ ์ฒด ํ์ด์ง ์ ํ์ธ
num_pages = len(reader.pages)
print(f"๋ฌธ์์ ์ด ํ์ด์ง ์: {num_pages}์ฅ")
# ์ฒซ ๋ฒ์งธ ํ์ด์ง(์ธ๋ฑ์ค 0)์์ ํ
์คํธ ์ถ์ถ
first_page = reader.pages[0]
text = first_page.extract_text()
# ์ถ์ถ๋ ํ
์คํธ ์ถ๋ ฅ (์ผ๋ถ๋ง)
print("\n--- ์ฒซ ํ์ด์ง ํ
์คํธ (์๋ถ๋ถ 500์) ---")
print(text[:500] + "...")
print("--------------------------------------")
except FileNotFoundError:
print("❌ 'report.pdf' ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค. ํ์ผ์ ํ์ธํด์ฃผ์ธ์.")
except Exception as e:
print(f"⚠️ ํ
์คํธ ์ถ์ถ ์ค ์ค๋ฅ ๋ฐ์: {e}")
B. ๊ณ ๊ธ ํ ์คํธ ์ถ์ถ (pdfminer.six)
pdfminer.six๋ ํ
์คํธ์ ์์น ์ ๋ณด๊น์ง ๋ณด์กดํ๋ฉฐ ์ถ์ถํ ์ ์์ด, ๋ณต์กํ ํ๋ ๋ค๋จ ํธ์ง ๋ฌธ์๋ฅผ ์ฒ๋ฆฌํ ๋ ์ ๋ฆฌํฉ๋๋ค. ์ฌ์ฉ๋ฒ์ ๋ค์ ๋ณต์กํ์ง๋ง, ์๋ ์ฝ๋๋ฅผ ํตํด ์ฝ๊ฒ ์ ๊ทผํ ์ ์์ต๋๋ค.
from io import StringIO
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser
def extract_text_from_pdf(pdf_path):
output_string = StringIO()
with open(pdf_path, 'rb') as in_file:
parser = PDFParser(in_file)
doc = PDFDocument(parser)
rsrcmgr = PDFResourceManager()
# LAParams ์ค์ : ํ
์คํธ ๋ ์ด์์ ๋ถ์ ๋งค๊ฐ๋ณ์
# detect_vertical=True๋ ์์ง ํ
์คํธ ๊ฐ์ง์ ๋์์ ์ค๋๋ค.
laparams = LAParams(line_overlap=0.5, char_margin=2.0, word_margin=0.1, line_margin=0.5, boxes_flow=0.5, detect_vertical=False)
# TextConverter: ์ถ์ถ๋ ๋ด์ฉ์ output_string์ ์ฐ๋๋ก ์ค์
device = TextConverter(rsrcmgr, output_string, laparams=laparams)
interpreter = PDFPageInterpreter(rsrcmgr, device)
# ๋ชจ๋ ํ์ด์ง๋ฅผ ์ํํ๋ฉฐ ํ
์คํธ ์ถ์ถ
for page in PDFPage.create_pages(doc):
interpreter.process_page(page)
return output_string.getvalue()
# ์ฌ์ฉ ์์
try:
full_text = extract_text_from_pdf('report.pdf')
print("\n--- pdfminer.six ์ถ์ถ ํ
์คํธ (์๋ถ๋ถ 500์) ---")
print(full_text[:500] + "...")
print("----------------------------------------------")
except FileNotFoundError:
print("❌ 'report.pdf' ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.")
except Exception as e:
print(f"⚠️ pdfminer.six ์ถ์ถ ์ค ์ค๋ฅ ๋ฐ์: {e}")
5. PDF ํ์ด์ง ํ์ ๋ฐ ์ํธํ/๋ณตํธํ ๐ (PyPDF2)
๋ฌธ์์ ๋ณด์์ ๊ฐํํ๊ฑฐ๋, ์ค์บ๋ ๋ฌธ์์ ๋ฐฉํฅ์ ์์ ํ ๋ ์ ์ฉํฉ๋๋ค.
A. ํน์ ํ์ด์ง ํ์ ํ๊ธฐ ↩️
์ค์บ๋ ๋ฌธ์ ์ค ์ผ๋ถ ํ์ด์ง๊ฐ ๊ฑฐ๊พธ๋ก ๋์ด์์ ๋ ์ฌ์ฉํฉ๋๋ค.
# 'rotate_original.pdf'๋ฅผ ์ด์ด 'rotated_output.pdf'๋ก ์ ์ฅํ๋ค๊ณ ๊ฐ์
try:
with open('rotate_original.pdf', 'rb') as input_file:
reader = PyPDF2.PdfReader(input_file)
writer = PyPDF2.PdfWriter()
for i in range(len(reader.pages)):
page = reader.pages[i]
# 2๋ฒ์งธ ํ์ด์ง (์ธ๋ฑ์ค 1)๋ฅผ ์๊ณ ๋ฐฉํฅ์ผ๋ก 90๋ ํ์
if i == 1:
page.rotate(90)
print(f"✔️ {i+1}๋ฒ์งธ ํ์ด์ง๋ฅผ 90๋ ํ์ ํ์ต๋๋ค.")
writer.add_page(page)
with open('rotated_output.pdf', 'wb') as output_file:
writer.write(output_file)
print("๐ ํ์ด์ง ํ์ ์ด ์๋ฃ๋์์ต๋๋ค!")
except FileNotFoundError:
print("❌ 'rotate_original.pdf' ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.")
B. PDF ์ํธ ์ค์ ํ๊ธฐ ๐
์ค์ํ ๋ฌธ์๋ฅผ ๋ณดํธํ๊ธฐ ์ํด ์ํธ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.
try:
with open('protected_original.pdf', 'rb') as input_file:
reader = PyPDF2.PdfReader(input_file)
writer = PyPDF2.PdfWriter()
# ์๋ณธ ํ์ด์ง๋ฅผ ๋ชจ๋ ์๋ก์ด Writer์ ๋ณต์ฌ
for page in reader.pages:
writer.add_page(page)
# ์ํธ ์ค์ (์ํธ: '1234')
# ๊ฒฝ๊ณ : ์ด ๋ฐฉ์์ ๊ฐ๋ ฅํ ์ํธํ๊ฐ ์๋๋ฏ๋ก ์ค์ํ ๋ฌธ์๋ ๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ธ์.
writer.encrypt('1234')
with open('protected_output.pdf', 'wb') as output_file:
writer.write(output_file)
print("๐ PDF์ ์ํธ '1234' ์ค์ ์๋ฃ!")
except FileNotFoundError:
print("❌ 'protected_original.pdf' ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.")
6. ๋ง๋ฌด๋ฆฌํ๋ฉฐ: PDF ์ฒ๋ฆฌ, ์ด์ ๋๋ ต์ง ์์์! ๐ช
ํ์ด์ฌ์ ์ด์ฉํ PDF ์ฒ๋ฆฌ๋ ์ฌ๊ธฐ์ ๋ณด์ฌ๋๋ฆฐ ๊ฒ๋ณด๋ค ํจ์ฌ ๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. PyPDF2์ pdfminer.six ์ธ์๋ ๋ฐ์ดํฐ๋ฅผ ํ ํ์์ผ๋ก ์ถ์ถํ๋ ๋ฐ ํนํ๋ **tabula-py**๋, PDF๋ฅผ ์ด๋ฏธ์ง๋ก ๋ณํํ๋ Pillow ๋ฑ ์ ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ง์ต๋๋ค.
์ค๋ ๋ฐฐ์ด ๊ธฐ๋ณธ ์ง์๊ณผ ์์ ๋ฅผ ๋ฐํ์ผ๋ก, ์ฌ๋ฌ๋ถ์ ์ผ์ ์ ๋ฌด๋ ํ์ต ๊ณผ์ ์์ ๋ฐ์ํ๋ PDF ์ฒ๋ฆฌ ๋ฌธ์ ๋ฅผ ํ์ด์ฌ์ผ๋ก ์ค๋งํธํ๊ฒ ํด๊ฒฐํด ๋ณด์ธ์! ์ฝ๋ฉ ์ค๋ ฅ๋ ๋๊ณ , ์๊ฐ๋ ์ ์ฝํ๋ ์ผ์์ด์กฐ์ ํจ๊ณผ๋ฅผ ๋๋ฆด ์ ์์ ๊ฑฐ์์.

๋๊ธ
๋๊ธ ์ฐ๊ธฐ