goodthings4me.tistory.com
2년 전에 티스토리 API를 활용하여 자동 등록하는 코드를 만들었는데, 이용을 안 하다가 최근에 다시 해볼까 해서 정보를 찾아보니 티스토리 등록 API가 없어졌다고 한다. 그래서 selenium을 만들어서 테스트한 후 그 코드를 올려봅니다.
티스토리에 html 파일 자동 등록하기
티스토리에 여러개의 글을 html 파일 형태로 등록하기 위해서는 다음과 같은 절차로 진행합니다.
- 카테고리를 하나 만든다. (카테고리가 없으면 생략해도 되지만, 아래 코드는 '테스트'라는 카테고리에 등록함)
- 티스토리에 포스팅 등록할 html 파일을 먼저 만든다.
- selnium을 사용하여 티스토리에 자동으로 html 모드 방식으로 등록하도록 코드를 작성한다. (아래 코드)
1. 티스토리 카테고리 만들기
2. 포스팅 등록할 html 코드 작성하기
파일 이름이 긴 이유는
파일 이름 중 '$'를 구분자로 하여 파이썬 코드에서 split() 함수로 나눈 후,
앞 부분은 포스팅 제목으로 사용하고,
뒷 부분은 태그로 자동 등록하기 위함
[html 파일 코드]
<h2 style="text-align: center; font-weight: bold;">마인드시티 앱 다운로드</h2>
<p style="text-align: center;">
<a href="https://play.google.com/store/apps/details?id=com.kobotis.mindcity&hl=ko" target="_blank" style="display: inline-block; background-color: green; color: white; font-weight: bold; padding: 10px 20px; border-radius: 15px; text-decoration: none; transition: background-color 0.3s;">Mind City 앱 다운로드(Android)</a>
</p>
<p style="text-align: center;">
<a href="https://apps.apple.com/kr/app/%EB%AF%B8%EC%85%98%EC%8B%9C%ED%8B%B0-missioncity/id1663107997" target="_self" style="display: inline-block; background-color: blue; color: white; font-weight: bold; padding: 10px 20px; border-radius: 15px; text-decoration: none; transition: background-color 0.3s;">Mind City 앱 다운로드(IOS)</a>
</p>
3. 포스팅 html 글을 selnium을 사용하여 티스토리에 자동 등록하는 파이썬 코드
import os, time, random
import pyperclip
import chromedriver_autoinstaller
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
import keys_manager
import pyperclip
def init_driver():
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36') # 사용자 에이전트 지정
# chrome_options.add_argument('headless')
chrome_options.add_experimental_option('detach', True)
chrome_ver = chromedriver_autoinstaller.get_chrome_version()
print(f'크롬 현재 버전: {chrome_ver}')
chromedriver = f'./{chrome_ver.split(".")[0]}/chromedriver.exe'
if not os.path.exists(chromedriver):
os.makedirs(os.path.dirname(chromedriver), exist_ok=True)
res = chromedriver_autoinstaller.install(True) # 크롬 드라이버 다운로드
if res:
print(f'크롬 드라이버 설치 완료!({chrome_ver.split(".")[0]} 버전)')
else:
print(f'크롬 드라이버 설치 오류 발생!({chrome_ver.split(".")[0]} 버전)')
driver = webdriver.Chrome(options=chrome_options)
return driver
def tistory_login(_driver):
_driver.get('https://www.tistory.com/auth/login')
time.sleep(3)
login_button = _driver.find_element(By.CLASS_NAME, 'txt_login')
login_button.click()
time.sleep(1)
# 아이디 입력
email_input = _driver.find_element(By.NAME, 'loginId')
email_input.click()
time.sleep(0.5)
email_input.send_keys(keys_manager.mindcity[0])
time.sleep(1)
# 비밀번호 입력
password_input = _driver.find_element(By.NAME, 'password')
password_input.click()
time.sleep(0.5)
password_input.send_keys(keys_manager.mindcity[1])
time.sleep(1)
# 로그인 버튼 클릭
login_button = _driver.find_element(By.CSS_SELECTOR, 'button[type="submit"]')
login_button.click()
time.sleep(60) # 2단계 인증 또는 캡차 있을 시 60
def tistory_write():
_driver = init_driver() # chrome driver init
tistory_login(_driver) # 티스토리 로그인
## 예약 발행 시, 분
hour_minute = [
(10, random.randint(1, 15)),
(10, random.randint(41, 59)),
(11, random.randint(1, 15)),
(11, random.randint(41, 59)),
]
## 포스팅 티스토리 URL, 카테고리 지정 필수!!
tistory_blog_name = f'''https://mind-city.tistory.com'''
tistory_category_name = '테스트'
# html 파일이 있는 폴더 경로
folder_path = "./data/tistory/"
file_list = []
for filename in os.listdir(folder_path):
file_list.append(filename)
print(file_list)
hm_idx = 0
for n, file_name in enumerate(file_list, 1):
posting_title = file_name.split('$')[0]
tags = file_name.split('$')[1].replace('.html', '')
print(f'\n{posting_title}\n{tags}\n\n')
time.sleep(3)
# tistory 포스팅 시작
_driver.get(f'{tistory_blog_name}/manage/post')
time.sleep(3)
# _driver.maximize_window() # 창 최대화
# 이전에 쓰고 있는 글이 있어도 새로운 글을 작성하도록 alert popup 처리
try:
obj = _driver.switch_to.alert
print(f'\nalert dismiss')
obj.dismiss()
time.sleep(2)
except:
pass
### html 모드로 작성 ###
# html 모드로 변환
_driver.find_element(By.ID, 'editor-mode-layer-btn-open').click()
time.sleep(2)
_driver.find_element(By.ID, 'editor-mode-html').click()
time.sleep(2)
_driver.switch_to.alert.accept() # html 모드 변환시 alert 처리
time.sleep(2)
# 카테고리 선택 - 위에서 카테고리로 지정한 것 찾음
_driver.find_element(By.ID, 'category-btn').click()
time.sleep(2)
_driver.find_element(By.XPATH, f"//span[normalize-space()='{tistory_category_name}']").click()
time.sleep(2)
# 제목 입력
_driver.find_element(By.ID, 'post-title-inp').click()
pyperclip.copy(posting_title)
ActionChains(_driver).key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()
time.sleep(1)
# 글쓰기 -------------------------------------------------------------------------
post_body_content = ''
if file_name.endswith(".html"):
input_path = os.path.join(folder_path, file_name)
# 파일을 여러 인코딩 방식으로 시도하여 읽기
encodings = ['utf-8', 'cp949']
for encoding in encodings:
try:
with open(input_path, 'r', encoding=encoding) as file:
post_body_content = file.read()
break
except UnicodeDecodeError:
print(f"Failed to read {input_path} with encoding {encoding}")
continue
else:
print(f"Failed to read {input_path} with all tried encodings.")
continue
_driver.find_element(By.CLASS_NAME, 'CodeMirror-lines').click()
pyperclip.copy(post_body_content)
ActionChains(_driver).key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()
time.sleep(1)
# 태그 입력하기
tag_input = _driver.find_element(By.ID, "tagText")
tag_input.click()
time.sleep(1)
tag_input.send_keys(tags)
tag_input.send_keys(Keys.RETURN)
time.sleep(1)
# 완료 버튼 누르기
_driver.find_element(By.ID, 'publish-layer-btn').click()
time.sleep(1)
# 공개 버튼
_driver.find_element(By.ID, 'open20').click()
time.sleep(2)
# 예약 버튼 - 위 예약 버튼, 형제 태그인 예약 버튼 찾기에서 에러가 발생하여 아래 코드로 수정하여 사용함
current_reserve = _driver.find_elements(By.CLASS_NAME, "btn_date")
current_reserve[1].click()
time.sleep(1)
new_hour = hour_minute[hm_idx][0]
new_minute = hour_minute[hm_idx][1]
# 예약 시간 입력: 두 번째 box_date의 input 태그 찾기
hour_input = _driver.find_element(By.XPATH, "(//div[@class='box_date']/input[@type='number'])[1]") # 시간
hour_input.click()
time.sleep(1)
# 새 시간 입력
hour_input.clear() # 기존 값 지우기
hour_input.send_keys(str(new_hour))
time.sleep(1)
# 예약 시간 입력: 세 번째 box_date의 input 태그 찾기
minute_input = _driver.find_element(By.XPATH, "(//div[@class='box_date']/input[@type='number'])[2]") # 분
minute_input.click()
time.sleep(1)
# 새 시간 입력
minute_input.clear() # 기존 값 지우기
minute_input.send_keys(str(new_minute))
time.sleep(1)
# '공개 발행' 버튼 클릭
publish_button = _driver.find_element(By.ID, "publish-btn")
publish_button.click()
time.sleep(2)
hm_idx += 1
_driver.quit()
print("\nEND!!!")
tistory_write()
- init_driver() 함수는 selenium 웹드라이버 구동 함수이고,
- tistory_login() 함수는 selenium 구동 웹 페이지에서 tistory.com에 접속한 후 아이디와 비밀번호를 자동으로 입력함
- 이때, keys_manager 모듈을 통해 해당 티스토리의 계정(id, pw)을 가진 리스트 변수에서 id, pw를 불러오도록 함
- 로그인 버튼 클릭 마지막 부분에 있는 time.sleep(60)은 혹시 있을 티스토리 2단계 인증 또는 캡챠를 대비하기 위해 60초로 설정되어 있고, 이 2가지가 뜨지 않는다면 2~3초 설정해도 됨
- tistory_write() 함수에서 hour_minute 부분은 예약 설정을 위한 것으로, (10, random.randint(1, 15)) 의미는 10시 기준으로 1분에서 15분 사이의 숫자 1개를 사용하도록 함
- 첫번째 for 문은 지정 폴더에서 여러 개의 html 파일을 읽어서 file_list 리스트에 넣고,
- 두번째 for 문은 실제 파일을 하나씩 불어와서 포스팅 제목과 태그를 설정하고, 포스팅을 자동으로 시작하는 코드임
- 잠시 기다리면 html 모드로 해당 html 파일을 자동으로 등록함
4. 자동 등록 관련 내용 보기
자동 등록 중인 페이지 캡처 이미지
자동 등록 예약 페이지
수정 버튼 클릭 시 페이지
등록된 포스팅 리스트
등록된 포스팅 내용
'코딩 연습 > 코딩배우기' 카테고리의 다른 글
블로그 글 복사 - 네이버 블로그 텍스트 추출 (0) | 2024.11.24 |
---|---|
html color에 사용할 rgb 색상표 만들기 (0) | 2024.09.08 |
블로그스팟 포스팅 URL 글 목록 전체 가져오기 (0) | 2024.08.25 |
파이썬 워드클라우드 설치, konlpy Okt() 사용 (0) | 2024.02.14 |
파이썬 도서관리 프로그램 (0) | 2024.01.03 |
댓글