티스토리 블로그를 2차 개인 도메인으로 사용하다가 다시 기존 tistory.com 도메인으로 원위치 했습니다.

2차 도메인 주소에서 1차 도메인으로 리디렉션까지 시켰지만 그 이후로 블로그 방문통계를 보니 유입 수치가 엄청 줄어들었습니다.

언젠간 다시 회복되겠지 하면서 거의 1년이 흘렀지만 아직 여전히 회복이 되지 않더군요~ ㅋ

그래서 Google Search Console 메뉴를 여기저기 둘러봤더니 설정에 주소 변경이라는 항목이 있네요~

속성 설정에 주소 변경을 클릭합니다.

리디렉션은 예전에 아파치 .htaccess 파일에 걸어두었습니다.

RewriteEngine On

RewriteCond %{HTTP_HOST} ^blog\.ivps\.kr$ [NC]
RewriteRule ^(.*)$ https://ivps.tistory.com%{REQUEST_URI} [R=301,L]

blog.ivps.kr 요청이 오면 ivps.tistory.com 으로 리디렉션 하도록 한 설정입니다.

새 사이트 선택에서 변경할 사이트를 선택하고 유효성 검사 및 업데이트를 누릅니다.

유효성 검사 통과가 되면 이동 확인을 누릅니다.

이렇게 해놓고 몇일을 더 기다려 봐야겠습니다.

도움말은 여기를 참고하세요~

 

블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

티스토리에 2차 도메인으로 개인 도메인이 연결되어 있었는데 보안사이트가 적용되지 않아서 과감히 연결을 해제했습니다.

1차와 2차 모두 네이버 웹마스터 도구에 등록이 되어 있는데도 하나를 지웠더니 방문수가 급격하게 줄어들었네요~

유입 감소를 해결하기 위한 방법에 대해서 알아보겠습니다.

티스토리 개인 도메인 연결 해제 후 검색유입 감소

검색 유입다음에서만 되는 것 같습니다.

며칠 좀 더 지켜봐야겠네요~

 

개인도메인 삭제한지 딱 7일이 지났는데, 네이버, 구글 실망입니다~ ㅋ

중복 사이트 패널티 먹은건지 잘 모르겠지만 1차 도메인 주소로 검색 색인현황을 보니 좀 더딘 것 같습니다.

네이버 웹마스터도구 색인현황

 

▶ 1차 조치사항 ( 7일이 지난 후 )

  ☞ 기존 2차 도메인 호스트를 가상서버에 웹서비스를 구축하고 .htaccess 작성해서 1차 도메인으로 리다이렉트 적용

      한번 지켜봐야겠네요~

      효과가 있네요~ 예전만 못하지만 기존 2차 도메인 주소 타고 리디렉션 되어서 오는 것 같습니다.

 

▶ 검색유입 감소 해결 방법

  ☞ 1차 도메인 네이버 및 구글 웹마스터도구에 사이트 주소 등록

  ☞ 기존 2차 도메인 주소를 1차로 리디렉션 하기

RewriteEngine On

RewriteCond %{HTTP_HOST} ^blog\.ivps\.kr$ [NC]
RewriteRule ^(.*)$ https://ivps.tistory.com%{REQUEST_URI} [R=301,L]

제 블로그 주소를 예로 들었는데 본인의 블로그 주소에 맞게 수정하시면 됩니다.

 

블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[티스토리] Python Open API 이용 블로그 및 이미지 백업하기



앞에서는 블로그의 내용만 RSS 로 만들었는데 이번에는 사진 이미지까지 백업하는 파이썬 소스코드를 공개합니다.


티스토리에서 워드프레스로 완전히 이전을 원하시는 경우에 사용하시면 됩니다.


이미지는 본문 내용에 포함할 수도 있고 다운로드한 사진은 img src 의 url 을 치환할 수도 있습니다.


IMG_SRC_TYPE 값이 1 이면 URL 만 치환, 2 이면 본문에 이미지 삽입


본문에 포함되는 방식이 아닌 1의 경우는 아래 코드에서 저장된 이미지 파일을 해당 경로에 수동으로 업로드 하셔야 합니다.



▶ Python 소스코드


# coding=utf-8

# pip install beautifulsoup4

# pip install python-magic

# pip install pytz

# pip install requests

# pip install urllib3

import base64

import json

import magic

import math

import os

import requests

import urllib2

import urlparse

import xml.etree.ElementTree as xml

from bs4 import BeautifulSoup

from datetime import datetime

from pytz import timezone


URL_0 = 'https://www.tistory.com/auth/login'       ### 티스토리 로그인 URL

URL_1 = 'https://www.tistory.com/oauth/authorize'  ### 인증 요청 및 Authentication code 발급 URL

URL_2 = 'https://www.tistory.com/apis/blog/info'   ### 블로그 정보 URL

