한줄 요약
“이제 진짜로 자동으로 돌아가는 시스템을 만든다”
“부분적으로 돌아가는 자동화는 반쪽짜리다.”
👉 이 글에서는 크롤링 → 본문추출 → 요약 → 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] 완전 자동화(크론/스케줄링) + 장애 알림 + 백업 시스템 구축