IT 이야기/Python

[Python] 티스토리 블로그, 구글 검색 반영(색인) 자동화 시스템을 개발해보자 2

출가외인 2024. 6. 26. 14:06
반응형

 

 

 

목차

 

 

 

 

들어가며

 

프로젝트 이름 : Index_Google
사용 프로그램 : 파이썬 Python
코딩 방법 : ChatGPT
최종 프로그램 돌릴 하드웨어 : 시놀로지 도커 Synology Docker

 

지난 글에서는 구글 인덱싱 프로그램의 가장 핵심 부분을 작성했다.

 

1. 티스토리 발행글 URL 수집

2. 수집된 URL로 인덱싱

 

실제 구동을 해본 결과 수집 -> 인덱싱 과정이 매끄럽다.

첫 실행 이후부터는 인덱싱을 진행한 URL은 패스하고, 새롭게 수집된 URL만 인덱싱 한다.

 

 

 

파이썬 코드 작성

아래는 실제 구동이 가능한 코드 전문

이 코드는 Python3와 필요한 모듈이 설치되어 있다면 윈도우, 맥os, 리눅스 등에서 모두 실행 가능한 것으로 확인된다.

 

 

import time
import json
import re
import random
import pandas as pd
import requests
from time import sleep
from datetime import datetime, timedelta
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
import os

# ANSI color code definitions
C_END = "\033[0m"
C_BOLD = "\033[1m"
C_YELLOW = "\033[33m"
C_BGBLACK = "\033[40m"

# Read settings from JSON file
with open('blogs.json', 'r', encoding='utf-8') as f:
    config = json.load(f)

tistory_address_lists = config['tistory_address_lists']
google_api_json_key_dictionary = config['google_api_json_key_dictionary']
available_indexing_list_num = 200
csv_submit_urls_path = "./"
PAUSE_TIME = 1
INDEXING_WAIT_TIME = 5

user_agents = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15'
]
user_agent = random.choice(user_agents)

def get_tistory_post_lists_indexing_google():
    for tistory_blog_address in tistory_address_lists:
        modified_address = tistory_blog_address.replace('https://', '').replace('http://', '').replace('.', '_')
        csv_save_path = f'{csv_submit_urls_path}google_{modified_address}_submit_urls.csv'
        submit_urls = []
        tistory_sitemap_address = f'{tistory_blog_address}/sitemap.xml'

        res = requests.get(tistory_sitemap_address, headers={'User-Agent': user_agent})
        pattern = f'(?<={tistory_blog_address}/)[^\\s]*(?=</loc>)'
        url_info_lists = re.findall(pattern, res.text)

        for url_info in url_info_lists:
            if url_info.isdigit() or url_info.find('entry/') == 0:
                url = f'{tistory_blog_address}/{url_info}'
                submit_urls.append({'url': url, 'indexed': 'X'})

        df = pd.DataFrame(submit_urls)
        df.drop_duplicates(subset=['url'], keep='first', inplace=True)

        if not os.path.exists(csv_save_path):
            df.to_csv(csv_save_path, mode='w', encoding='utf-8-sig', index=False)
        else:
            df.to_csv(csv_save_path, mode='a', encoding='utf-8-sig', index=False, header=False)
            df = pd.read_csv(csv_save_path).drop_duplicates(subset=['url'], keep='first')
            df.to_csv(csv_save_path, index=False, encoding='utf-8-sig')

        print(f'{C_BOLD}{C_YELLOW}{C_BGBLACK}{csv_save_path} saved {len(submit_urls)} URLs{C_END}')
        indexing_google(tistory_blog_address, csv_save_path)

