파이썬으로 구글 시트 자동 연동하기 (gspread)
팀이 같이 쓰는 구글 시트에 매일 매출이나 실적을 손으로 옮겨 적어본 적 있으세요? 야근하면서 숫자 몇십 개를 시트에 또각또각 입력하다 보면 "이거 코드가 대신 해주면 안 되나" 싶은 순간이 오거든요.
지난 글에서 openpyxl로 엑셀에 서식 입히고 차트까지 그려서 자동 보고서를 만들었잖아요. 그것도 좋긴 한데, openpyxl엔 한 가지 결정적인 한계가 있어요. 그건 내 컴퓨터 안의 엑셀 파일만 다룬다는 거예요. 결과를 팀에 보여주려면 파일을 다시 첨부하고, 메일 보내고, 누군가는 "최종_진짜최종.xlsx"를 만들고... 익숙하시죠.
구글 시트는 달라요. 코드가 값을 넣는 순간, 팀원 전원이 브라우저에서 바로 봐요. 파일을 주고받을 필요가 아예 없는 거죠.
파이썬으로 이 구글 시트를 직접 읽고 쓰는 방법을 정리해볼게요. 솔직히 코드 자체는 쉬워요. 진짜 어려운 건 처음 한 번 하는 인증 설정이거든요. 그래서 이 부분을 제일 천천히, 제일 친절하게 다뤄볼게요.
gspread 설치
먼저 라이브러리부터 깔아요.
pip install gspread # 구글 시트를 파이썬에서 다루게 해주는 라이브러리
예전 자료를 보면 oauth2client 같은 걸 같이 깔라고 나오는데요. 요즘 gspread는 인증 기능이 안에 들어있어서 이거 하나면 충분해요. 옛날 글 따라 하다가 괜히 헷갈리지 마세요.
gspread 인증 설정 5단계 (제일 중요한 부분)
여기서 90%가 막혀요. 그래서 천천히 갈게요.
설명하기 전에 비유 하나 깔고 갈게요. 우리가 지금 하려는 건 내 코드가 쓸 "로봇 직원"을 한 명 채용하는 일이에요. 사람인 내가 아니라, 코드가 대신 시트에 출입할 직원이 따로 필요하거든요. 이 비유 기억해두세요. 뒤에서 계속 나와요.
- 구글 클라우드 콘솔 접속 —
console.cloud.google.com에 들어가서 새 프로젝트를 하나 만들어요. 이름은 아무거나, 예를 들어my-sheet-bot같은 걸로요. - API 두 개 켜기 — "API 및 서비스 → 라이브러리"로 가서 아래 두 개를 검색하고 각각 "사용 설정"을 눌러요.
- Google Sheets API
- Google Drive API (시트를 이름으로 열 때 필요해요)
- 서비스 계정 만들기 — "사용자 인증 정보 → 사용자 인증 정보 만들기 → 서비스 계정"을 눌러요. 이게 아까 말한 그 로봇 직원을 채용하는 단계예요. 이름만 적고 만들면 돼요. 역할 설정은 건너뛰어도 괜찮아요.
- JSON 키 다운로드 — 방금 만든 서비스 계정을 클릭하고 "키" 탭 → "키 추가 → 새 키 만들기 → JSON"을 누르면
.json파일이 하나 내려와요. 이게 바로 로봇 직원의 사원증이에요. 이 사원증으로 코드가 구글에 로그인하는 거죠. 보통credentials.json으로 이름 바꿔서 코드 옆에 둬요. - 서비스 계정 이메일을 시트에 "공유"하기 — JSON 파일을 열어보면
"client_email": "xxxx@xxxx.iam.gserviceaccount.com"이런 줄이 있어요. 이 이메일을 복사해서, 자동화할 구글 시트의 우측 상단 "공유"에 편집자로 추가해요.
코드도 맞는데 왜 안 되지? — 403 함정
방금 5번, 그냥 슥 지나치셨죠. 거기서 잠깐 멈춰주세요.
서비스 계정 이메일을 시트에 공유하는 걸 빼먹으면, 코드가 아무리 완벽해도 무조건 403 에러가 나요.
이게 진짜 무서운 게, "코드도 맞고 인증도 됐는데 대체 왜 안 돼?" 하면서 몇 시간을 날리는 분들의 99%가 바로 이 공유를 안 한 거예요. 저도 처음에 한참 헤맸거든요.
아까 비유로 다시 볼게요. 로봇 직원이 사원증(JSON 키)은 있어요. 그래서 회사 건물 로그인까지는 돼요. 그런데 우리가 자동화하려는 그 시트는 특정 회의실이거든요. 사원증이 있어도 그 회의실 출입증, 즉 시트 공유 권한이 없으면 문 앞에서 막혀요.
그러니까 순서를 외워두세요. 채용(서비스 계정) → 사원증(JSON 키) → 회의실 초대(시트 공유). 마지막 초대를 빼먹으면 다 소용없어요.
아, 그리고 이 JSON 키 파일은 비밀번호급 비밀이에요. 깃허브에 올리거나 카톡으로 보내는 거 절대 금지예요. 유출되면 남이 그 로봇 직원 행세를 하면서 내 시트를 휘저을 수 있거든요.
파이썬으로 구글 시트 열고 읽고 쓰기
이제 설정이 끝났으니 코드는 정말 간단해요.
import gspread
gc = gspread.service_account(filename="credentials.json") # 사원증으로 로그인
sh = gc.open("9월 매출 현황") # 시트를 이름으로 열기
ws = sh.sheet1 # 첫 번째 탭 선택
print(ws.title) # 잘 열렸는지 탭 이름 출력
# 실행 결과:
# 시트1
여기서 gc.open("이름")은 시트 제목을 넣는 거예요. URL을 통째로 넣는 분들이 있는데 그건 안 돼요. URL로 열고 싶으면 gc.open_by_url(...)을 쓰면 돼요.
셀 하나 읽고 쓰는 것도 볼게요.
print(ws.acell("A1").value) # A1 칸 값 읽기
ws.update_acell("A1", "날짜") # A1 칸에 "날짜" 쓰기
ws.update_acell("B1", "매출") # B1 칸에 "매출" 쓰기
엑셀 주소 그대로 "A1", "B1" 쓰면 되니까 직관적이잖아요.
행 추가와 전체 데이터 가져오기
자동 기록에서 제일 많이 쓰는 건 행 추가예요. 맨 아래 빈 줄에 한 줄을 통째로 붙여줘요.
ws.append_row(["2025-09-25", "강남점", 150000]) # 맨 아래에 한 줄 추가
ws.append_row(["2025-09-25", "홍대점", 98000]) # 또 한 줄 추가
거꾸로, 시트에 있는 데이터를 파이썬으로 읽어올 수도 있어요.
records = ws.get_all_records() # 첫 행을 헤더로 보고 딕셔너리 리스트로 변환
for row in records:
print(row["지점"], row["매출"]) # 헤더 이름으로 값 꺼내기
# 실행 결과:
# 강남점 150000
# 홍대점 98000
get_all_records()는 첫 번째 행을 컬럼 이름(헤더)으로 인식해요. 그래서 첫 행이 그냥 데이터면 그게 헤더로 잡혀버리니까, 시트 맨 위에는 "날짜 / 지점 / 매출" 같은 제목 줄을 꼭 둬야 해요.
범위를 한 번에 업데이트하기 (429 에러 예방)
조심할 게 하나 있어요. 반복문 안에서 셀을 하나씩 수백 번 쓰면, 구글이 "호출이 너무 잦다"면서 429 에러를 뱉어요. 분당 호출 횟수에 제한이 있거든요.
그래서 데이터가 많을 땐 한 칸씩 말고, 범위를 한 번에 모아서 쓰는 게 좋아요.
data = [
["날짜", "지점", "매출"], # 헤더
["09-25", "강남", 150000],
["09-25", "홍대", 98000],
]
ws.update("A1", data) # A1부터 한 번에 채움 (호출 단 1번)
append_row를 100번 부르면 호출이 100번이지만, update로 모으면 1번이에요. 차이가 크죠.
구글 스프레드시트 자동화 실전: 일일 매출 기록
배운 걸 합쳐서, 매일 지점별 매출을 시트에 자동으로 쌓는 예제예요.
import gspread
from datetime import date
gc = gspread.service_account(filename="credentials.json")
ws = gc.open("일일 매출 기록").sheet1
today = date.today().isoformat() # 오늘 날짜 (예: 2025-09-25)
sales = [("강남점", 150000), ("홍대점", 98000), ("부산점", 120000)]
for branch, amount in sales: # 지점별로 한 줄씩
ws.append_row([today, branch, amount])
print("오늘 매출 기록 완료!")
# 실행 결과:
# 오늘 매출 기록 완료!
이걸 매일 아침 한 번 돌리기만 하면, 손으로 입력하던 그 야근이 사라지는 거예요.
자주 만나는 에러
- 403 (The caller does not have permission): 십중팔구 서비스 계정 이메일을 시트에 공유 안 한 거예요. JSON의
client_email을 시트 공유에 편집자로 넣으면 해결돼요. (1순위 범인이에요) - SpreadsheetNotFound: 시트 이름 오타거나, 역시 공유를 안 해서 못 찾는 경우예요.
- 429 (Quota exceeded): 호출이 너무 잦은 거예요.
update로 모아쓰기 하세요. - FileNotFoundError:
credentials.json경로가 틀린 거예요. 코드와 같은 폴더에 있는지 확인하세요. - API not enabled: 클라우드 콘솔에서 Sheets나 Drive 중 하나를 안 켰을 때예요.
직접 해보기
- 구글 시트를 하나 새로 만들고, 서비스 계정 이메일을 공유에 추가한 뒤,
append_row로 "오늘 할 일" 3개를 코드로 입력해보세요. - (심화) 방금 넣은 데이터를
get_all_records()로 다시 읽어와서 화면에 출력해보세요.
힌트: 1번이 403이 나면 거의 100% 공유를 빠뜨린 거예요. 시트 우측 상단 "공유"부터 다시 확인하세요.
여기까지 하면 로컬 엑셀(openpyxl)과 구글 시트(gspread), 두 가지 도구가 손에 들어온 셈이에요. 다음 글에서는 이 둘을 합쳐서 제대로 된 걸 하나 만들어볼 거예요. 흩어진 데이터를 모아 월별 매출 보고서를 한 방에 정리하는 미니 프로젝트로, 지금까지 배운 걸 전부 써먹어볼게요.
제 글이 도움이 되셨다면 댓글 & 공감 부탁드려요 😀
'Application > Python' 카테고리의 다른 글
| [Python] 10. 파이썬으로 PDF 합치고 나누기 (PyPDF2) (0) | 2026.07.02 |
|---|---|
| [Python] 09. 파이썬 미니 프로젝트: 월별 매출 정리 자동화 (1) | 2026.07.01 |
| [Python] 07. 파이썬으로 엑셀 자동 보고서 만들기 (서식과 차트) (0) | 2026.06.17 |
| [Python] 06. 파이썬으로 여러 엑셀 파일 하나로 합치기 (0) | 2026.06.16 |
| [Python] 05. 파이썬 엑셀 자동화, openpyxl로 시작하기 (0) | 2026.06.15 |