지금까지 작성한 코드가 잘 작동하는지 확인해보는겸 글 하나를 타겟으로 티스토리에 업로드를 해본다.
사전 준비물
- [Automatic Tech Blog Management] Github Blog: .md파일 및 xml 분석하기
- [Automatic Tech Blog Management] Tistory API 발급받기
run.py 생성하기
```python
from gitblog import *
from tistory import *
import markdown2
from sys import platform
def personal_setting(head, body):
def code_line(text):
text = text.split('\n')
for idx, b in enumerate(text):
if "```" in b:
if "<pre><code>" in b:
text[idx] = b[:11]
else:
if len(b) == 3:
text[idx] = ""
return '\n'.join(text)
return head, code_line(body)
def create_post(githubBlog, tistory):
flag = 0
for g_content in githubBlog.contents:
for t_content in tistory.contents:
if t_content["title"] == g_content["title"]:
flag = 1
if flag:
flag = 0
continue
else:
path = '/' + '/'.join(g_content["link"].split('/')[6:-1]) + ".md"
head, body = githubBlog.parsing_md(path)
body = markdown2.markdown(body)
head, body = personal_setting(head, body)
tistory.posting(
head['title'],
body,
head['categories'],
head['tags'],
)
if __name__ == "__main__":
target_os = ''
if platform == "linux" or platform == "linux2":
target_os = "linux"
elif platform == "darwin":
target_os = "_osx"
elif platform == "win32":
target_os = "_win.exe"
githubBlog = GithubBlog("https://ruby-kim.github.io")
tistory = Tistory('https://dev-rubykim.tistory.com/', target_os)
tistory.get_access_token()
githubBlog.parsing_xml()
tistory.parsing_rss()
tistory.toc_post()
create_post(githubBlog, tistory)
```
- 전체적인 알고리즘은
python-markdown2
패키지를 사용하여.md
파일을.html
로 변경 후 tistory에 업로드 하는 것이다. - 각자 로컬에서 실행하는 개발환경이 다른 점을 고려하여 platform 설정도 넣어놨다. (아래에 tistory 클래스 변경사항 참고)
- 따라서 Windows가 아닌 Linux, OS X를 사용하는 개발자는 자신의 개발환경에 맞춰 chromedriver 파일을 넣어준다.
create_post()
함수는 github blog과 tistory의 포스트를 비교 후 해당 포스트가 없을 시 자동생성 및 업로드 해주는 코드이다.- 코드 중 flag가 바로 중복 포스트 체크를 위한 변수이다.
- hexo 백업용 repository의
/source/_posts
내의 데이터에 접근하기 위해 각자의 github url을 파악 후 알맞게 세팅해준다.- 현재 사용 중인 github blog는 **https://ruby-kim.github.io/YYYY/MM/DD/[.md파일 path]**로 되어 있으므로, 이에 따라 path를 다음과 같이 설정했다.
personal_setting()
은 말 그대로 각자 작성한.md
변환 결과물에서 변경되지 않은 부분이 있을 시 직접 세팅해주는 함수이다.- 56번째 줄의 결과물을 출력해보면 markdown에서 html로 변환 시 코드블럭에 관한 전처리가 덜 되어있음을 확인할 수 있다. (```가 추가됨)
- 따라서 해당 부분을 전처리하는 함수
code_line()
를personal_setting()
에 선언 및 처리한다.
Tistory class 내용 변경
```python
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from urllib.parse import unquote
import time
import os
import json # 추가
class Tistory:
def __init__(self, blogUrl, platform):
# local params
load_dotenv()
self.app_id = os.environ.get("TISTORY_APP_ID")
self.secret_key = os.environ.get("TISTORY_SECRET_KEY")
self.tistory_id = os.environ.get('TISTORY_ID')
self.tistory_pwd = os.environ.get('TISTORY_PWD')
self.tistory_rss = blogUrl + "rss"
# Github Actions params
# self.app_id = os.environ['TISTORY_APP_ID']
# self.secret_key = os.environ['TISTORY_SECRET_KEY']
# self.tistory_id = os.environ['TISTORY_ID']
# self.tistory_pwd = os.environ['TISTORY_PWD']
# self.tistory_rss = blogUrl + "rss"
# Etc params
self.callback_url = blogUrl
self.oauth_url = 'https://www.tistory.com/oauth/authorize'
self.access_token = None
# selenium setting params
self.webdriver_options = webdriver.ChromeOptions()
self.webdriver_options.add_argument('headless')
self.chromedriver = "./chromedriver/chromedriver" + platform # 변경
# ... (생략된 코드는 모두 기존과 동일)
def get_access_token(self):
"""
generate access-token automatically
:return: access-token
"""
browser = webdriver.Chrome(
executable_path=self.chromedriver, # 변경
options=self.webdriver_options
)
self.login_kakao(browser)
self.access_token = self.confirm_tistory_oauth(browser)
if self.access_token is None:
assert "Non-existence access token"
else:
assert "Generate access token Successfully"
def posting(self, title, content, category, tag): # 추가
try:
tistory_url = 'https://www.tistory.com/apis/post/write?'
headers = {'Content-Type': 'application/json; charset=utf-8'}
params = {
'access_token': self.access_token,
'output': 'json',
'blogName': 'dev-rubykim', # 자신의 tistory url 참고
'title': title,
'content': content,
'visibility': '0',
'category': str(category[1:-1]),
'published':'',
'slogan':'',
'tag': str(tag[1:-1]),
'acceptComment': '1',
'password':''
}
data=json.dumps(params)
response = requests.post(tistory_url, headers=headers, data=data)
print(response.text)
except:
print("Error while uploading post in Tistory!")
...
```
- OS에 따른 chromedriver 세팅을 하면서 자잘한 파라미터 값들을 수정한다.
- tistory 글을 업로드 할 수 있는
posting()
을 만든다.
GithubBlog class 내용 변경
```python
class GithubBlog:
def __init__(self, blogUrl):
self.url = blogUrl
self.xml = blogUrl + "/atom.xml"
self.contents = []
self.curTime = datetime.now(pytz.utc).isoformat()
self.md_head = {}
self.md_body = ""
def parsing_md(self, target_path):
# local params
load_dotenv()
repo = get_github_repo(os.environ.get('MY_GITHUB_BLOG_BACKUP'), 'koBlog_backup')
file = get_repo_specific_file_content(repo, target_path)
self.md_head, self.md_body = preprocess(file, target_path)
return self.md_head, self.md_body # 변경
```
기존의 코드에서는 .md의 header와 body를 반환하지 않아 GithubBlog 내부에서만 활용할 수 있는데, 직관적인 코드를 위해 return으로 변경해준다.
run.py 실행하기
```shell
python3 run.py
```
- 결과물이 다음과 같이 나오면 성공적으로 티스토리에 업로드 된 것을 확인할 수 있다.
{"tistory":{"status":"200","postId":"12","url":"https:\/\/dev-rubykim.tistory.com\/12"}}
전체 코드
- https://github.com/ruby-kim/automatic-tech-blog-management/blob/local/run.py
- https://github.com/ruby-kim/automatic-tech-blog-management/blob/local/tistory.py
- https://github.com/ruby-kim/automatic-tech-blog-management/blob/local/gitblog.py