def indexing_google(blog_address, csv_save_path):
    print(f"\nindexing_google() >> Index target address: {blog_address}, JSON file: {google_api_json_key_dictionary[blog_address]}")

    df = pd.read_csv(csv_save_path)
    if len(df) == 0:
        print(f'\nNo URLs to index. The file ({csv_save_path}) must contain URLs.')
        return

    count = 0
    for index_count in range(len(df)):
        if df["indexed"].values[index_count] == 'O':
            print(f'[SKIP] The URL ({df["url"].values[index_count]}) has already been indexed.')
            continue

        if available_indexing_list_num == count:
            print(f"\nThe desired number of indexes ({available_indexing_list_num}) has been reached.")
            df.to_csv(csv_save_path, mode='w', encoding='utf-8-sig', index=False)
            break

        url = df["url"].values[index_count]
        json_key_file = google_api_json_key_dictionary[blog_address]
        scopes = ["https://www.googleapis.com/auth/indexing"]
        endpoint = "https://indexing.googleapis.com/v3/urlNotifications:publish"

        credentials = ServiceAccountCredentials.from_json_keyfile_name(json_key_file, scopes=scopes)
        http = credentials.authorize(httplib2.Http())

        content = {'url': url, 'type': "URL_UPDATED"}
        response, content = http.request(endpoint, method="POST", body=json.dumps(content))
        result = json.loads(content.decode())

        if response['status'] == '200':
            print(f'>> NOTICE: Indexing request successful!!')
            df.at[index_count, 'indexed'] = 'O'
            count += 1
        elif response["status"] == '429':
            print(f'{C_BOLD}{C_YELLOW}{C_BGBLACK}>> NOTICE: GOOGLE maximum indexing limit (200) reached. Loop terminated.{C_END}')
            return -1
        else:
            print(f'{C_BOLD}{C_YELLOW}{C_BGBLACK}NOTICE: Indexing request failed!! [{response["status"]}] {C_END}')
            df.at[index_count, 'indexed'] = 'X'
            count += 1

        if count != available_indexing_list_num:
            sleep(INDEXING_WAIT_TIME)

    df.to_csv(csv_save_path, mode='w', encoding='utf-8-sig', index=False)

def main():
    start_time = time.time()
    print("START TIME : ", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
    print("\nSTART...")

    get_tistory_post_lists_indexing_google()

    end_time = time.time()
    print("Execution time (h:m:s)", str(timedelta(seconds=end_time - start_time)).split(".")[0])
    print("END TIME : ", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
    print("\nEND...")

if __name__ == '__main__':
    main()

 

 

main.py
0.01MB

 

 

 

필요한 것들

 

1. Python3 설치

Python3 는 구동 환경에 알맞게 설치하면 된다.

 

 

2. 필요한 모듈 설치

프로그램을 실행시키는데 필요한 모듈은 아래 명령어로 설치가 가능하다.

 

# Python 패키지 설치
pip install pandas requests oauth2client httplib2 tqdm

 

 

3. 블로그 주소 작성

'blogs.json' 이라는 이름의 파일에 별도 작성을 하면 된다.

블로그 주소가 여러개인 경우에도 사용 가능

 

{
  "tistory_address_lists": [
    "https://story-way.tistory.com"
  ],
  "google_api_json_key_dictionary": {
    "https://story-way.tistory.com": "A.json"
  }
}

 

 

4. 구글 api 가져오기

구글 api를 가져오려면 조금 어려울 수 있는데, 이 부분은 별도의 글로 다시 설명을 하려고 한다.

(아직 미작성)

 

 

 

실제 구동 모습

내가 프로그램을 구동한 환경은 시놀로지 Synology 의 Docker 기능으로 구축한 Ubuntu 서버다.

모니터링 및 컨트롤은 외부에서 맥을 사용하고 있다.

 

START TIME :  2024-06-26 13:00:02

START...
./google_story-way_tistory_com_submit_urls.csv saved 48 URLs

indexing_google() >> Index target address: https://story-way.tistory.com, JSON file: A.json
[SKIP] The URL (https://story-way.tistory.com/59) has already been indexed.
[SKIP] The URL (https://story-way.tistory.com/58) has already been indexed.

(생략)

Execution time (h:m:s) 0:00:00
END TIME :  2024-06-26 13:00:02

 

 

리눅스 Ubuntu 서버에서 Cron 이라는 기능으로 특정 시간마다 반복하게 해둔 상태이고, 반복할 때마다 생기는 로그의 일부를 가져왔다.

 

아주 잘 작동되고 있음을 확인할 수 있다.

[끝]

 

 

PS. 만약 구글 인덱싱을 자동으로 하고 싶은 사람이 있다면 블로그 당 월 1만원의 비용을 받고 대신 운영해볼까 고민중...

 

 

[Python] 티스토리 블로그, 구글 검색 반영(색인) 자동화 시스템을 개발해보자 1

 

집나가면 개고생

최신 IT 기기와 소프트웨어 리뷰, 카메라 장비 분석, 내돈내산 솔직 리뷰, 그리고 다양한 맛집 탐방기를 제공하는 블로그입니다. 전문가의 시선으로 상세하고 객관적인 정보를 전달합니다.

story-way.tistory.com

 

반응형