본문 바로가기

개발 기록/자동 포스팅 프로그램

chat gpt를 이용한 코드 작성 도움 및 경과

위 사진은 저번 글에서 포스팅 된 내용이다.

 

이를 해결하기 위해서 여러가지 방법을 알아봤다. 그를 해결하기 위해 대략적인 구조는 구해냈지만 구현하는 작업이 어려울 것 같아 chatGPT의 도움을 받아보기로 했다.

 

chatGPT에게는 내가 작성한 코드와 달성하고자 하는 목표들을 입력했다.

 

그러자 이러한 코드를 받을 수 있었다.

import requests
import markdown2

def convert_markdown_to_tistory_format(markdown_content):
    # Markdown을 HTML로 변환
    html_content = markdown2.markdown(markdown_content)

    # HTML에서 필요한 부분만 추출하여 줄 변경
    tistory_formatted_content = html_content.replace("<h1>", "").replace("</h1>", "\n\n")

    return tistory_formatted_content

def post_to_tistory(title, content, access_token, blog_name, category_id=None):
    # 티스토리 API 엔드포인트
    api_url = f'https://www.tistory.com/apis/post/write'

    # 포스팅할 데이터
    data = {
        'access_token': access_token,
        'output': 'json',
        'blogName': blog_name,
        'title': title,
        'content': content,
        'visibility': 0,  # 0: 보통, 1: 비공개, 2: 보호
    }

    if category_id:
        data['category'] = category_id

    # 티스토리 API 호출
    response = requests.post(api_url, data=data)

    # 결과 출력
    print(response.json())

if __name__ == '__main__':
    # 포스팅할 Markdown 파일 읽기
    with open('your_markdown_file.md', 'r', encoding='utf-8') as file:
        markdown_content = file.read()

    # Markdown을 티스토리 형식으로 변환
    tistory_formatted_content = convert_markdown_to_tistory_format(markdown_content)

    # 티스토리 API 키 및 블로그 정보 설정
    access_token = 'YOUR_ACCESS_TOKEN'
    blog_name = 'YOUR_BLOG_NAME'
    category_id = 'YOUR_CATEGORY_ID'  # Optional, if you want to specify a category

    # 포스팅 함수 호출
    post_to_tistory('Your Post Title', tistory_formatted_content, access_token, blog_name, category_id)

 

맨 아래는 필요한 정보를 입력하는 구조이므로 넘어가겠다.

 

위의 구조를 살펴보자면 .md 파일을 입력받아 <h1> 이라는 태그를 이용하여 받아가고 있다.

 

.md 파일은 마크다운 파일로 원래 웹 페이지에도 응용되어 혼란이 일어난 것 같았다.

 

따라서는 나는 줄 변경을 위해 #을 이용하여 분류를 하려 하였지만 프로그램은 태그를 찾는 것을 반복하여 원하는 결과를 얻을 수 없었다.

 

몇 번의 문답을 통해서 얻어낸 코드는 다음과 같았다.

import requests
import markdown2
from bs4 import BeautifulSoup