URL_3 = 'https://www.tistory.com/apis/post/list'   ### 블로그 리스트 URL

URL_4 = 'https://www.tistory.com/apis/post/read'   ### 블로그 상세보기 URL

blogName = 'ivps' ### 블로그명

page = 0          ### 1 페이지 부터 시작

count = 30        ### 최대값 30

post_id = 0       ### 아래에서 데이터를 추출

access_token = '' ### 아래에서 데이터를 추출

loginParams = {                                    ### 로그인 Parameters ( 블로그주소, 이메일계정, 비밀번호 )

 'redirectUrl':'http://ivps.tistory.com',

 'loginId':'이메일계정',

 'password':'비밀번호'

}

tokenParams = {                                    ### 토큰값을 받아오기 위한 Parameters ( App ID, CallBack, 'token' )

 'client_id':'Open API App ID',

 'redirect_uri':'Open API CallBack',

 'response_type':'token'

}

def params_2(access_token):                        ### 블로그 정보 Parameters

  return {'access_token':access_token, 'output':'json'}

def params_3(access_token, blogName, page, count): ### 블로그 리스트 Parameters

  return {'access_token':access_token, 'output':'xml', 'targetUrl':blogName, 'page':page, 'count':count}

def params_4(access_token, blogName, post_id):     ### 블로그 상세보기 Parameters

  return {'access_token':access_token, 'output':'xml', 'targetUrl':blogName, 'postId':post_id}

IS_IMG_TO_SAVE = 1  ### 이미지 저장

IMG_SRC_TYPE = 1    ### 1:이미지 URL 변경, 2:이미지를 본문 내용에 포함

def image_save_from_html(html):

  html_obj = BeautifulSoup(html, 'html.parser')

  img_data = html_obj.find_all('img')

  print('img count : ' + str(len(img_data)))

  for image in img_data:

    if '//cfile' in image['src']:

      print('img src : ' + image['src'])

      try:

        imgUrl = image['src']

        filename = image['src'].split('/')[-1]

        imgData = urllib2.urlopen(image['src']).read()

        f = open(filename, 'wb')

        f.write(imgData)

        f.close()

        if(IMG_SRC_TYPE == 1):

          imgSrc = image_url_change(filename)

          html = html.replace(imgUrl, imgSrc)

        elif(IMG_SRC_TYPE == 2):

          imgSrc = image_to_rawdata(filename)

          html = html.replace(imgUrl, imgSrc)

        else:

          print('@@@ imgUrl : ' + imgUrl)

      except:

        print('@@@ HTMLparse Error : ' + str(image))

    else:

      print('@@@ Pass img src : ' + image['src'])

  return html

def image_to_rawdata(filename):

  mime_type = magic.from_file(filename, mime=True)

  print('mime_type : ' + mime_type)

  f = open(filename, 'rb')

  image = f.read()

  f.close()

  rawData = base64.b64encode(image).decode('utf-8')

  imgSrc = 'data:'+ mime_type +';base64,' + rawData

  return imgSrc

def image_url_change(filename):

  mime_type = magic.from_file(filename, mime=True)

  print('mime_type : ' + mime_type)

  if '.' not in filename: ### 이미지 파일 확장자가 없으면 추가

    ext = mime_type.split('/')[-1]

    os.rename(filename, filename+'.'+ext)

    filename = filename+'.'+ext

  imgSrc = '/wp-content/uploads/tistory/' + filename

  return imgSrc



rs = requests.session()

