PDF 파일 구글 시트 범위별로 분할 자동화

소개

학​술지 편집 후 만들어진 파일을 페이지별로 업로드하기 위해 PDF 분할

학​술지 편집 후 만들어진 파일을 페이지별로 업로드하기 위해 PDF 분할하는 작업은 원고편집인에게 자동화 숙원 작업 중 하나이다. 파일이 수정될때마다 분할하면 한펀 원고에도 백번이상 작업해야 될 수 있다. PDF와 구글시트라는 서로 다른 프로그램을 오가며 작업을 한다는 것은 기존 원고편집인에게는 사무실에 로보트나 도입되야 가능할 것이라고 생각되는 작업이었다. 칼퇴자동화 첫수업에 스터디장의 영업비밀 창고대방출과 스터디원들의 실패담 공개의 용기에 힘입어 원고편집인의 숙원 작업 중 하나를 자동화했다.

진행 방법

고수들께 사전에 문의하여 얻은 조언은 다음과 같았다.

스터디장께서 오프라인 첫 모임에 파이썬을 이용하는 것을 추천해주셨고,

오프라인 뒷풀이에서 저한테 첫 숙원사업인 참고문헌 자동화에 퍼플렉시티를 제공하여 알려주신 분이 파이썬을 쓰는 방법을 클로드에게 물어보면 된다고 하셨다. 아울러 프로그램은 실무자가 만드는것이 더 낫다는 개발자로서의 경험담도 알려주셨다.

수업 전에 만들어보려고 이 방법, 저 궁리 다해봤지만 결국 빈손으로 수업에 갔다가 스터디장의 아낌없는 창고대방출과 스터디원의 열정적인 실패담 공개에 용기를 얻고 비개발자의 로망인 파이썬 첫 코딩을 했다.

창고대방출 1원칙.간단한 프롬프트로 용기있게 시작했다.

"구글시트에서 값을 받아 PDF 파일을 특정 페이지만 추출하는 프로그램을 작성해줘"

google docs 한국어 google docs 한국어 google docs 한국어 google docs kor

수업 전에는 엄두도 못냈지만 창고대방출 2.뻔뻔스럽게 계속 물었다.

"Sheets API를 활성화하는 방법을 알려줘"

007 한국어 google 검색 엔진 한국어 google 검색 엔진 한국어 google 검색 엔진 한국어 google 검색

첫 소개시간에 들은 유튜브 API 를 시험해 본것도 기억나서 계속 도전했다,

그리고 계속 질문.창고대방출3. 오류를 묻는다.

"OAuth 동의 화면 구성에서 앱이름이 입력이 안되"

"OAuth 동의 화면에서 앱 이름에 커서가 들어가지가 않아"

"OAuth 클라이언트 ID 가 없어"

"credentials.json 파일을 다운로드 방법이 뭐야"

그러다가 드디어 파이선에 도달했다

"Python 스크립트를 디렉토리에 저장하는 방법알려줘"

휴대폰에 있는 중국어 앱의 스크린샷


"Python 을 PC에서 사용하는 방법 알려줘"

다음에는 말로만 듣던 비주얼베이직까지 처음으로 깔았다.

결국 나의 프롬프트는 질문으로만 되었다

"Google Sheets PDF Page Extractor 를 어떻게 어디에 붙여넣어야 되니"

다음은 오류와의 싸움

창고대방출4. 한수 더 떠 나의 다음 프롬프트는 오류코드로만 되었다.

"오류코드"를 계속 클로드에 붙였다.

"액세스 차단됨: PDF Extractor 앱이 Google의 인증 절차를 완료하지 않았습니다"

"사용자 인증 정보 만들기" → "OAuth 클라이언트 ID" 선택 3. 애플리케이션 유형: "데스크톱 앱" 선택 후 이름: "PDF Extractor" 입력에서 커서가 입력이 안됨"

그 후 2시간에 걸친 오류코드와의 싸움

