상세 컨텐츠

본문 제목

[Automatic Tech Blog Management] Github blog 포스트를 Tistory에 자동 업로드하기

카테고리 없음

by 루비해 2022. 5. 1. 03:17

본문

지금까지 작성한 코드가 잘 작동하는지 확인해보는겸 글 하나를 타겟으로 티스토리에 업로드를 해본다.

사전 준비물


run.py 생성하기


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 내용 변경


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 내용 변경


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 실행하기


python3 run.py

  • 결과물이 다음과 같이 나오면 성공적으로 티스토리에 업로드 된 것을 확인할 수 있다.
    • {"tistory":{"status":"200","postId":"12","url":"https:\/\/dev-rubykim.tistory.com\/12"}}


전체 코드



관련 포스트 더보기

[Automatic Tech Blog Management] Intro