try:

  r0 = rs.post(URL_0, data=loginParams)

  try:

    r1 = rs.get(URL_1, params=tokenParams)

    access_token = str( urlparse.parse_qs( r1.url.split('#')[1] )['access_token'][0] )

    print('### access_token : ' + access_token)

    try:

      r2 = rs.get(URL_2, params=params_2(access_token))

      print('### Open API, Blog Info Url : ' + str(r2.url))

      #print(r2.text)

      item = json.loads(r2.text)

      item_size = len(item['tistory']['item']['blogs'])

      ### RSS XML Create

      rss = xml.Element('rss')

      rss.set('version', '2.0')

      x1_ch = xml.SubElement(rss, 'channel')

      for i in range(item_size): ### 0 ~ 5, 없거나 최대 5개의 블로그

        blog_name = item['tistory']['item']['blogs'][i]['name']

        if(blog_name == blogName): # 일치하는 블로그만

          print('### Find blog : ' + str(blog_name))

          ### ==> 필요는 없지만 티스토리 rss 에 나온는 형식에 맞춰줌

          x1_ch_ti = xml.SubElement(x1_ch, 'title').text             = item['tistory']['item']['blogs'][i]['title']

          x1_ch_li = xml.SubElement(x1_ch, 'link').text              = item['tistory']['item']['blogs'][i]['url']

          x1_ch_de = xml.SubElement(x1_ch, 'description').text       = item['tistory']['item']['blogs'][i]['description']

          x1_ch_la = xml.SubElement(x1_ch, 'language').text          = 'ko'

          x1_ch_pu = xml.SubElement(x1_ch, 'pubDate').text           = datetime.now(timezone('Asia/Seoul')).strftime('%a, %d %b %Y %H:%M:%S %z')

          x1_ch_ge = xml.SubElement(x1_ch, 'generator').text         = 'ivps.kr'

          x1_ch_ma = xml.SubElement(x1_ch, 'managingEditor').text    = item['tistory']['item']['blogs'][i]['nickname']

          x1_ch_im = xml.SubElement(x1_ch, 'image')

          x1_ch_im_ti = xml.SubElement(x1_ch_im, 'title').text       = item['tistory']['item']['blogs'][i]['title']

          x1_ch_im_ur = xml.SubElement(x1_ch_im, 'url').text         = item['tistory']['item']['blogs'][i]['profileImageUrl']

          x1_ch_im_li = xml.SubElement(x1_ch_im, 'link').text        = item['tistory']['item']['blogs'][i]['url']

          x1_ch_im_de = xml.SubElement(x1_ch_im, 'description').text = item['tistory']['item']['blogs'][i]['description']

          ### <==

          nickname = item['tistory']['item']['blogs'][i]['nickname']

          totalCnt = item['tistory']['item']['blogs'][i]['statistics']['post']

          print('### post : ' + totalCnt) ### 포스팅 갯수

          pages = int ( math.ceil ( float(totalCnt) / float(count) ) )

          for j in range(pages): ### 총 페이지 만큼 반복

            page = j+1

            print('### Page : ' + str(page) + ' of ' + str(pages) + ' ###')

            try:

              r3 = rs.get(URL_3, params=params_3(access_token, blogName, page, count))

              print('### Open API, Blog List Url : ' + str(r3.url))

              xmlList = xml.fromstring(r3.text.encode(r3.encoding))

              #xml.dump(xmlList)

              for parent in xmlList.getiterator('post'): ### 목록에서 postId 추출

                post_id = int( parent.find('id').text )

                visibility = int( parent.find('visibility').text )

                if(visibility in (2,3)): ### 2:??, 3:발행 게시글

                  try:

                    r4 = rs.get(URL_4, params=params_4(access_token, blogName, post_id))

                    print('### Open API, Blog Desc Url, postId(' + str(post_id) + ') : ' + str(r4.url))

                    xmlDesc = xml.fromstring(r4.text.encode(r4.encoding))

                    #print(xml.dump(xmlDesc))

                    for desc in xmlDesc.getiterator('item'): ### 상세내용 추출

                      if(IS_IMG_TO_SAVE == 1):

                        html = image_save_from_html(desc.find('content').text)

                      else:

                        html = desc.find('content').text

                      x2_it = xml.SubElement(x1_ch, 'item')

                      x3_ti = xml.SubElement(x2_it, 'title').text       = parent.find('title').text

                      x3_li = xml.SubElement(x2_it, 'link').text        = parent.find('postUrl').text

                      x3_de = xml.SubElement(x2_it, 'description').text = html

                      for tag in desc.find('tags').findall('tag'): ### 카테고리 갯수 만큼 반복

                        x3_ca = xml.SubElement(x2_it, 'category').text  = tag.text

                      x3_au = xml.SubElement(x2_it, 'author').text      = nickname

                      x3_gu = xml.SubElement(x2_it, 'guid').text        = parent.find('postUrl').text

                      x3_pu = xml.SubElement(x2_it, 'pubDate').text     = parent.find('date').text

                  except:

                    print('@@@ Error : ' + str(r4.url))

                else:                    ### 0:비공개, 1:보호

                  print('### Pass PostId(' + str(post_id) + ') visibility : ' + str(visibility))

            except:

              print('@@@ Error : ' + str(r3.url))

        else:

          print('### Pass blog : ' + str(blog_name))

    except:

      print('@@@ Error : ' + str(r2.url))

  except:

    print('@@@ Error : ' + str(r1.url))

except:

  print('@@@ Error : ' + str(r0.url))


#xml.dump(rss)

xml.ElementTree(rss).write('/var/www/html/rss.xml') # 적당한 위치에 저장


색깔이 다른 부분만 수정해서 사용하시면 됩니다.


이미지를 본문 내용에 포함하는 경우에 이미지가 많이 들어간 경우는 걸러주는 작업이 필요해 보입니다.


양이 많으니깐 메모리 부족 현상 때문인지 Killed 가 발생하더군요~



티스토리가 요즘 방문통계가 영 이상하네요~


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[티스토리] Python 으로 sitemap.xml 만들기



티스토리 블로그는 RSS 는 제공하지만 사이트맵은 제공하지 않습니다.


