네이버 블로그를 백업해보자 - 3편

  • 오늘은 이번 네이버 블로그 백업 연재의 마지막편입니다.
  • 블로그 포스팅의 내용이 바뀌었다면 깃헙 레포지토리에도 바뀐 내용을 업데이트 해야겠죠?
    • 2편에서는 커밋을 통해 새로운 파일을 만들었다면, 이번에는 이미 파일이 있는 경우 수정하도록 해보겠습니다.
    • 방법을 간략하게 정리해 보면
      • 먼저 해당 파일이 존재하는지 확인하기 위해서 아래 페이지의 내용을 살펴봅시다.
        • 깃헙파일 정보얻기
        • 위 링크의 호출에서 파일이 존재하면 200 상태로 반응하고 Body에 sha 프로퍼티가 존재합니다.
            def get_github_sha(url, token):
                headers = {
                    "Accept": "application/vnd.github+json",
                    "Authorization": "Bearer %s" % token,
                    "X-GitHub-Api-Version": "2022-11-28"
                }
                r = requests.get(url, headers=headers)
                if r.status_code == 200:
                    return r.json().get("sha")
                return False
          
      • 위에서 얻게된 sha를 지난번까지 사용했던 PUT 호출에 함께 넣어 보내면 Create가 아니라 Update가 되는 것 입니다.
        • 깃헙파일 생성 혹은 수정하기
        • 파일이 수정되면 자동으로 푸시되게 하기 위해서 branch 프로퍼티를 추가했습니다.
            def put_github_file(url, github_owner, email, content, token):
                headers = {
                    "Accept": "application/vnd.github+json",
                    "Authorization": "Bearer %s" % token,
                    "X-GitHub-Api-Version": "2022-11-28"
                }
                sha = get_github_sha(url, token)
                if sha == False:
                    ## No sha means No File
                    data = {
                        "message": "commit",
                        "branch": "master",
                        "committer": {
                            "name": github_owner,
                            "email": email
                        },
                        "content": content
                    }
                    requests.put(url, data=json.dumps(data), headers=headers)
                else:
                    ## Update File
                    data = {
                        "message": "commit",
                        "branch": "master",
                        "sha": sha,
                        "committer": {
                            "name": github_owner,
                            "email": email
                        },
                        "content": content
                    }
                    requests.put(url, data=json.dumps(data), headers=headers)
          
      • 그렇게 되면 깃헙페이지 특성상 자동으로 깃헙액션을 수행하고, 빌드 및 배포가 진행됩니다.
  • 한편 배포된 깃헙 페이지의 URL이 구글검색에 표시될 수 있도록, 서치콘솔에 URL을 등록하는 호출도 해보겠습니다.
    • 그러기 위해서는 구글 개발자 서비스계정을 등록해야합니다.
    • 그리고 나서 인증에 사용되는 사용자를 등록한 후 JSON 파일을 받아야 합니다.
    • 마지막으로 서치콘솔 URL Indexing을 사용하겠다고 지정해야 아래의 호출을 정상적으로 수행 할 수 있습니다.
      • URL Indexing Creation API
          def update_google_search_console_url_index(url):
              SCOPES = [ "https://www.googleapis.com/auth/indexing" ]
              ENDPOINT = "https://indexing.googleapis.com/v3/urlNotifications:publish"
        
              # service_account_file.json is the private key that you created for your service account.
              JSON_KEY_FILE = "file_name.json"
        
              credentials = ServiceAccountCredentials.from_json_keyfile_name(JSON_KEY_FILE, scopes=SCOPES)
              headers = {'Content-Type': 'application/json'}
              http = credentials.authorize(httplib2.Http())
        
              content = """{
              \"url\": \"%s\",
              \"type\": \"URL_UPDATED\"
              }""" % url
        
              response, content = http.request(ENDPOINT, method="POST", body=content, headers=headers)
        
  • 전체 코드는 아래 링크에 올려두었습니다. 지난번과 비교했을 때 달라진 내용은 아래와 같습니다.
    • 블로그 내용을 가져올 때, 링크 형태이면 MarkDown에서도 링크 형태로 보여지도록 했습니다.
    • 파일명에 표시되는 날짜도 직접 지정할 수 있게 코드를 수정했습니다.
    • 전체코드

구글 바드를 이용해 봤습니다!!!

챗 GPT를 뛰어넘는 물건이 나타났다고 해서
한 번 이용해 봤습니다.
바로 구글 바드!!!



