블로그를 운영하다 보면 정성스럽게 달리는 댓글이 반가우면서도, 하나하나 답글을 달기에는 시간이 부족할 때가 많습니다. 오늘은 내 컴퓨터(로컬 PC)에 AI 서버를 구축하고, 티스토리 블로그 댓글에 자동으로 답장을 다는 비용 제로 자동화 시스템 만드는 방법을 상세히 소개해 드립니다.
이 방법은 유료 API 비용 걱정 없이 Llama 3.1 같은 최신 오픈소스 LLM 모델을 활용하며, 윈도우 환경에서도 WSL2를 통해 강력한 리눅스 서버 환경을 그대로 사용할 수 있는 것이 장점입니다. 초보자분들도 차근차근 따라 하실 수 있도록 코드 적용법부터 주의사항까지 꼼꼼하게 정리했습니다.
목차
1. 댓글 자동화 시스템 작동 원리: AI는 어떻게 답글을 다나요?
이 시스템은 크게 세 가지 단계로 유기적으로 움직이며 24시간 블로그를 관리합니다.
- 댓글 모니터링 (서버/비서): 설정된 시간(예: 3시간)마다 내 티스토리 관리자 페이지에 접속하여 답글이 달리지 않은 새로운 댓글이 있는지 스캔합니다.
- AI 문장 생성 (내 집 PC/두뇌): 새로운 댓글을 발견하면 내 컴퓨터에서 실행 중인 Ollama AI(Llama 3.1) 무료 AI에게 댓글 내용을 전달하고, 분위기에 맞는 친절한 답글 작성을 요청합니다.
- 자동 등록 프로세스: AI가 생성한 답변을 셀레니움(Selenium) 브라우저가 자동으로 입력하고 ‘등록’ 버튼을 눌러 작업을 완료합니다.
2. 댓글 자동화 환경 구축 및 준비물 (사전 설정)
외부 서버(오라클 등)나 내 컴퓨터의 WSL2 환경에서 코드를 실행하기 위해 다음 도구들이 필요합니다.
- Python 설치: 스크립트 실행을 위한 기본 환경입니다.
- 크롬 드라이버 및 셀레니움: 웹브라우저를 자동으로 제어하여 티스토리 관리자 페이지를 조작합니다.
- Ollama: 내 PC에서 대규모 언어 모델(LLM)을 돌려주는 엔진입니다.
- ngrok: (외부 서버 이용 시 필요) 로컬 PC의 AI 서버 주소를 외부 서버에서 접속할 수 있도록 안전한 터널을 열어줍니다.
3. WSL2 및 Ollama AI 서버 구축 (내 PC 설정)
내 컴퓨터를 강력한 AI 서버로 만들어 속도와 보안을 동시에 잡는 방법입니다.
Step 1: WSL2(Ubuntu) 리눅스 환경 설치
- 윈도우 시작 메뉴에서 PowerShell을 찾고 ‘관리자 권한으로 실행’합니다.
- 아래 명령어를 입력하고 설치가 완료되면 컴퓨터를 재부팅합니다.
wsl --install재부팅 후 나타나는 Ubuntu 창에서 사용자 ID와 비밀번호를 설정하면 리눅스 준비가 끝납니다.
Step 2: Windows용 Ollama 설치 및 환경 변수 설정