그래서 sitemap 만들어주는 사이트에서 만들고 편집해서 등록하였었는데 엄청 귀찮습니다.


파이썬으로 티스토리 블로그의 사이트맵을 생성해주는 프로그래밍을 해서 공개합니다.



▶ Python Create Sitemap 소스코드


# coding=utf-8

import json

import math

import requests

import urlparse

import xml.etree.ElementTree as xml

from datetime import datetime

from pytz import timezone


headers = { ### 헤더 필요시 requests.post(URL, headers=headers)

 'Referer':'https://www.tistory.com/auth/login',

 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'

}

URL_0 = 'https://www.tistory.com/auth/login'       ### 티스토리 로그인 URL

URL_1 = 'https://www.tistory.com/oauth/authorize'  ### 인증 요청 및 Authentication code 발급 URL

URL_2 = 'https://www.tistory.com/apis/blog/info'   ### 블로그 정보 URL

URL_3 = 'https://www.tistory.com/apis/post/list'   ### 블로그 리스트 URL

URL_4 = 'https://www.tistory.com/apis/post/read'   ### 블로그 상세보기 URL

loginParams = {                                    ### 로그인 Parameters ( 블로그주소, 이메일계정, 비밀번호 )

 'redirectUrl':'http://ivps.tistory.com',

 'loginId':'이메일계정',

 'password':'비밀번호'

}

tokenParams = {                                    ### 토큰값을 받아오기 위한 Parameters ( App ID, CallBack, 'token' )

 'client_id':'Open API App ID',

 'redirect_uri':'Open API CallBack',

 'response_type':'token'

}

def params_2(access_token):                        ### 블로그 정보 Parameters

  return {'access_token':access_token, 'output':'json'}

def params_3(access_token, blogName, page, count): ### 블로그 리스트 Parameters

  return {'access_token':access_token, 'output':'xml', 'targetUrl':blogName, 'page':page, 'count':count}

def params_4(access_token, blogName, post_id):     ### 블로그 상세보기 Parameters

  return {'access_token':access_token, 'output':'xml', 'targetUrl':blogName, 'postId':post_id}


blogName = 'ivps' ### 블로그명

page = 0          ### 1 페이지 부터 시작

count = 30        ### 최대값 30

post_id = 0       ### 아래에서 데이터를 추출

access_token = '' ### 아래에서 데이터를 추출


rs = requests.session()

try:

  r0 = rs.post(URL_0, data=loginParams)

  try:

    r1 = rs.get(URL_1, params=tokenParams)

    access_token = str( urlparse.parse_qs( r1.url.split('#')[1] )['access_token'][0] )

    print('### access_token : ' + access_token)

    try:

      r2 = rs.get(URL_2, params=params_2(access_token))

      print('### Open API, Blog Info Url : ' + str(r2.url))

      #print(r2.text)

      item = json.loads(r2.text)

      item_size = len(item['tistory']['item']['blogs'])

      ### SITEMAP XML Create

      sitemap = xml.Element('urlset')

      sitemap.set('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9')

      for i in range(item_size): ### 0 ~ 5, 없거나 최대 5개의 블로그

        blog_name = item['tistory']['item']['blogs'][i]['name']

        if(blog_name == blogName): # 일치하는 블로그만

          print('### Find blog : ' + str(blog_name))

          ### ==> 블로그 주소 부분

          x1_1st = xml.SubElement(sitemap, 'url')

          x2_lo = xml.SubElement(x1_1st, 'loc').text        = item['tistory']['item']['blogs'][i]['url']

          x2_ch = xml.SubElement(x1_1st, 'changefreq').text = 'always'

          x2_pr = xml.SubElement(x1_1st, 'priority').text   = '1.0'

          ### <==

          totalCnt = item['tistory']['item']['blogs'][i]['statistics']['post']

          print('### post : ' + totalCnt) ### 포스팅 갯수

          pages = int ( math.ceil ( float(totalCnt) / float(count) ) )

          for j in range(pages): ### 총 페이지 만큼 반복

            page = j+1

            print('### Page : ' + str(page) + ' of ' + str(pages) + ' ###')

            try:

              r3 = rs.get(URL_3, params=params_3(access_token, blogName, page, count))

              print('### Open API, Blog List Url : ' + str(r3.url))

              xmlList = xml.fromstring(r3.text.encode(r3.encoding))

              #xml.dump(xmlList)

              for parent in xmlList.getiterator('post'): ### 목록에서 postId 추출

                post_id = int( parent.find('id').text )

                visibility = int( parent.find('visibility').text )

                if(visibility in (2,3)): ### 2:??, 3:발행 게시글

                  x2_ur = xml.SubElement(sitemap, 'url')

                  x3_lo = xml.SubElement(x2_ur, 'loc').text        = parent.find('postUrl').text

                  x3_ch = xml.SubElement(x2_ur, 'changefreq').text = 'daily'

                  x1_pr = xml.SubElement(x2_ur, 'priority').text   = '0.9'

                else:                                  ### 0:비공개, 1:보호

                  print('### Pass PostId(' + str(post_id) + ') visibility : ' + str(visibility))

            except:

              print('@@@ Error : ' + str(r3.url))

        else:

          print('### Pass blog : ' + str(blog_name))

    except:

      print('@@@ Error : ' + str(r2.url))

  except:

    print('@@@ Error : ' + str(r1.url))

