[실전#2] 전체 자동화 파이프라인 (크롤링 → 요약 → LLM → 워드프레스) 완성 코드

한줄 요약

“이제 진짜로 자동으로 돌아가는 시스템을 만든다”

“부분적으로 돌아가는 자동화는 반쪽짜리다.”
👉 이 글에서는 크롤링 → 본문추출 → 요약 → LLM 리포트 → 워드프레스 자동 게시까지
하나의 완성된 파이프라인으로 묶는 전체 코드를 정리한다.

1. 목표

  • BeautifulSoup + requests 기반 크롤러 완성
  • Readability 기반 본문 추출 자동화
  • Sumy + Yake 기반 요약 · 키워드 추출 자동화
  • OpenAI LLM 기반 최종 리포트 생성
  • WordPress REST API 기반 자동 포스팅
  • 전체 흐름을 orchestration 해주는 orchestrator.py 통합 완성본 제공

2. 전체 구조

project/
├── core/
│   ├── crawler.py
│   ├── extractor.py
│   ├── summarizer.py
│   ├── llm_client.py
│   ├── wp_client.py
│   └── pipelines.py
└── orchestrator.py

이제 아래 코드들을 그대로 복사해서 파일로 만들면, 하나의 완성된 자동화 파이프라인이 된다.

💻 1) core/crawler.py — URL 수집 + HTML 가져오기

# core/crawler.py
import requests

HEADERS = {
    "User-Agent": "Mozilla/5.0"
}

def fetch_html(url: str) -> str:
    r = requests.get(url, headers=HEADERS, timeout=10)
    r.raise_for_status()
    return r.text

def fetch_urls(config):
    """단일 URL 또는 URL 리스트를 받아 HTML을 모두 가져옴"""
    urls = config.get("urls", [])
    results = {}
    for url in urls:
        results[url] = fetch_html(url)
    return results

💻 2) core/extractor.py — 본문 자동 추출(Readability)

# core/extractor.py
from readability import Document
from bs4 import BeautifulSoup

def extract_content(html: str) -> str:
    """광고/사이드바 제거하고 핵심 본문만 반환"""
    doc = Document(html)
    content = doc.summary()
    soup = BeautifulSoup(content, "html.parser")
    text = soup.get_text(separator="\n", strip=True)
    return text

💻 3) core/summarizer.py — 요약 + 키워드(Yake)

# core/summarizer.py
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.lex_rank import LexRankSummarizer
import yake

def summarize(text: str, sentences=3):
    parser = PlaintextParser.from_string(text, Tokenizer("korean"))
    summarizer = LexRankSummarizer()
    result = summarizer(parser.document, sentences)
    return "\n".join([str(r) for r in result])

def extract_keywords(text: str, topk=5):
    kw = yake.KeywordExtractor(lan="ko", top=topk)
    return [k[0] for k in kw.extract_keywords(text)]

def summarize_all(url_text_map):
    """
    url_text_map: {url: cleaned_text}
    """
    results = []
    for url, text in url_text_map.items():
        summary = summarize(text)
        keywords = extract_keywords(text)
        results.append({
            "url": url,
            "summary": summary,
            "keywords": keywords
        })
    return results

💻 4) core/llm_client.py — LLM으로 최종 리포트 생성

# core/llm_client.py
from openai import OpenAI

client = OpenAI()

def make_final_report(items, cfg):
    model = cfg.get("model", "o4-mini")

    # 요약/키워드들을 하나의 입력 텍스트로 합치기
    input_text = ""
    for it in items:
        input_text += (
            f"URL: {it['url']}\n"
            f"요약:\n{it['summary']}\n"
            f"키워드: {', '.join(it['keywords'])}\n\n"
        )

    prompt = f"""
당신은 뉴스 편집자입니다.
다음 기사들의 요약과 키워드를 참고해서
'오늘의 뉴스 브리핑' 형식의 한국어 보고서를 작성해 주세요.

요구사항:
- 핵심 이슈 3~5개로 정리
- 각 이슈마다 2~3문장으로 설명
- 마지막에 '오늘의 핵심 키워드' 섹션 추가

===== 기사 요약 시작 =====
{input_text}
===== 기사 요약 끝 =====
"""

    resp = client.responses.create(
        model=model,
        input=prompt,
    )
    return resp.output_text

