-
티스토리 글쓰기 - 파이썬 selenium 자동 등록 코드코딩 연습/코딩배우기 2024. 11. 21. 10:23
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. 자동 등록 관련 내용 보기
자동 등록 중인 페이지 캡처 이미지
자동 등록 예약 페이지
수정 버튼 클릭 시 페이지
등록된 포스팅 리스트
등록된 포스팅 내용
'코딩 연습 > 코딩배우기' 카테고리의 다른 글
파이썬 정규표현식 r'"(.*?)" ' 과 re.DOTALL 알아보기 (0) 2025.02.01 블로그 글 복사 - 네이버 블로그 텍스트 추출 (0) 2024.11.24 html color에 사용할 rgb 색상표 만들기 (0) 2024.09.08 블로그스팟 포스팅 URL 글 목록 전체 가져오기 (0) 2024.08.25 파이썬 워드클라우드 설치, konlpy Okt() 사용 (0) 2024.02.14