20. VS Code에서 Python으로 블로그 글 자동 생성하기

 저도 처음엔 직장을 다니며 블로그 1일 1포스팅을 하겠다는 욕심에 퇴근 후 매일 2~3시간씩 모니터 씨름을 했습니다. 피곤한 날엔 글감이 안 떠올라 한 줄도 못 쓰고 밤을 새우기 일쑤였죠. 안 되겠다 싶어 파이썬과 ChatGPT API를 연동해 핵심 키워드만 넣으면 3초 만에 뼈대와 초안을 뽑아주는 프로그램을 만들었습니다. 매일 2시간씩 걸리던 글쓰기 지옥에서 벗어나, 지금은 10분 만에 나온 초안에 제 생각과 사진만 슥 얹어서 30분 만에 고품질의 포스팅을 완성하고 있습니다.

이 글에서는 제목 하나를 입력하면 SEO 최적화된 마크다운 블로그 글 초안이 자동으로 생성되어 파일로 저장되는 시스템을 — Gemini API와 Python을 활용해 VS Code에서 처음부터 완성까지 구축해 드리겠습니다.


블로그 글 자동 생성이 필요한 이유 — 편집자 vs 작가의 역할 분리

글을 잘 쓰는 것과 글을 빠르게 생산하는 것은 다른 능력입니다. 블로그를 꾸준히 운영하려면 두 가지가 모두 필요한데, 대부분의 사람은 아이디어는 있지만 매번 초안을 만드는 과정에서 시간을 소진합니다.

AI를 활용한 글 자동 생성은 이 역할을 분리합니다. AI가 작가(초안 작성)를 맡고, 사람이 편집자(검수·보완·경험담 추가)를 맡는 구조입니다. 빈 페이지를 채우는 심리적 부담이 사라지고, 사람은 오직 품질을 높이는 작업에만 집중할 수 있습니다.

이 시스템으로 할 수 있는 것

  • 제목 입력 → 마크다운 초안 자동 생성 → 파일 저장 전 과정 자동화
  • 여러 제목을 한 번에 배치 처리 — 10개 제목을 넣으면 10개 파일이 한 번에 생성
  • 프롬프트 커스터마이징 — 말투, 구조, 길이, 키워드를 조건으로 설정
  • 생성 이력 관리 — 언제 어떤 제목으로 글을 생성했는지 CSV로 자동 기록

사전 준비 — Gemini API 키 발급하기

Google의 Gemini API는 무료 티어를 제공합니다. 분당 15회, 하루 1,500회 요청이 무료로 제공되어 블로그 초안 생성 용도로는 충분합니다.

API 키 발급 순서

  1. 브라우저에서 Google AI Studio 에 접속합니다 (aistudio.google.com).
  2. Google 계정으로 로그인합니다.
  3. 왼쪽 메뉴에서 "Get API Key" 를 클릭합니다.
  4. "Create API Key" 버튼을 눌러 키를 생성합니다.
  5. 생성된 키를 복사해 안전한 곳에 저장합니다.



⚠️ API 키는 절대 코드에 직접 넣지 마십시오. 깃허브에 올라가는 순간 자동 스캐너에 의해 노출될 수 있습니다. 반드시 .env 파일로 관리하십시오.


환경 설정 — 라이브러리 설치 및 키 관리

pip install google-generativeai python-dotenv

프로젝트 폴더에 .env 파일을 만들고 아래 내용을 저장합니다.

GEMINI_API_KEY=your_api_key_here

.gitignore 파일에 .env 를 추가합니다.

# .gitignore
.env
__pycache__/
*.pyc
output/

STEP 1 — Gemini API 연결 및 기본 호출 테스트

import google.generativeai as genai
from dotenv import load_dotenv
import os

load_dotenv()
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))

# 모델 설정
model = genai.GenerativeModel("gemini-2.5-flash")

# 기본 호출 테스트
response = model.generate_content("안녕하세요, 테스트입니다.")
print(response.text)

gemini-2.5-flash 는 속도와 비용 효율이 뛰어난 모델로, 블로그 초안 생성처럼 대량 텍스트 작업에 적합합니다. 품질을 더 높이고 싶다면 gemini-2.5-pro 를 사용할 수 있습니다.




STEP 2 — SEO 최적화 블로그 글 생성 프롬프트 설계

블로그 글 자동 생성의 품질은 프롬프트 설계가 전부라고 해도 과언이 아닙니다. 같은 API를 써도 프롬프트가 구체적일수록 결과물의 완성도가 달라집니다.