except:

  print('@@@ Error : ' + str(r0.url))


#xml.dump(sitemap)

xml.ElementTree(sitemap).write('/var/www/html/sitemap.xml', encoding='utf-8', xml_declaration=True) # 적당한 위치에 저장


RSS 만들어주는 코드에서 응용해서 만들었습니다.


색깔이 들어간 부분만 수정하시면 됩니다.


티스토리에서 제공하는 Open API 를 이용한 코드입니다.


오픈API 등록은 https://ivps.tistory.com/645 여기를 참고하세요~


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[티스토리] Python Open API 활용 블로그 RSS 생성 소스



예전엔 티스토리에서 블로그 전체 백업기능이 있었는데 지금은 없어졌습니다.


RSS 기능으로 백업은 가능한데 최대 50개까지만 가능합니다.


그래서 파이썬으로 전체 게시글을 RSS 로 만들어 주는 프로그램을 만들어서 공개합니다.


RSS 만 있으면 워드프레스로 플러그인을 이용하면 블로그 이전이 가능합니다.


물론 이미지 파일은 티스토리가 존재해야 이미지가 보여집니다~


이미지까지 백업하지 않는 이상 완전한 탈출은 힘듭니다.



# yum install python python-pip

# pip install requests pytz


사전에 python 관련해서 미리 설치를 하여야 합니다.



▶ Python 소스코드


# coding=utf-8

import json

import math

import requests

import urlparse

import xml.etree.ElementTree as xml

from datetime import datetime

from pytz import timezone


headers = { ### 헤더 필요시 requests.post(URL, headers=headers)

 'Referer':'https://www.tistory.com/auth/login',

 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'

}

URL_0 = 'https://www.tistory.com/auth/login'       ### 티스토리 로그인 URL

URL_1 = 'https://www.tistory.com/oauth/authorize'  ### 인증 요청 및 Authentication code 발급 URL

URL_2 = 'https://www.tistory.com/apis/blog/info'   ### 블로그 정보 URL

URL_3 = 'https://www.tistory.com/apis/post/list'   ### 블로그 리스트 URL

URL_4 = 'https://www.tistory.com/apis/post/read'   ### 블로그 상세보기 URL

loginParams = {                                    ### 로그인 Parameters ( 블로그주소, 이메일계정, 비밀번호 )

 'redirectUrl':'http://ivps.tistory.com',

 'loginId':'이메일계정',

 'password':'비밀번호'

}

tokenParams = {                                    ### 토큰값을 받아오기 위한 Parameters ( App ID, CallBack, 'token' )

 'client_id':'Open API App ID',

 'redirect_uri':'Open API CallBack',

 'response_type':'token'

}

def params_2(access_token):                        ### 블로그 정보 Parameters

  return {'access_token':access_token, 'output':'json'}

def params_3(access_token, blogName, page, count): ### 블로그 리스트 Parameters

  return {'access_token':access_token, 'output':'xml', 'targetUrl':blogName, 'page':page, 'count':count}

def params_4(access_token, blogName, post_id):     ### 블로그 상세보기 Parameters

  return {'access_token':access_token, 'output':'xml', 'targetUrl':blogName, 'postId':post_id}


blogName = 'ivps' ### 블로그명

page = 0          ### 1 페이지 부터 시작

count = 30        ### 최대값 30

post_id = 0       ### 아래에서 데이터를 추출

access_token = '' ### 아래에서 데이터를 추출


rs = requests.session()

