2022년 10월 15일 15시 33분경 발생한 판교 SK C&C 데이터 센터 화재로 인해 네이버나 다음 카카동 서비스가 일시 중단되면서 티스토리 또한 접속에 재한이 생겼으며 이로하여금 티스토리를 하는 블로거들이 지금까지 작성한 글을 날릴까 걱정이 컸는데 다행히도 자동으로 지금까지 작성된 모든것들이 복구가 되었습니다.
하지만 이 때문에 티스토리 블로거들의 걱정도 커졌는데 그래서 기존에 단종된 기능인 티스토리 백업 기능이 다시 재활성화되었습니다.
그러나 아쉬운점은 티스토리 백업으로 지금까지 작성한 글과 사진이 백업되고 동영상의 경우 별도의 다운로드 링크로제공되며 백업 후 글을 모두 삭제한 뒤 다시 복구를 하거나 다른 티스토리로 이전하기 위해 마이그레이션 복구 기능을 지원하지 않기 때문에 실제로 백업 한 데이터를 재활용 하기 위해서는 워드프레스나 구글 블로그 스팟등 다른 CMS 형 블로그를 사용해야 백업한 데이터를 재사용할 수 있다는 점입니다.
티스토리를 워드프레스 마이그레이션 이전하더라도 기존의 TISTORY.COM 내부링크를 워드프레스 도메인으로 리디렉션 시켜줘야합니다.
티스토리 백업 – 글 사진 동영상 저장
우선 티스토리 백업기능이 2022년 12월에 확인해보니 다시 백업기능이 복구되어 있습니다.
티스토리 관리자 계정으로 로그인 후 설정 – 관리 – 블로그로 들어갑니다.
데이터 관리를 통해 티스토리 블로그 폐쇄를 통한 삭제 및 백업이 가능합니다.
기본적으로 티스토리 백업 시 위 내용을 참고 후 동의하면 백업하기를 눌러줍니다.
- 작성된 글, 첨부 이미지/파일/동영상을 백업 지원합니다.
- 백업 요청 시점을 기준으로 저장된 데이터를 백업 지원합니다.
- 댓글/방명록, 통계, 스킨, 링크 등은 백업되지 않습니다.
- 용량에 따라 다소 시간이 소요될 수 있습니다.
- 데이터 백업 후 30일간 다운로드 가능하며, 해당 기간 동안은 새로운 데이터 백업이 불가능합니다.
- 동영상은 백업 파일 안에 다운로드할 수 있도록 개별 다운로드 링크로 제공됩니다.
2000개가 넘는 글을 백업하는데 걸리는 시간은 대략 1시간 조금 걸리지 않았으며 용량은 대략 20GB 정도의 용량을 보입니다.
백업된 티스토리 글을 워드프레스로 이전하기 위해서 기존의 글을 찾아보던 중 아래 깃허브의 글을 참고하면 도움이 될거 같습니다.
참고 : 카페24 환불 – 워드프레스 서버이전 마이그레이션
워드프레스 FTP 백업 – 로그인 및 블루호스트, 카페24 접속오류
티스토리 백업 워드프레스이전 마이그레이션
참고 : 워드프레스 설치 설정방법 카페24 도메인 호스트 구입
티스토리 가입 네이버 블로그 차이점 장점 및 단점
우선 tistory 의 스킨을 [사용중TickTalk(사용자 수정/업로드) ver.1.0(사용자 수정/업로드)] 으로 변경하시기 바랍니다. 본 스크립트와 설명은 이 스킨을 기반으로 제작되었습니다. 또한 환경설정 – 기본정보 – 블로그 정보 – 주소설정 에서 주소방식을 [숫자 (http://notice.tistory.com/123)] 로 변경하시기 바랍니다. 워드프레스를 미리 설치하신 후 워드프레스 블로그의 url 및 기타 설정을 미리 진행하셔야 합니다. 본 사항을 미리 수행하지 않을경우 스크립트가 동작하지 않을수 있습니다.
티스토리 백업 진행하기 전 모든 부분에 대해서 읽어보신 후 진행하시기 바랍니다. 사전작업이 필요할 수 있습니다.
티스토리 백업하기
우선 tistory_backup.py 를 열어 맨 위의 base_url 을 백업할 블로그의 url 로 변경합니다.
본 스크립트는 이미지 주소를 워드프레스용 주소로 미리 치환합니다. 따라서 워드프레스에 tistory 에서 백업된 사진을 올릴 폴더를 미리 셋팅한 뒤 해당 폴더의 상대주소를 입력해줍니다.
저의 경우는 워드프레스 폴더의 /wp-content/uploads/tistory 폴더를 만들어 업로드 할 예정이었으므로 해당 상대경로를 입력하였습니다.
블로그를 갓 만든 상태에선 uploads 폴더가 없을수 있으며 없으면 만들어주셔야 합니다. 향후 첨부파일이 올라갈 디렉터리 입니다.
파이썬으로 스크립트를 돌립니다.
본 스크립트는 파이썬 2.7 기준으로 제작되었으며 python tistory_backup.py의 data.xml 파일을 잘 보관합니다.
워드프레스에 글 Import 하기
앞서 티스토리 백업 데이터 파일 중 image 폴더에 있는 이미지들을 전체 다 앞서 지정한 서버 폴더에 업로드 합니다.
저의 경우는 /wp-content/uploads/tistory 폴더에 업로드 하였습니다.
WP All Import 라는 plugin 을 다운받아 설치하고 Activate 시킵니다.
관리자 페이지 왼쪽 밑의 All Import 메뉴에서 New Import 를 선택합니다.
Upload a file 버튼을 선택하고 앞서 만들어진 data.xml 파일을 선택하고 업로드 합니다.
업로드 이후 표시된 화면에서 New Items 박스버튼을 선택한 후 Create new [Posts] 를 선택한 이후 아래의 [Continue to Step 2] 버튼을 누릅니다.
다음 화면에서 왼쪽의 박스 버튼 리스트에서 item 을 클릭하신 후 아래의 Continue to Step 3 를 클릭합니다.
다음에 표시된 화면의 오른쪽 XML tree 에서 <title> 을 클릭하여 왼쪽의 제목창으로 drag & drop 합니다.
같은 방법으로 content 도 왼쪽의 본문 창으로 drag & drop 합니다.
본문창 바로 아래의 Advanced Options 창을 눌러서 열은 뒤 모두다 체크 해제하고 Decode HTML entities with html_entity_decode 만 활성화 합니다.
아래의 Images 드롭다운 메뉴를 눌러 열은 뒤 라디오 체크박스에서 Use images currently in Media Library 를 선택합니다.
그 다음 아래의 Taxonomies, Categories, Tags 드랍다운 창을 열어서 카테고리나 태그를 설정합니다. 일괄로 Tistory_backup 같은 카테고리나 태그를 설정할수도 있고 백업된 파일에서 가져와서 원래의 카테고리를 설정할수도 있습니다. 원래의 카테고리를 설정할 경우 오른쪽 XML tree 에서 category 를 입력창으로 drag & drop 합니다.
그 다음 아래의 Other Post Options 를 누른 뒤 Post Dates 부분의 입력창에서 now 를 지우고 오른쪽 XML tree 에서 date 를 drag & drop 합니다.
그 다음 맨 아래의 Continue to Step 4 를 클릭합니다.
Unique Idenfier 부분에 오른쪽 XML Tree 의 id 를 drap & drop 하고 맨 아래의 Continue 를 클릭하고 최종 Import 진행 버튼을 눌러 Import 를 진행합니다.
게시글의 숫자에 따라 다소 시간이 소요될수 있습니다.
게시글의 id 수정하기
게시글의 id 가 단순히 순차적으로 증가된 값으로 등록되기 때문에 원래의 Tistory 블로그 주소 숫자와 매칭이 되지 않을수 있습니다. 따라서 db 를 수정하여 해당 부분을 바로잡아줄수 있습니다.
기존 블로그에서 Redirect 를 시킬 필요가 없다면 본 작업은 수행하지 않아도 됩니다. 본 작업을 위해서는 워드프레스도 동일하게 블로그 주소 방식을 숫자로 변경해야 합니다
워드프레스 설정에서 Settings – Permalinks – Common Settings 에서 Custom Structure 를 선택하신 후 “/%post_id%” 라고 입력합니다(따옴표는 제외).
본 작업을 수행하기 전에 wordpress db 를 dump 하여 백업해 놓으신뒤 진행하시기 바랍니다. 본 작업으로 인한 데이터 손실은 책임지지 않습니다. 빈 워드프레스 DB 에서 진행할것을 권장합니다.
또한 기존에 워드프레스 글 데이터가 있을 경우 ID 값이 충돌하여 에러가 발생할수 있습니다. 이 경우 본 작업은 진행하시면 안됩니다.
- DB 관리툴을 열어 wp_posts (설정에 따라 앞의 wp 부분 prefix가 다를수 있음) 에서 새로 import 된 글의 guid 부분을 확인하고 복사합니다.
- 해당 guid 에서 뒤의 숫자 부분만 지운 url 을 change_index.sql 의 아래 블로그 주소 부분을 지우고 넣습니다.
- 자신의 워드프레스 db 테이블 이름에 맞게 wp_posts 와 wp_pmxi_posts 부분을 수정한 후 sql 문을 수행합니다.
- sql 문이 잘 수행이 되었는지 확인합니다. 잘 수행이 되었다면 id 가 기존 티스토리 블로그에 매칭되도록 변경됩니다.
- 블로그 주소로 접속하여 확인해봅니다.
티스토리 새 워드프레스 자동 리디렉션 주소 변경
티스토리 관리자 페이지에서 꾸미기 – HTML/CSS 편집에 들어간 뒤 </head> 바로 윗 부분에 tistory_auto_redirect.js 파일에 있는 코드를 붙여넣습니다.
붙여넣을때에 해당 스크립트의 윗 부분에 있는 BLOG_SITE_URL 의 변수를 자신의 새로운 블로그 URL 로 변경합니다.
본 스크립트를 추가하고 저장하면 이 스크립트가 자동으로 블로그의 같은 번호의 글을 체크하여 새로운 블로그에 같은 번호의 글이 있을때만 Redirect 시킵니다.
UPDATE wp_posts AS t
INNER JOIN wp_pmxi_posts AS tr
ON t.id = tr.post_id
SET t.id = tr.unique_key;
UPDATE wp_posts SET guid = CONCAT("https://blog.domain.com/archives/", CAST(id AS CHAR)) WHERE id > 40;
<script>
var BLOG_SITE_URL = 'https://blog.domain.com'
function isUrlExists(url, page_url)
{
$.getJSON("http://query.yahooapis.com/v1/public/yql?"+
"q=select%20*%20from%20html%20where%20url%3D%22"+
encodeURIComponent(url)+"%22&format=json'&callback=?", function(data){
if(data.results[0]){
window.location.replace(BLOG_SITE_URL + page_url);
}
else{
}
}
);
}
var page_url = window.location.pathname;
if (page_url.length > 1) {
isUrlExists(BLOG_SITE_URL + page_url, page_url);
}
</script>
# -*- coding: utf8 -*-. #
from __future__ import unicode_literals
import urllib2
import BeautifulSoup
import time
import dicttoxml
import sys
import urllib
base_url = 'yourblog.tistory.com'
image_content_url = '/wp-content/uploads/tistory/'
article_data = []
error_count = 0
error_max_count = 50
try:
for index in range(42, 1000):
u = None
try:
u = urllib2.urlopen('http://' + base_url + '/' + str(index))
except urllib2.HTTPError as e:
if e.code == 404:
print('Post ' + str(index) + ' - Not Found')
error_count += 1
if error_count > error_max_count:
print('Error Count is over the max value. Stopping the crawler')
break
time.sleep(3)
continue
else:
raise
error_count = 0
b = BeautifulSoup.BeautifulSoup(u.read())
# Check 404 also
absent_post = b.find('div', {'class': 'absent_post'})
if absent_post:
print('Post ' + str(index) + ' - Not Found')
time.sleep(3)
continue
# Get Title of article
title = b.find('div', {'class': 'tit'}).find('a', {'class': 'link'}).contents[0].encode('utf-8')
category = b.find('div', {'class': 'tit'}).find('a', {'class': 'category'}).contents[0].encode('utf-8')
date = b.find('div', {'class': 'tit'}).find('span', {'class': 'date'}).contents[0].replace('.', '-').replace(' ', 'T') + ':00'
# Get Atricle from page
article = b.find('div', {'class': 'desc'})
# Delete another category article element
another_category = article.find('div', {'class': 'another_category another_category_color_gray'})
if another_category:
another_category.decompose()
# Delete Copyright element
article.find('div', {'style': 'width:100%;margin-top:30px;clear:both;height:30px'}).decompose()
imagelist = article.findAll('img')
for image in imagelist:
if '//cfile' in image['src']:
filename = image['src'].split('/')[-1]
filetype = ''
if 'itistory-photo' in image['filename']:
if image['filemime'] == 'image/jpeg' or image['filemime'] == 'image/jpg':
filetype = 'jpg'
elif image['filemime'] == 'image/png':
filetype = 'png'
elif image['filemime'] == 'image/gif':
filetype = 'gif'
else:
filetype = image['filename'].split('.')[-1].lower()
print(filename + '.' + filetype)
try:
urllib.urlretrieve(image['src'], 'image/' + filename + '.' + filetype)
except Exception:
print('File retrieve error - ' + image['src'])
# Object is soft copy object. It will change root object value.
image['src'] = image_content_url + filename + '.' + filetype
image['onclick'] = None
print('Post ' + str(index) + ' - [' + category.decode('utf-8') + ']' + title.decode('utf-8') + ' - ' + date)
article_data.append({
'id': index,
'title': title,
'date': date,
'category': category,
'content': str(article)
})
time.sleep(3)
except KeyboardInterrupt:
xml = dicttoxml.dicttoxml(article_data, custom_root='article', attr_type=False)
file = open('data.xml', 'w')
file.write(xml)
file.close()
sys.exit(0)
xml = dicttoxml.dicttoxml(article_data, custom_root='article', attr_type=False)
file = open('data.xml', 'w')
file.write(xml)
file.close()
해당 글의 원문은 이곳에서 확인가능하며 티스토리 연동을 위한 워드프레스 플러그인도 참고하세요
이상 티스토리 백업 및 워드프레스 서버 이전 마이그레이션에 대해 알아보았습니다.