- Ollama 공식 홈페이지에서 설치 파일을 내려받아 설치합니다.
- 환경 변수 설정: WSL2나 외부 서버에서 내 PC의 AI를 호출하려면 문을 열어줘야 합니다.
- ‘시스템 환경 변수 편집’ 검색 -> ‘환경 변수’ 클릭.
- 사용자 변수 ‘새로 만들기’ -> 변수 이름: OLLAMA_HOST / 변수 값: 0.0.0.0 입력.
- 트레이 아이콘에서 Ollama를 종료 후 재시작합니다.
Step 3: AI 모델(Llama 3.1) 다운로드 및 WSL 라이브러리 설치
터미널에서 AI 모델을 받고, WSL2 Ubuntu 환경에 필요한 패키지들을 깔아줍니다.
# AI 모델 받기 (Windows CMD에서 실행)
ollama run llama3.1
WSL2(Ubuntu) 패키지 및 라이브러리 설치
sudo apt update && sudo apt upgrade -y
sudo apt install python3 python3-pip -y
pip3 install requests selenium webdriver-manager
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb -y4. 티스토리 AI 자동 답글 파이썬 스크립트
아래 코드는 예시 값으로 작성되었습니다. # — 설정 구간 — 부분을 본인의 티스토리 정보와 주소로 반드시 수정해 주세요.
import time
import requests
import pickle
import os
import urllib3
import re
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
--- 설정 구간 (이 부분을 본인 정보로 수정하세요) ---
USER_ID = "[email protected]" # 티스토리/카카오 계정 이메일
USER_PW = "your_password" # 계정 비밀번호
WSL2 내부 이용시 http://localhost:11434 , 외부 서버 이용시 ngrok 주소 입력
NGROK_URL = "https://your-unique-id.ngrok-free.dev"
BLOG_LIST = [
"https://blog1.tistory.com/manage/comments",
"https://blog2.tistory.com/manage/comments"
]
COOKIE_FILE = "/home/ubuntu/tistory_cookies.pkl"
HISTORY_FILE = "/home/ubuntu/replied_ids.txt"
NGROK_AUTH = ("your_id", "your_password") # 보안 설정 시 사용
-----------------------------------------------
def load_history():
if os.path.exists(HISTORY_FILE):
with open(HISTORY_FILE, "r") as f:
return set(line.strip() for line in f if line.strip())
return set()
def save_history(c_id):
with open(HISTORY_FILE, "a") as f:
f.write(f"{c_id}\n")
def save_cookies(driver):
try:
with open(COOKIE_FILE, "wb") as f:
pickle.dump(driver.get_cookies(), f)
print("성공: 새로운 쿠키 저장됨")
except Exception as e:
print(f"쿠키 저장 실패: {e}")
def ask_home_ai(comment_text):
print(f"🤖 AI에게 문장 요청 중: {comment_text[:10]}...")
url = f"{NGROK_URL.rstrip('/')}/api/generate"
headers = {"ngrok-skip-browser-warning": "69420", "Content-Type": "application/json"}
payload = {
"model": "llama3.1:latest",
"prompt": f"너는 친절한 블로그 운영자야. 이 댓글에 정중하게 1문장으로 답글을 써줘: {comment_text}",
"stream": False,
}
session = requests.Session()
session.verify = False
try:
res = session.post(url, json=payload, headers=headers, auth=NGROK_AUTH, timeout=240)
if res.status_code == 200:
return res.json()["response"].strip()
else:
print(f"❌ 서버 응답 에러: {res.status_code}")
except Exception as e:
print(f"❌ AI 서버 통신 에러: {e}")
return None
셀레니움 브라우저 설정 (Headless 모드)
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--window-size=1920,1080")
chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
try:
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=chrome_options)
wait = WebDriverWait(driver, 20)
print("🌐 티스토리 관리자 페이지 접속...")
driver.get(BLOG_LIST[0])
time.sleep(3)
if os.path.exists(COOKIE_FILE):
with open(COOKIE_FILE, "rb") as f:
for cookie in pickle.load(f):
try: driver.add_cookie(cookie)
except: continue
driver.refresh()
time.sleep(3)
if "manage/comments" not in driver.current_url:
print("🔑 로그인이 필요합니다.")
try:
kakao_btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.link_kakao_id, .link_kakao")))
driver.execute_script("arguments[0].click();", kakao_btn)
time.sleep(5)
driver.find_element(By.NAME, "loginId").send_keys(USER_ID)
driver.find_element(By.NAME, "password").send_keys(USER_PW)
driver.find_element(By.CSS_SELECTOR, "button.btn_g.highlight.submit").click()
except Exception as e:
print(f"로그인 오류: {e}")
raise e
print("!!! 인증 대기 중 (최대 2분) !!!")
auth_success = False
for i in range(120):
if "manage/comments" in driver.current_url:
print(f"로그인 성공!")
auth_success = True
save_cookies(driver)
break
time.sleep(1)
if not auth_success: exit()
today_str = datetime.now().strftime("%Y-%m-%d")
replied_history = load_history()
for admin_url in BLOG_LIST:
print(f"\n🚀 블로그 체크: {admin_url}")
driver.get(admin_url)
time.sleep(5)
items = driver.find_elements(By.CSS_SELECTOR, "ul.list_post li")
for item in items:
try:
c_id = item.find_element(By.CSS_SELECTOR, "input[type='checkbox']").get_attribute("id")
if c_id in replied_history: continue
date_text = item.find_element(By.CSS_SELECTOR, "span.txt_info.txt_info_type1:not(.txt)").text
if today_str not in date_text: continue
status = item.find_elements(By.CSS_SELECTOR, "span.info_status")
if status and "답글" in status[0].text:
save_history(c_id)
continue
comment_text = item.find_element(By.CSS_SELECTOR, "strong.tit_post a.link_cont").text.strip()
print(f"🔥 새 댓글 발견: {comment_text[:15]}")
ai_reply = ask_home_ai(comment_text)
if not ai_reply: continue
reply_btn = item.find_element(By.XPATH, ".//a[contains(text(), '답글')]")
driver.execute_script("arguments[0].click();", reply_btn)
time.sleep(3)
editor = driver.find_elements(By.CSS_SELECTOR, ".tf_blog[contenteditable='true']")[-1]
driver.execute_script("arguments[0].focus(); arguments[0].innerHTML = arguments[1];", editor, ai_reply)
editor.send_keys(Keys.SPACE)
time.sleep(1)
parent = editor.find_element(By.XPATH, "./ancestor::div[contains(@class, 'inner_blog_layer')]")
driver.execute_script("arguments[0].click();", parent.find_element(By.CSS_SELECTOR, "button.btn_default"))
print(f"✅ 등록 완료: {c_id}")
save_history(c_id)
time.sleep(5)
except: continue
except Exception as e:
print(f"❌ 에러 발생: {e}")
finally:
if 'driver' in locals(): driver.quit()
print("\n--- 전체 작업 종료 ---")5. 자동화 실행 및 스케줄링 설정
1) 스크립트 실행 테스트
WSL2 터미널에서 아래 명령어를 입력하여 파일(tistory_ai_reply.py)을 생성하고 코드를 붙여넣은 뒤 수동으로 먼저 실행해 봅니다.
nano tistory_ai_reply.py
(코드 붙여넣기 후 Ctrl+O, Enter, Ctrl+X)
python3 tistory_ai_reply.py2) 크론탭(Crontab) 자동화 설정
3시간마다 서버가 자동으로 돌도록 스케줄러에 등록합니다.
crontab -e
맨 아래 줄에 추가 (3시간 간격 실행)
0 */3 * * * /usr/bin/python3 /home/ubuntu/tistory_ai_reply.py >> /home/ubuntu/tistory_ai.log 2>&1⚠️ 필수 주의사항 및 보안 가이드
- 절전 모드 해제: 내 PC를 서버로 쓸 경우, 컴퓨터가 절전 모드에 빠지면 자동화가 멈춥니다. 윈도우 전원 설정에서 ‘절전 모드 안 함’으로 설정하세요.
- ngrok 주소 관리: ngrok 무료 버전은 실행할 때마다 주소가 바뀔 수 있습니다. 주소가 바뀌면 파이썬 코드의
NGROK_URL도 반드시 업데이트해야 합니다. - 비밀번호 보안: 계정 정보가 포함된 스크립트 파일은 외부(GitHub 등)에 절대 올리지 않도록 주의하세요.
이제 여러분의 블로그는 잠든 사이에도 AI 비서가 친절하게 독자들과 소통하게 될 것입니다.
팁: 본문의 NGROK_URL을 로컬에서만 사용하실 거라면 http://localhost:11434로 바로 설정하여 사용하시면 더 편리합니다.