try:

  r0 = rs.post(URL_0, data=loginParams)

  try:

    r1 = rs.get(URL_1, params=tokenParams)

    access_token = str( urlparse.parse_qs( r1.url.split('#')[1] )['access_token'][0] )

    print('### access_token : ' + access_token)

    try:

      r2 = rs.get(URL_2, params=params_2(access_token))

      print('### Open API, Blog Info Url : ' + str(r2.url))

      #print(r2.text)

      item = json.loads(r2.text)

      item_size = len(item['tistory']['item']['blogs'])

      ### RSS XML Create

      rss = xml.Element('rss')

      rss.set('version', '2.0')

      x1_ch = xml.SubElement(rss, 'channel')

      for i in range(item_size): ### 0 ~ 5, 없거나 최대 5개의 블로그

        blog_name = item['tistory']['item']['blogs'][i]['name']

        if(blog_name == blogName): # 일치하는 블로그만

          print('### Find blog : ' + str(blog_name))

          ### ==> 필요는 없지만 티스토리 rss 에 나온는 형식에 맞춰줌

          x1_ch_ti = xml.SubElement(x1_ch, 'title').text             = item['tistory']['item']['blogs'][i]['title']

          x1_ch_li = xml.SubElement(x1_ch, 'link').text              = item['tistory']['item']['blogs'][i]['url']

          x1_ch_de = xml.SubElement(x1_ch, 'description').text       = item['tistory']['item']['blogs'][i]['description']

          x1_ch_la = xml.SubElement(x1_ch, 'language').text          = 'ko'

          x1_ch_pu = xml.SubElement(x1_ch, 'pubDate').text           = datetime.now(timezone('Asia/Seoul')).strftime('%a, %d %b %Y %H:%M:%S %z')

          x1_ch_ge = xml.SubElement(x1_ch, 'generator').text         = 'ivps.kr'

          x1_ch_ma = xml.SubElement(x1_ch, 'managingEditor').text    = item['tistory']['item']['blogs'][i]['nickname']

          x1_ch_im = xml.SubElement(x1_ch, 'image')

          x1_ch_im_ti = xml.SubElement(x1_ch_im, 'title').text       = item['tistory']['item']['blogs'][i]['title']

          x1_ch_im_ur = xml.SubElement(x1_ch_im, 'url').text         = item['tistory']['item']['blogs'][i]['profileImageUrl']

          x1_ch_im_li = xml.SubElement(x1_ch_im, 'link').text        = item['tistory']['item']['blogs'][i]['url']

          x1_ch_im_de = xml.SubElement(x1_ch_im, 'description').text = item['tistory']['item']['blogs'][i]['description']

          ### <==

          nickname = item['tistory']['item']['blogs'][i]['nickname']

          totalCnt = item['tistory']['item']['blogs'][i]['statistics']['post']

          print('### post : ' + totalCnt) ### 포스팅 갯수

          pages = int ( math.ceil ( float(totalCnt) / float(count) ) )

          for j in range(pages): ### 총 페이지 만큼 반복

            page = j+1

            print('### Page : ' + str(page) + ' of ' + str(pages) + ' ###')

            try:

              r3 = rs.get(URL_3, params=params_3(access_token, blogName, page, count))

              print('### Open API, Blog List Url : ' + str(r3.url))

              xmlList = xml.fromstring(r3.text.encode(r3.encoding))

              #xml.dump(xmlList)

              for parent in xmlList.getiterator('post'): ### 목록에서 postId 추출

                post_id = int( parent.find('id').text )

                visibility = int( parent.find('visibility').text )

                if(visibility in (2,3)): ### 2:??, 3:발행 게시글

                try:

                  r4 = rs.get(URL_4, params=params_4(access_token, blogName, post_id))

                  print('### Open API, Blog Desc Url, postId(' + str(post_id) + ') : ' + str(r4.url))

                  xmlDesc = xml.fromstring(r4.text.encode(r4.encoding))

                  #print(xml.dump(xmlDesc))

                  for desc in xmlDesc.getiterator('item'): ### 상세내용 추출

                      x2_it = xml.SubElement(x1_ch, 'item')

                      x3_ti = xml.SubElement(x2_it, 'title').text       = parent.find('title').text

                      x3_li = xml.SubElement(x2_it, 'link').text        = parent.find('postUrl').text

                      x3_de = xml.SubElement(x2_it, 'description').text = desc.find('content').text

                      for tag in desc.find('tags').findall('tag'): ### 카테고리 갯수 만큼 반복

                        x3_ca = xml.SubElement(x2_it, 'category').text  = tag.text

                      x3_au = xml.SubElement(x2_it, 'author').text      = nickname

                      x3_gu = xml.SubElement(x2_it, 'guid').text        = parent.find('postUrl').text

                      x3_pu = xml.SubElement(x2_it, 'pubDate').text     = parent.find('date').text

                except:

                  print('@@@ Error : ' + str(r4.url))

                else:                    ### 0:비공개, 1:보호

                  print('### Pass PostId(' + str(post_id) + ') visibility : ' + str(visibility))

            except:

              print('@@@ Error : ' + str(r3.url))

        else:

          print('### Pass blog : ' + str(blog_name))

    except:

      print('@@@ Error : ' + str(r2.url))

  except:

    print('@@@ Error : ' + str(r1.url))

except:

  print('@@@ Error : ' + str(r0.url))

  

#xml.dump(rss)

xml.ElementTree(rss).write('/var/www/html/rss.xml') # 적당한 위치에 저장


색깔로 표시한 부분만 수정하면 됩니다.


제대로 안되면 중간 중간에 있는 주석 풀어서 디버깅 해보세요~