Alt text

재미나이라는 엄청난 AI 추론 모델을 이용해서
텍스트는 물론
이미지 등의 멀티미디어 컨텐츠까지
제공하는 서비스라고 하더군요~



Alt text

그래서 위와 같은 요구를 날려 봤습니다.
말길을 알아듣는 것 같긴 하군요~
그런데 제공해 준 사진을 클릭하니
좀 이상합니다.
저는 생성형 이미지를 직접 만들어 줄 거라고
기대했는데.. 그냥 유료 이미지 사이트를
연결해 주네요.

https://kr.freepik.com/premium-photo/young-father-raising-his-cute-baby-girl-and-looking-at-her-at-home-happiness-of-being-father-and-parenthood-lovely-warm-moment-of-dad-and-baby-lifestyle-concept_25560259.htm

이번에는 조금 더 구체적으로 아래와 같은
요청을 날려 봤습니다.



Alt text
아래와 같은 내용의 컨텐츠와 사진을
연결해 놓고 전형적인 한국의 거실이라고
사기(?)를 치네요????

https://m.post.naver.com/viewer/postView.nhn?volumeNo=10164537

이번에는 코딩도 할 수 있는지
시켜봤습니다.
Alt text
흠… 이건 좀 무섭습니다.
하지만 정말로 연역적인 추리를 하는 것인지
외워서 정답을 내놓는 것인지는
확인이 필요할 듯합니다.
이 분야는 추후에 더 깊이 있게
확인해 보도록 하구요~


Alt text
이번에는 제가 운영하는 유튜브 채널을
알고 있는지 물어봤습니다.
정말 대답을 뻔뻔하게 잘하네요.
바드가 아니라 뻔뻔이로 이름을 바꿔야겠어요.
야옹철톡은 도대체 어떤 분의 유튜브 채널일꼬…
제가 운영하는 유튜브는
호박이의 망난감랜드 인데 말이죠…
구독자가 42만명???
누구 놀리나!!! 꼴랑 206명이다!!
마지막으로 이 블로그에 대해서 알고 있는지
물어봤습니다.



Alt text
뭐??? 호박즙???
도라지21??? 구독자가 10만 명???
이거 뻔뻔한 게 아니라
가짜 뉴스 생성기였네~~
하지만 끝부분에 절반의 진실을 담은
내용이 살짝 소름 돋게 합니다.
Alt text
블로그 주인은
2022년 12월에 딸 ‘어흥이’를 출산하고
(2023년 1월이죠 땡!)

같은 해 10월에
고양이 ‘호박이’를 입양했습니다.
(2017년 10월인데요…
그래도 10월은 맞췄네)

블로그에는 어흥이, 호박이와 함께하는 일상과 육아, 반려동물에 대한 다양한 정보를 공유하고 있습니다.
(오잉)

블로그의 특징은 다음과 같습니다.

글과 사진의 퀄리티가 높다.
육아, 반려동물에 대한 정보가 풍부하다.
공감과 유익함을 주는 콘텐츠를 제공한다.

어흥&호박이네는
육아, 반려동물에 관심이 있는 분들에게
유익한 블로그라고 생각합니다.
킹바드 갓바드 曰
뭔가 엉성하면서도 신기하네요…
점점 진화하면서 정확도가 높아지지 않을까요?
몇 주 후에 또 확인해 봐야겠어요.

네이버 블로그를 백업해보자 - 2편

  • 지난 시간에는 네이버 블로그에 있는 글과 이미지를 가져오는 방법에 대해서 고민해 봤다면
  • 오늘은 가져온 글과 이미지를 GITHUB API를 이용해서 깃헙블로그에 올리는 내용을 살펴보겠습니다.
  • 제가 운용하는 깃헙블로그는 깃헙페이지와 jekyll을 이용해서 구축되었습니다.
  • GITHUB API를 이용하기 위해서는 사전에 TOKEN을 받아두어야 합니다.
  • 긴 말 할 거 없이 코드를 보시죠~
import requests
from bs4 import BeautifulSoup
from datetime import datetime
from dotenv import load_dotenv
import os
import json
import base64

# 이미지 파일을 다운로드하는 함수
def download(url, file_name):
    with open(file_name, "wb") as file:
        response = requests.get(url)
        file.write(response.content)