def build_prompt(title: str, keywords: list = None) -> str:
    keyword_str = ", ".join(keywords) if keywords else "없음"

    prompt = f"""
너는 구글 SEO 전문가이자 전문 테크 블로거야.
아래 조건에 맞는 완성도 높은 블로그 글을 마크다운 형식으로 작성해.

[제목]
{title}

[작성 조건]
- 분량: 공백 제외 최소 1,500자 이상
- 구조: 서론(## 들어가며) → 본론(## 소제목 3~5개) → 결론(## 마무리) 계층 구조
- 각 소제목에는 핵심 키워드가 자연스럽게 포함될 것
- 말투: "~습니다", "~입니다" 체로 통일
- 초보자도 이해할 수 있는 일상적 비유를 최소 2개 이상 포함
- 핵심 요약은 반드시 번호 목록 또는 불릿 포인트로 작성
- 코드 예제가 있으면 반드시 코드 블록(```)으로 감쌀 것
- SEO를 위해 제목의 핵심 키워드를 본문 첫 100자 안에 자연스럽게 포함
- 서론 첫 단락은 [직접 작성 필요] 태그로 비워둘 것

[포함할 키워드]
{keyword_str}

[출력 형식]
마크다운 텍스트만 출력하고, 앞뒤에 어떠한 설명이나 ```markdown 태그도 붙이지 말 것.
""".strip()

    return prompt

STEP 3 — 글 생성 및 파일 저장 함수

import re
from datetime import datetime
from pathlib import Path

OUTPUT_DIR = Path("output")
OUTPUT_DIR.mkdir(exist_ok=True)

def generate_blog_post(title: str, keywords: list = None) -> str:
    prompt = build_prompt(title, keywords)

    try:
        response = model.generate_content(
            prompt,
            generation_config=genai.types.GenerationConfig(
                temperature=0.7,      # 창의성 수준 (0~1, 높을수록 다양한 표현)
                max_output_tokens=4096,
            )
        )
        return response.text

    except Exception as e:
        print(f"생성 실패: {e}")
        return ""

def save_post(title: str, content: str) -> Path:
    # 파일명 생성 — 제목에서 특수문자 제거
    safe_name = re.sub(r"[^\w가-힣\s]", "", title).strip().replace(" ", "_")
    timestamp = datetime.now().strftime("%Y%m%d_%H%M")
    filename = OUTPUT_DIR / f"{timestamp}_{safe_name}.md"

    with open(filename, "w", encoding="utf-8") as f:
        f.write(f"# {title}\n\n")
        f.write(content)

    print(f"저장 완료: {filename}")
    return filename

def create_post(title: str, keywords: list = None) -> Path:
    print(f"생성 중: {title}")
    content = generate_blog_post(title, keywords)

    if content:
        return save_post(title, content)
    return None

STEP 4 — 배치 처리 + 생성 이력 CSV 저장

여러 글을 한 번에 생성하고, 결과를 CSV로 기록하는 기능입니다.

import csv
import time

HISTORY_FILE = "generation_history.csv"

def save_history(records: list) -> None:
    file_exists = Path(HISTORY_FILE).exists()

    with open(HISTORY_FILE, "a", encoding="utf-8-sig", newline="") as f:
        writer = csv.writer(f)
        if not file_exists:
            writer.writerow(["생성일시", "제목", "키워드", "파일경로", "성공여부"])
        writer.writerows(records)

def batch_generate(topics: list, delay: int = 5) -> None:
    """
    topics: [{"title": "제목", "keywords": ["키워드1", "키워드2"]}, ...]
    delay: 각 요청 사이 대기 시간(초) — API 제한 방지
    """
    records = []

    for i, topic in enumerate(topics, 1):
        title = topic["title"]
        keywords = topic.get("keywords", [])

        print(f"\n[{i}/{len(topics)}] 처리 중: {title}")
        filepath = create_post(title, keywords)

        record = [
            datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            title,
            ", ".join(keywords),
            str(filepath) if filepath else "실패",
            "성공" if filepath else "실패",
        ]
        records.append(record)

        if i < len(topics):
            print(f"  {delay}초 대기 중...")
            time.sleep(delay)

    save_history(records)
    print(f"\n✅ 배치 완료. 총 {len(topics)}개 처리.")
    print(f"📄 이력 저장: {HISTORY_FILE}")

실제 실행 예시

# main.py

