
이번엔 ChatGPT API로 블로그 자동화 한 번 해봤읍니다.
어떻게 했는지 한 번 알아볼까요?

이런식으로 인트로덕션을 작성하고 이름을 지정해줬읍니다. 모델은 gpt-3.5-turbo를 사용했읍니다.
근데 1500자 이상 못적더라고요
이러고 대충 스레드 만들고 메시지 만들고 스레드에 넣어서 답변 요청하고 파싱해서 뿌렸읍니다.
import time
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI()
def create_assistant():
my_assistant = client.beta.assistants.create(
instructions="""
너는 한국에서 팔로워가 가장 많은 파워 블로거야. 주로 한국에서 일어나는 이슈에 대해 블로그를 많이 작성해.
너는 어떤 이슈가 발생했는지 문장 한 문장만 주어지면 그에 대한 블로그를 1500자 이상 작성할 수 있어.
너가 작성하는 블로그의 작성 방식은 제목, 서론, 본론, 결론 순으로 작성해. 이런 식으로 글을 작성하지만
글에서 '# 본론'과 같이 임의로 표기하진 않고 글만 작성해. 하지만 제목만 'title[제목]' 이런 식으로 작성해.
""",
name="블로그 자동화 어시스턴트",
tools=[{"type": "code_interpreter"}],
model="gpt-3.5-turbo",
)
return my_assistant.id
def create_thread():
empty_thread = client.beta.threads.create()
return empty_thread.id
def request_question(assistant_id, thread_id, content: str):
client.beta.threads.messages.create(
thread_id,
role="user",
content=content,
)
run = client.beta.threads.runs.create(
thread_id=thread_id,
assistant_id=assistant_id,
)
run_id = run.id
while run.status != "completed":
print("답변을 생성중입니다...")
time.sleep(1)
run = client.beta.threads.runs.retrieve(
thread_id=thread_id,
run_id=run_id
)
messages = client.beta.threads.messages.list(
thread_id=thread_id
)
return messages.data[0].content[0].text.value
def separate_response(text):
title_index = text.find("[")
if title_index != -1:
title = text[title_index + 1:text.find("]", title_index)]
else:
print(text)
raise RuntimeError("잘못된 응답 형식입니다.")
intro_start = text.find("서론")
body_start = text.find("본론")
conclusion_start = text.find("결론")
if intro_start != -1 and body_start != -1 and conclusion_start != -1:
content = text[body_start:conclusion_start].strip()
else:
print(text)
raise RuntimeError("잘못된 응답 형식입니다.")
return title, content
이게 메인이라고 할 수 있읍니다.

셀레니움4 이후부턴 크롬드라이버가 내장으로 들어가서 따로 다운받지 않아도 사용할 수 있읍니다.
필요한 설정만 해주면 되는데 저는 티스토리 블로그를 자동으로 돌리려고 하기 때문에 봇인걸 숨기기 위해 우회 방법으로 유저 에이전트를 설정해주고 크롬을 디버깅모드를 사용해서 돌렸읍니다.
다음으론 대충 로그인하고 글 생성한거 가져와서 블로그로 작성하는 파이프라인을 구성해서 자동으로 돌아가도록 코드를 작성합니다.
import time
import pyperclip
from selenium import webdriver
from selenium.common import NoAlertPresentException
from selenium.webdriver import ActionChains, Keys
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from dotenv import load_dotenv
import random
import os
load_dotenv()
class Blog:
def __init__(self):
user_agents = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',
]
user_agent_index = random.choice(list(range(0, len(user_agents), 1)))
chrome_options = Options()
chrome_options.add_argument('headless')
chrome_options.add_argument('window-size=1920x1080')
chrome_options.add_argument('disable-gpu')
chrome_options.add_argument(user_agents[user_agent_index])
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
self.driver = webdriver.Chrome(options=chrome_options)
def main(self, title, content):
self.driver.implicitly_wait(3)
self.driver.get(
url='https://k-issue-briefing.tistory.com/manage/newpost/?type=post&returnURL=%2Fmanage%2Fposts%2F')
time.sleep(0.8)
self.driver.find_element(By.CSS_SELECTOR,
"#cMain > div > div > div > div > a.btn_login.link_kakao_id > span.txt_login").click()
time.sleep(1)
self.driver.find_element(By.CSS_SELECTOR, "#loginId--1").send_keys(os.getenv("KAKAO_EMAIL"))
self.driver.find_element(By.CSS_SELECTOR, "#password--2").send_keys(os.getenv("KAKAO_PASSWD"))
self.driver.find_element(By.CSS_SELECTOR,
"#mainContent > div > div > form > div.confirm_btn > button.btn_g.highlight.submit").click()
time.sleep(2)
try:
self.driver.switch_to.alert.dismiss()
except NoAlertPresentException as e:
pass
pyperclip.copy(title)
self.driver.find_element(By.CSS_SELECTOR, '#post-title-inp').click()
ActionChains(self.driver).key_down(Keys.COMMAND).send_keys('v').key_up(Keys.COMMAND).perform()
time.sleep(0.3)
self.driver.find_element(By.CSS_SELECTOR, '#kakao-editor-container').click()
self.driver.switch_to.frame(self.driver.find_element(By.CSS_SELECTOR, "#editor-tistory_ifr"))
pyperclip.copy(content)
self.driver.find_element(By.CSS_SELECTOR, "#tinymce > p").click()
ActionChains(self.driver).key_down(Keys.COMMAND).send_keys('v').key_up(Keys.COMMAND).perform()
# self.driver.execute_script(
# f"document.querySelector('#tinymce').insertBefore(document.createElement('p').appendChild(document.createTextNode('{content}')), document.querySelector('#tinymce').nextSibling)")
# self.driver.find_element("#tinymce").click()
self.driver.switch_to.default_content()
time.sleep(0.5)
self.driver.find_element(By.CSS_SELECTOR, "#publish-layer-btn").click()
time.sleep(1)
self.driver.find_element(By.CSS_SELECTOR, "#publish-btn").click()

이건 제가 테스트한다고 대충 뉴스 제목 긁어와서 주제 입력만 해서 생성한 블로그입니다. 앞으로 이렇게 블로그 날먹치고 구글 애드센스로 돈 버는게 목적입니다. 아마 시간만 있다면 좀 더 다듬어서 크몽이나 이런데 납품도 할 생각입니다. 지켜봐주십쇼. 감사합니다.
# 위 두 파일을 결합하는 코드
from gpt import create_assistant, create_thread, request_question, separate_response
from blog import Blog
assistant_id = create_assistant()
thread_id = create_thread()
blog = Blog()
def main():
query = input("원하는 블로그 주제와 내용을 입력해주세요. : ")
if not assistant_id or not thread_id:
print('어시스턴트 id 또는 스레드 id가 존재하지 않습니다.')
return
res = request_question(assistant_id, thread_id, query)
title, content = separate_response(res)
blog.main(title, content)
if __name__ == '__main__':
main()
그럼 혹시 이글도?