def parse_markdown(markdown_content):
    soup = BeautifulSoup(markdown_content, 'html.parser')
    
    title_tag = soup.h1
    title = title_tag.text.strip() if title_tag else "Untitled"  # 타이틀이 없으면 "Untitled"으로 처리

    problem_link_tag = soup.select_one('a[href^="https://www.acmicpc.net/problem/"]')
    problem_link = problem_link_tag['href'] if problem_link_tag else "No problem link found"  # 문제 링크가 없으면 "No problem link found"으로 처리

    performance_summary_tag = soup.select_one('.ke-size16')
    performance_summary = performance_summary_tag.text.strip() if performance_summary_tag else "No performance summary found"  # 성능 요약이 없으면 "No performance summary found"으로 처리

    category_tag = soup.select_one('h3:contains("분류")')
    category = category_tag.find_next_sibling().text.strip() if category_tag and category_tag.find_next_sibling() else "No category found"  # 분류가 없으면 "No category found"으로 처리

    submission_date_tag = soup.select_one('h3:contains("제출 일자")')
    submission_date = submission_date_tag.find_next_sibling().text.strip() if submission_date_tag and submission_date_tag.find_next_sibling() else "No submission date found"  # 제출 일자가 없으면 "No submission date found"으로 처리

    problem_description_tag = soup.select_one('h3:contains("문제")')
    problem_description = problem_description_tag.find_next_sibling().text.strip() if problem_description_tag and problem_description_tag.find_next_sibling() else "No problem description found"  # 문제가 없으면 "No problem description found"으로 처리

    input_description_tag = soup.select_one('h3:contains("입력")')
    input_description = input_description_tag.find_next_sibling().text.strip() if input_description_tag and input_description_tag.find_next_sibling() else "No input description found"  # 입력이 없으면 "No input description found"으로 처리

    output_description_tag = soup.select_one('h3:contains("출력")')
    output_description = output_description_tag.find_next_sibling().text.strip() if output_description_tag and output_description_tag.find_next_sibling() else "No output description found"  # 출력이 없으면 "No output description found"으로 처리

    algorithm_classification_tag = soup.select_one('h3:contains("알고리즘 분류")')
    algorithm_classification = algorithm_classification_tag.find_next_sibling().text.strip() if algorithm_classification_tag and algorithm_classification_tag.find_next_sibling() else "No algorithm classification found"  # 알고리즘이 없으면 "No algorithm classification found"으로 처리

    problem_solution_tag = soup.select_one('h3:contains("문제 풀이")')
    problem_solution = problem_solution_tag.find_next_sibling().text.strip() if problem_solution_tag and problem_solution_tag.find_next_sibling() else "No problem solution found"  # 문제 풀이가 없으면 "No problem solution found"으로 처리

    return {
        'title': title,
        'problem_link': problem_link,
        'performance_summary': performance_summary,
        'category': category,
        'submission_date': submission_date,
        'problem_description': problem_description,
        'input_description': input_description,
        'output_description': output_description,
        'algorithm_classification': algorithm_classification,
        'problem_solution': problem_solution,
    }

# 나머지 코드는 이전과 동일합니다.

 

위 코드의 결과는 이러했다.

 

# [Untitled](No problem link found) ### 성능 요약 No performance summary found ### 분류 No category found ### 제출 일자 No submission date found ### 문제 설명 No problem description found ### 입력 No input description found ### 출력 No output description found ### 알고리즘 분류 No algorithm classification found ### 문제 풀이 No problem solution found

 

문제가 지속적으로 해결되지 않아 나는 문제점을 먼저 하나 씩 짚어보기록 했다.

 

먼저 No ~~ found 부분이다.

 

이는 특정한 인자를 찾지 못했을 때 이를 해결하기 위한 예외처리를 위한 값이다.

 

h3:contains("(항목이름)")

 

이에 주목하여 찾다보니 이러한 부분을 위 코드에서 발견할 수 있었다.

 

이 코드를 찾아보는 h3 태그를 단 것 중에서 해당 항목을 발견한 것이다.

 

하지만 내 repository에 커밋된 .md 파일에는 그러한 형식이 없었다.

 

더보기

README.md

 

# [Silver I] 곱셈 - 1629 