topics = [
    {
        "title": "VS Code에서 Python으로 엑셀 자동화하기",
        "keywords": ["파이썬 엑셀", "openpyxl", "업무 자동화"]
    },
    {
        "title": "Python 가상환경 사용법 완벽 정리",
        "keywords": ["venv", "가상환경", "pip"]
    },
    {
        "title": "Python으로 텔레그램 봇 만들기",
        "keywords": ["텔레그램 봇", "python-telegram-bot", "알림"]
    },
]

batch_generate(topics, delay=5)

실행하면 output/ 폴더에 글 파일들이 생성되고, generation_history.csv 에 이력이 기록됩니다.






STEP 5 — 품질 개선 팁 3가지

① system_instruction으로 일관된 페르소나 유지하기

model = genai.GenerativeModel(
    model_name="gemini-1.5-flash",
    system_instruction=(
        "너는 10년 경력의 한국인 테크 블로거이자 Python 개발자야. "
        "항상 '~습니다', '~입니다' 체를 사용하고, "
        "초보자도 이해할 수 있는 비유를 즐겨 사용해. "
        "코드 예제는 반드시 실행 가능한 완성 코드로 작성해."
    )
)

② 생성된 글의 길이 자동 검증

def validate_content(content: str, min_chars: int = 1500) -> bool:
    # 공백 제외 글자 수 계산
    char_count = len(content.replace(" ", "").replace("\n", ""))

    if char_count < min_chars:
        print(f"⚠️ 분량 부족: {char_count}자 (최소 {min_chars}자 필요)")
        return False

    print(f"✅ 분량 확인: {char_count}자")
    return True

③ 재시도 로직으로 안정성 높이기

def generate_with_retry(title: str, keywords: list = None, max_retry: int = 3) -> str:
    for attempt in range(1, max_retry + 1):
        content = generate_blog_post(title, keywords)

        if content and validate_content(content):
            return content

        print(f"  재시도 {attempt}/{max_retry}...")
        time.sleep(3)

    print(f"❌ 최대 재시도 초과: {title}")
    return ""

자주 발생하는 오류와 해결법

오류 1 — ResourceExhausted: 429 오류 발생

원인: 무료 티어 분당 요청 한도 초과
해결: delay 값을 10초 이상으로 늘리거나, 유료 티어로 업그레이드

오류 2 — 생성된 글에 ```markdown 태그가 붙어 나오는 경우

원인: 모델이 마크다운 코드 블록으로 응답을 감싸는 경우
해결: 후처리로 제거

content = response.text
content = re.sub(r"^```markdown\n?", "", content)
content = re.sub(r"\n?```$", "", content)
content = content.strip()

오류 3 — 한글 파일명이 깨지는 경우

원인: 운영체제별 파일명 인코딩 차이
해결: 파일명에서 한글을 영문으로 변환하거나, 날짜+번호 방식으로 저장

# 한글 제목을 날짜+인덱스로 대체
filename = OUTPUT_DIR / f"{timestamp}_{i:03d}.md"
# 파일 내부 첫 줄에 실제 제목 기록

마무리 — 핵심 요약

✅ Python 블로그 글 자동 생성 시스템 체크리스트

  1. Gemini API 키 발급 — Google AI Studio에서 무료 발급, .env 파일로 관리
  2. 프롬프트 설계가 품질을 결정 — 조건이 구체적일수록 완성도가 높아집니다
  3. 단일 생성은 create_post(), 대량 생성은 batch_generate() 사용
  4. API 제한 방지를 위해 요청 사이에 반드시 time.sleep() 추가
  5. 생성 이력을 CSV로 저장 — 어떤 글을 언제 만들었는지 관리 가능
  6. 자동 생성 글은 반드시 서론과 스크린샷을 직접 보완 후 발행

다음으로 알아두면 좋은 것

이 시스템에 이전 시리즈의 Selenium 또는 requests를 결합하면, 생성된 글을 티스토리나 워드프레스에 자동으로 업로드하는 것도 가능합니다. 단, 블로그 플랫폼의 이용 약관을 반드시 확인하시고, 자동 포스팅 전에 글 품질 검수 단계를 반드시 거치시길 권장합니다. 완전 자동화보다 반자동화(초안 자동 생성 + 사람이 검수 후 발행) 가 장기적으로 더 안전하고 지속 가능한 전략입니다.




댓글

이 블로그의 인기 게시물

1.Python 설치부터 실행까지 10분 만에 끝내기 — 초보자도 바로 따라 하는 완벽 가이드

30.Python pyautogui로 마우스와 키보드 자동화하기: VSCode 실전 가이드

29.Python subprocess로 외부 명령어 실행하기: VSCode 실전 활용법