이때 믿는 구석은 수업시간 스터디장의 조언이었다.

창고대방출5. "클로드가 안된다고 해도 된다고 하면 된다"

결국 성공했다

한국어 및 중국어 단어 목록 스크린샷

감사합니다. 저희 스터디와 지피터스 파이팅!입니다

import os.path from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request from googleapiclient.discovery import build import pickle from PyPDF2 import PdfReader, PdfWriter class SheetsPDFExtractor: def __init__(self): self.SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly'] self.creds = None def authenticate(self): if os.path.exists('token.pickle'): with open('token.pickle', 'rb') as token: self.creds = pickle.load(token) if not self.creds or not self.creds.valid: if self.creds and self.creds.expired and self.creds.refresh_token: self.creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', self.SCOPES) self.creds = flow.run_local_server(port=0) with open('token.pickle', 'wb') as token: pickle.dump(self.creds, token) def get_sheet_data(self, spreadsheet_id, range_name): service = build('sheets', 'v4', credentials=self.creds) sheet = service.spreadsheets() result = sheet.values().get( spreadsheetId=spreadsheet_id, range=range_name ).execute() return result.get('values', []) def parse_page_ranges(self, range_string): pages = set() ranges = range_string.replace(' ', '').split(',') for r in ranges: if '-' in r: start, end = map(int, r.split('-')) pages.update(range(start, end + 1)) else: pages.add(int(r)) return sorted(list(pages)) def extract_pdf_pages(self, input_pdf_path, output_pdf_path, pages_to_extract): pdf_reader = PdfReader(input_pdf_path) pdf_writer = PdfWriter() max_pages = len(pdf_reader.pages) for page_num in pages_to_extract: if 1 <= page_num <= max_pages: pdf_writer.add_page(pdf_reader.pages[page_num - 1]) else: print(f'Warning: Page {page_num} is out of range (max: {max_pages})') with open(output_pdf_path, 'wb') as output_file: pdf_writer.write(output_file) def process_batch(self, spreadsheet_id, range_name, input_pdf_folder, output_pdf_folder): self.authenticate() data = self.get_sheet_data(spreadsheet_id, range_name) for row in data: try: if len(row) >= 2: filename = row[0] pages = self.parse_page_ranges(row[1]) input_path = os.path.join(input_pdf_folder, filename) output_path = os.path.join(output_pdf_folder, f'extracted_{filename}') if os.path.exists(input_path): self.extract_pdf_pages(input_path, output_path, pages) print(f'Successfully processed {filename} (Pages: {row[1]})') else: print(f'File not found: {filename}') except Exception as e: print(f'Error processing {filename}: {str(e)}') def main(): SPREADSHEET_ID = '1IJ_OZ2hx_7bwD-F7XkHNc-7Laed4MUl1NYBXNfGcnSw' RANGE_NAME = '시트1!A2:B' # 실제 시트 이름으로 변경 INPUT_PDF_FOLDER = 'input_pdfs' OUTPUT_PDF_FOLDER = 'output_pdfs' if not os.path.exists(OUTPUT_PDF_FOLDER): os.makedirs(OUTPUT_PDF_FOLDER) extractor = SheetsPDFExtractor() extractor.process_batch(SPREADSHEET_ID, RANGE_NAME, INPUT_PDF_FOLDER, OUTPUT_PDF_FOLDER) if __name__ == '__main__': main()

사투는 2시간이었지만.결과는 20-200시간 절약이다.

한사람이 희생해서 여러 사람이 살 수 있었다.

고목나무에 꽃을 필려면 용기와 헌신으로 가능할 수 있다.

단체로 하니 20-20년간 숙원사업도 가능했다. 결국 문제는 용기와 된다는 믿음이었다.

단체로 해야 빠르다는 지피터스의 문구때문에 지원했고 실감했다.

나도 도움을 줄수 있어야 겠다

4
2개의 답글

👉 이 게시글도 읽어보세요