💻 5) core/wp_client.py — 워드프레스 자동 포스팅

# core/wp_client.py
import requests
import base64

def post_to_wordpress(content: str, cfg):
    endpoint = cfg["endpoint"]          # 예: https://yourblog.com/wp-json/wp/v2/posts
    username = cfg["username"]
    password = cfg["password"]

    token = base64.b64encode(f"{username}:{password}".encode())
    headers = {
        "Authorization": f"Basic {token.decode('utf-8')}"
    }

    data = {
        "title": cfg.get("title", "자동 생성 뉴스 브리핑"),
        "content": content,
        "status": "publish"
    }

    r = requests.post(endpoint, headers=headers, json=data, timeout=15)
    r.raise_for_status()
    return r.json()

💻 6) core/pipelines.py — 전체 단계 연결

# core/pipelines.py
from core.crawler import fetch_urls
from core.extractor import extract_content
from core.summarizer import summarize_all
from core.llm_client import make_final_report
from core.wp_client import post_to_wordpress

def run_pipeline(cfg):
    # 1) URL → HTML
    html_map = fetch_urls(cfg["crawler"])

    # 2) HTML → 본문 텍스트
    clean_map = {u: extract_content(h) for u, h in html_map.items()}

    # 3) 요약 + 키워드
    summary_pack = summarize_all(clean_map)

    # 4) LLM 보고서 생성
    final_report = make_final_report(summary_pack, cfg["llm"])

    # 5) 워드프레스 포스팅
    result = post_to_wordpress(final_report, cfg["wordpress"])
    return result

💻 7) orchestrator.py — 전체 자동화 실행 스크립트

# orchestrator.py
import yaml
from core.pipelines import run_pipeline

def load_config(path="config/config.prod.yml"):
    with open(path, "r", encoding="utf-8") as f:
        return yaml.safe_load(f)

def main():
    cfg = load_config()
    result = run_pipeline(cfg)
    print("📬 게시 성공:", result.get("link", "(링크 정보를 찾을 수 없음)"))

if __name__ == "__main__":
    main()

3. config/config.prod.yml 예시

crawler:
  urls:
    - "https://news.naver.com/..."
    - "https://www.korea.kr/..."

llm:
  model: "o4-mini"

wordpress:
  endpoint: "https://yourblog.com/wp-json/wp/v2/posts"
  username: "admin"
  password: "비밀번호를_여기에"
  title: "자동 뉴스 요약 리포트"

4. 이 강좌에서 얻을 수 있는 것

  • 크롤러부터 워드프레스 업로드까지 실제로 실행 가능한 풀 파이프라인 코드
  • 파일 구조 + 설정 분리 + 모듈화가 된 서비스 수준 구조
  • python orchestrator.py 한 번 실행으로 “하루치 뉴스 요약 + 블로그 자동 게시” 구현

5. 요약 한 줄

“파일들이 서로 협력하도록 만들면 그것이 ‘파이プ라인’이고,
그 파이프라인이 스케줄에 맞춰 자동으로 실행되면 그것이 ‘서비스’다.”

이전 강좌 👉 [실전#1] 완성형 프로젝트 폴더 구조 & CI/CD 자동 배포 구축
다음 강좌 👉 [실전#3] 완전 자동화(크론/스케줄링) + 장애 알림 + 백업 시스템 구축

댓글 남기기

광고 차단 알림

광고 클릭 제한을 초과하여 광고가 차단되었습니다.

단시간에 반복적인 광고 클릭은 시스템에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.