[문제 링크](https://www.acmicpc.net/problem/1629) 

### 성능 요약

메모리: 2020 KB, 시간: 0 ms

### 분류

분할 정복을 이용한 거듭제곱, 수학

### 제출 일자

2023년 12월 13일 16:45:53

### 문제 설명

<p>자연수 A를 B번 곱한 수를 알고 싶다. 단 구하려는 수가 매우 커질 수 있으므로 이를 C로 나눈 나머지를 구하는 프로그램을 작성하시오.</p>

### 입력 

 <p>첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 모두 2,147,483,647 이하의 자연수이다.</p>

### 출력 

 <p>첫째 줄에 A를 B번 곱한 수를 C로 나눈 나머지를 출력한다.</p>

이러한 형식으로 되어있다. 그러니 h 관련 태그를 찾더라도 정보를 가공할 수 없었던 것이다.

 

 

따라서, 태그 인식이 아닌 한 줄 씩 인식하여 정보를 만들도록 하였다.

 

아래는 그 함수의 코드이다.

def parse_markdown(markdown_content):
    # 제목은 첫 번째 줄에서 추출
    title = markdown_content.split('\n')[0].lstrip("# ")

    # 문제 링크는 "[문제 링크]"가 나오는 첫 번째 문장에서 추출
    problem_link_start = markdown_content.find("[문제 링크]")
    if problem_link_start != -1:
        problem_link_start += len("[문제 링크]")
        problem_link_end = markdown_content.find("\n", problem_link_start)
        link_with_brackets = markdown_content[problem_link_start:problem_link_end].strip()
        problem_link = re.sub(r'[()]', '', link_with_brackets)
    else:
        problem_link = "No problem link found"

    # 각 카테고리에 대한 정보를 추출하고 딕셔너리에 저장
    parsed_data = {'title': title, 'problem_link': problem_link}
    current_category = None
    current_content = ""  # 변수 초기화 위치 수정
    
    for line in markdown_content.split('\n'):
        if line.startswith("### "):
            # 이전 카테고리의 내용을 딕셔너리에 저장
            if current_category:
                parsed_data[current_category] = current_content
            # 새로운 카테고리의 이름을 설정
            current_category = line[4:]
            # 새로운 카테고리의 내용 초기화
            current_content = ""
        else:
            # 현재 카테고리의 내용에 줄 추가
            current_content += line

    # 마지막 카테고리의 내용을 딕셔너리에 저장
    if current_category:
        parsed_data[current_category] = current_content

    return parsed_data

 

'\n'을 기준으로 구분하여 문장을 한 줄 씩 받는다. 그리고 이를 # 이 나올 때까지 dicionary의 value 값에 넣다가 다음 나오게 되면 다음 키 값으로 넘어간다. 즉, 저장된 파일의 #뒤에 나오는 것이 항목이 되고 그 아래 쓰여 있는 값들이 해당 항목의 하위 항목으로 들어가게 되는 것이다.

 

 

문제는 하나 더 있었다.

 

바로 줄 바꿈 문제였다.  티스토리는 웹 페이지므로 당연히 <p> 태그와 같은 줄 바꿈 태그를 이용해주어야 한다.

 

하지만 chatGPT는 이러한 부분을 간과하고 줄바꿈을 나타내는 '\n'을 그대로 사용하였다. 이에 이를 바꿔주는 작업을 거친 다음 편의성을 위해 몇 가지 구조를 추가하였다.

 

그 중 하나는 위에서 얻어낸 링크를 통해 anker 태그를 주소 텍스트에 붙여준 것이다.

def convert_markdown_to_tistory_format(parsed_data):
    tistory_formatted_content = (
        f'<strong>[문제 링크] : <a href="{parsed_data["problem_link"]}" target="_blank" rel="noopener"> {parsed_data["problem_link"]} </a></strong>'
    )
    
    #공백 한 줄 추가
    tistory_formatted_content += f'<p></p>'

    for category, content in parsed_data.items():
        if category not in ["title", "problem_link"]:
            tistory_formatted_content += f'<p><strong>### {category}</strong></p>\n<p>{content}</p>\n\n'

    return tistory_formatted_content

 

위 코드는 수정한 내용이다.

 

위 사진은 이렇게 수정한 코드로 만든 결과다.

 

제목은 별도로 지정해 준 것이 아니라 파일에서 자동으로 추출한 것이다.

 

이제 각 항목을 Bold 체로 바꿔주는 가시적인 기능을 추가하고 최하단에는 내가 제출한 답을 포스팅 하는 것을 목표로 하겠다.

'개발 기록 > 자동 포스팅 프로그램' 카테고리의 다른 글

몇 가지 기능 갱신  (0) 2023.12.22
최신 커밋 호출 성공  (0) 2023.12.20
posting content 파트 완성!!  (1) 2023.12.18
md 파일 포스팅 현황  (0) 2023.12.13
자동 포스팅 프로그램  (4) 2023.12.12