그리고 너무 빈번한 Open API 호출을 하면 트래픽 부하로 차단이 될 수도 있습니다.


그런 경우엔 해당 url 을 건너 뛰고 진행하시면 됩니다.


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

[티스토리] 오픈 API 로 블로그 목록 백업하기


예전엔 블록그 백업 기능을 지원했었는데 지금은 없어졌네요~ 유일하게 RSS 최대 50개까지 백업이 가능하지만 더 많은 포스팅이라면 Open API 를 이용할 수 밖에 없습니다.

백업하는 방법에 대해서만 언급하고 있으니 보시고 참고해서 프로그래밍은 직접하셔야 합니다.

인터넷에 찾아보시면 파이썬으로 되어 있는게 있더군요~


Open API 등록 : https://www.tistory.com/guide/api/manage/register


앱등록을 하면 앱관리에서 정보를 수정도 가능합니다.

[티스토리] 오픈 API 로 블로그 목록 백업하기

▶ 토큰 값 받기 ( 도움말 : https://tistory.github.io/document-tistory-apis/auth/authorization_code.html )

https://www.tistory.com/oauth/authorize?client_id={App ID}&redirect_uri={CallBack}&response_type=token

도움말을 보면 이해가 쉬울겁니다.

브라우저에서 위 주소를 치면 아래처럼 리다이렉트 되어 access_token 값이 날아옵니다.

모자이크 처리된 부분을 복사해서 아래 기능의 {access token} 값으로 이용하면 됩니다.

받고나서 1시간이 지나면 안된다는 군요~


▶ 블로그 정보 가져오기 ( 도움말 : https://tistory.github.io/document-tistory-apis/apis/v1/blog/list.html )

https://www.tistory.com/apis/blog/info?access_token={access token}&output=xml

output 은 json 또는 xml 둘 중에 하나입니다.


▶ 블로그 목록 가져오기 ( 도움말 : https://tistory.github.io/document-tistory-apis/apis/v1/post/list.html )

https://www.tistory.com/apis/post/list?access_token={access token}&output=xml&count=30&page=1&targetUrl=ivps

위에서 블로그 정보에서 총 게시글 수를 계산해서 page 와 count 프로그래밍 하시면 됩니다.

count 는 최대 30입니다.

targetUrl 은 티스토리 계정으로 총 5개의 블로그를 개설할 수 있는데 그 중에 하나를 입력하면 됩니다.


▶ 블로그 내용 가져오기 ( 도움말 : https://tistory.github.io/document-tistory-apis/apis/v1/post/read.html )

https://www.tistory.com/apis/post/read?access_token={access token}&output=xml&targetUrl=ivps&postId=3


이제 위의 3개의 API 를 조합해서 프로그래밍을 하면 됩니다.

나중에 여유가 되면 Python 으로 한번 만들어 보도록 하겠습니다.



▶ Python 으로 access_token 값 가져오기 : https://ivps.tistory.com/648

▶ Python 블로그 백업용 RSS 파일생성 : https://ivps.tistory.com/650



블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

티스토리 보안서버 SSL 적용


Tistory 가 http 에서 https 로 보안서버가 적용된다고 합니다.

*.tistory.com 블로그 및 2차 도메인까지 모두 적용된다고 하네요~

티스토리 보안서버 SSL 적용

인증서는 티스토리에서 알아서 적용해주는가 봅니다.


준비사항 :

HTML 스킨편집에서 외부 리소스 가져오는 부분에 http 로 되어 있는 부분만 수정해 주면 될 것 같습니다.

미리 바뀔 것에 대비해서 http:// 부분을 // 이렇게 변경해 주면 됩니다.


참고로 https:// 로 변경해도 되지만 // 이렇게 해주면 현재 열린게 http 면 http 로 https 면 https 로 호출을 합니다.


ps : 오늘자로 적용이 완료되었네요~

아래 링크 참고해서 적용시키면 됩니다.

https://notice.tistory.com/2444

개인도메인은 적용이 엄청 오래걸리네요~

5일째 아직 적용준비중으로 나오는군요~ ㅋ




블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

티스토리 Flash Player 허용방법



크롬브라우저와 파이어폭스에서 티스토리에 사진을 올릴려고 하니 플래시 플레이어가 설치되어 있는데도 아래와 같은 내용이 나오는군요~


"Daum 포토업로더는 Flash Player 10에 최적화 되어 있습니다.

최신 버전의 Flash를 설치하신 후 다시 시도해주세요."



티스토리 Flash Player 허용방법


이 팝업이 떠 있는 상태에서 브라우저 상단에 url 을 메모해 두었다가


아래 설정에서 사이트 허용에 추가하여 주면 됩니다.



티스토리 Flash Player 허용방법


크롬 설정에서 개인정보 및 보안으로 이동하여 콘텐츠 설정을 클릭합니다.



티스토리 Flash Player 허용방법


플래시를 클릭해서 위에서 메모한 주소를 허용 목록에 추가하여 주면 됩니다.



이제 다시 사진을 첨부해보세요.


파이어폭스는 https://get.adobe.com/kr/flashplayer/ 여기에서 플래시 플레이어를 설치한 다음에 브라우저를 재시작 하면 됩니다.



블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

티스토리 2차주소 도메인 비정상



오늘 블로그 접근이 안되네요.


cname 으로 host.tistory.io 네임서버 설정까지 잘 되어있는데도 


사이트에 연결할 수 없음

서버 DNS address을(를) 찾을 수 없습니다.

ERR_NAME_NOT_RESOLVED


이런 메시지가 뜨면서 접근이 안되네요. 티스토리에 뭔가 문제가 생긴것 같은데 별다는 공지도 아직까지 없군요~



# nslookup blog.ivps.kr

Server:         8.8.8.8

Address:        8.8.8.8#53


Non-authoritative answer:

blog.ivps.kr    canonical name = host.tistory.io.

Name:   host.tistory.io

Address: 110.45.229.135

Name:   host.tistory.io

Address: 175.126.170.70

Name:   host.tistory.io

Address: 180.70.134.239



빨리 수정이 되었으면 좋겠군요~


======


2016.10.28 10:31    아직 안됨


2016.10.28 13.21    지금 안됨


2016.10.28 15:05    공지가 떴군요~


http://notice.tistory.com/2356

(긴급) .io 장애로 인한 2차 주소 블로그 접속 불안 안내 및 CNAME 레코드 변경 요청드립니다.

새로운 소식/점검 안내 2016.10.28 14:35


cname blog.tistory.com 으로 바꿔도 안됨


2016.10.28 15:28    지금은 정상


블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,

티스토리 1차주소 변경후 검색색인 데미지



현재 블로그는 아니지만 예전에 운영하던 블로그의 네이버 웹마스터도구의 검색색인현황 그래프다.


네이버 검색엔진 버그이자 단점 같다.


예전 1차 주소랑 웹마스터도구에 사이트등록시 사이트소유확인에 사용된 메타 태그만 봐도 대번에 알겠구만 삐리한 네이버봇 같으니~


네이버 웹마스터도구 검색 노출 가능 문서 수네이버 웹마스터도구 검색 노출 가능 문서 수


위 그래프를 보면 7일과 8일 사이에 검색 노출 가능 문서 수 차이가 45이다.


그런데 이게 하루가 지나면 8일의 수가 7일과 똑같이 45 만큼 줄어서 나온다.


아무래도 이게 유사문서로 판단된게 아닐까 조심스레 추측해 본다.


저품질 블로그로 된 것 같기도 하고 아닌거 같기도 하고 아무튼 찜찜하다.



하루 뒤에 다시 확인해 보면 8일날 캡쳐 이미지에 보면 8일날 수치가 160근처인데 오늘은 120 이하로 돌아가 있다.


이게 쭈욱 계속 그렇다는 거다. 네이버봇이 영 삐리함을 알 수 있다.



이번엔 쭈욱 가던 수치가 바뀌어서 쭈욱 가고 있다. 도무지 감잡을수가 없다.



신규 개설 블로그 색인현황 봐줄만한 그래프 4/8

네이버웹마스터도구 색인현황네이버웹마스터도구 색인현황


신규 개설 블로그 색인현황 봐줄만한 그래프 4/9


이 그래프는 신규로 개설한 블로그의 그래프인데 7일날 수치가 변화하긴 했지만 8일날 수치는 정상적이다.


신규 개설 블로그 색인현황 비정상적 그래프 4/11


신규 개설 블로그도 상황이 같아졌다. 3에서 쭈욱가고 있는 그래프~


2016.04.25 내용 추가

계속해서 관찰했지만 위의 그래프는 안 믿는게 좋을 것 같다. 오늘 날짜의 수치만 참고 하고 과거의 수치는 안 보는게 맞는 듯 하다.

네이버 웹마스터도구가 베타버전이라고 명시되어있다. 아직까지 믿을게 못되는 네이버웹마스터도구인가 보다.



여담으로


구글은 site:blog.ivps.kr 로 검색하면 색인된 페이지를 알 수가 있는데


네이버는 한번에 검색해서 어느 포스팅 글이 색인이 되었는지 알 수 있는 방법이 없다.


구글의 장점이자 네이버의 단점이기도 하다


네이버는 site:홈페이지주소 이렇게 검색하면 달랑 사이트 하나만 나온다.


빙(BING)이나 구글 처럼 검색이 되면 좋은데 말이다.





블로그 이미지

영은파더♥

가상서버호스팅 VPS 리눅스 서버관리 윈도우 IT

,