# 블로그로부터 글과 이미지를 가져오는 함수
def get_blog_content(blog_id, post_id, github_img_path, author, category, tags):
    # 블로그에 올라가는 마크다운 헤더를 미리 지정합니다
    mark_downs = ['---',
                  'layout: post',
                  '',
                  '',
                  'date: %s' % datetime.today().strftime('%Y-%m-%d'),
                  'author: "%s"' % author,
                  'categories: [%s]' % category,
                  'tags: [%s]' % tags,
                  '---'
    ]
    post_url = 'https://blog.naver.com/PostView.naver?blogId=%s&logNo=%s&redirect=Dlog&widgetTypeCall=true&directAccess=true'
    html_text = requests.get(post_url % (blog_id, post_id)).text
    soup = BeautifulSoup(html_text, 'html.parser')

    img_file_count = 0
    is_fist = True
    for item in soup.select('span, img'):
        has_text = False
        if item.attrs.get("class"):
            for classItem in item.attrs.get("class"):
                if str(classItem).count("se-f") > 0:
                    has_text = True
                elif str(classItem).count("se-image-resource") > 0:
                    has_text = True
            if has_text:
                if item.name == 'img':
                    # 이미지 파일을 다운로드 합니다
                    img_src = item.attrs.get("data-lazy-src")
                    file_name = "img_file_%s.png" % img_file_count
                    download(img_src, file_name)
                    img_file_count = img_file_count + 1
                    mark_downs.append("![Alt text](%s/%s)<br/>" % (github_img_path, file_name))
                else:
                    if is_fist:
                        # 첫번째 텍스트는 제목이기 때문에
                        mark_downs[2] = 'title: "%s"' % item.text.replace("<!-- -->", "")
                        mark_downs[3] = 'description: "%s"' % item.text.replace("<!-- -->", "")
                        is_fist = False
                    else:
                        mark_downs.append("%s<br/>" % item.text)
    return mark_downs, img_file_count

# 깃헙 API를 이용해서 파일을 업로드하는 함수
def github_api(url, github_owner, email, content, token):
    headers = {
        "Accept": "application/vnd.github+json",
        "Authorization": "Bearer %s" % token,
        "X-GitHub-Api-Version": "2022-11-28"
    }
    data = {
        "message": "commit",
        "committer": {
            "name": github_owner,
            "email": email
        },
        "content": content
    }
    requests.put(url, data=json.dumps(data), headers=headers)

# 깃헙 API 함수를 호출하기 위한 중간 함수
def add_to_github(post_id, md, img_count, github_owner, email, github_repo, post_path, img_path, github_token):
    github_post_url = "https://api.github.com/repos/%s/%s/contents/%s" % (github_owner, github_repo, post_path)
    github_image_url = "https://api.github.com/repos/%s/%s/contents/%s" % (github_owner, github_repo, img_path)

    # MD File Commit
    post_name = "%s-%s.md" % (datetime.today().strftime('%Y-%m-%d'), post_id)
    md_bytes = '\n'.join(md).encode('utf-8')
    # base64로 변환후에 이것을 다시 ascii text로 바꿉니다
    md_base64 = base64.b64encode(md_bytes)
    github_api("%s/%s" % (github_post_url, post_name), github_owner, email, md_base64.decode('ascii'), github_token)

    # Image Files Commit
    for i in range(img_count):
        img_file_name = "img_file_%s.png" % i
        with open(img_file_name, "rb") as image_file:
            img_base64 = base64.b64encode(image_file.read())
            github_api("%s/%s" % (github_image_url, img_file_name), github_owner, email, img_base64.decode('ascii'), github_token)

# .env 파일로부터 변수들을 가져 옵니다
load_dotenv()
blog_id = os.environ.get("blog_id")
post_id = os.environ.get("post_id")
github_owner = os.environ.get("github_owner")
github_repo = os.environ.get("github_repo")
email = os.environ.get("email")
github_post_path = os.environ.get("github_post_path")
github_img_path = os.environ.get("github_img_path")
author = os.environ.get("author")
tags = os.environ.get("tags")
github_token = os.environ.get("github_token")

today = datetime.today().strftime('%Y%m%d')

full_img_path = "https://%s.github.io/%s/%s/%s" % (github_owner, github_repo, github_img_path, today)

md, img_count = get_blog_content(blog_id, post_id, full_img_path, author, "Lifes", tags)
add_to_github(post_id, md, img_count, github_owner, email, github_repo, github_post_path, "%s/%s" % (github_img_path, today), github_token)