개발자's Life

청약 API 이용하여 워드프레스 자동화 게시글 업로드(코드 공유) 본문

사이드 프로젝트

청약 API 이용하여 워드프레스 자동화 게시글 업로드(코드 공유)

Rowen Jobs 2025. 11. 16. 18:50
728x90
반응형

안녕하세요 로웬입니다!
우선 말씀드리자면 정말 사용했던 코드를 공유드리는거고 조금 더 세분화하고 세련된 코드 작성이 안된 코드인 부분은 너그러이 넘어가주심 감사하겠슴다.

한 1년전쯔음 청약 내용을 가지고 오는 API 와 워드프레스 게시글 업로드 하는 API 를 활용하였고 파이썬 코드를 작성하였습니다.

작성 후 제 개인 서버에 코드 올린 후 crontab 으로 주기적으로 게시글을 올리는 작업을 하였지만 조회수가 얼마 나오지 않아 멈췄었습니다.

(나름 구글 SEO 노출되는 조건을 최대한 맞추려 했는데 안됬던..)

 

구조는 아래와 같습니다!

LAND_MARKET

  • auto_posting_for_land_market.py (실제 실행되는 파이썬)
  • home_apply_api_func.py (청약 홈 API)
  • hug_api_func.py (HUG API)
  • rank-math.php (워드프레스에서 포커스 키워드를 자동으로 잡게 하기 위한 php 코드)
  • slack_alert.py (슬랙 API 를 이용하여 게시글 등록 후 메세지 전달)
  • wordpress_article_func.py (청약홈, HUG 순서대로 API 호출하여 게시글 작성)

*DB 나 공통 함수로 사용할 수 있는건 환경설정 파일이나 따로 파이썬 파일을 두고 사용하시는걸 추천드립니다*

 

home_apply_api_func.py

import requests
import time
import math
import pymysql
from bs4 import BeautifulSoup
from wordpress_article_func import create_article_to_wordpress
from hug_api_func import double_meter_price_each_area_table_html, double_meter_price_each_size_html, new_distribution_cnt_html
from datetime import date, timedelta

# 기본 header
HEADER = {
    "Accept": "*/*",
    'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36" 
}

# 청약홈/공공데이터 분양정보 KEY
APPLY_HOME_KEY = "YOUR_API_KEY"

# 청약홈 API 기본 URL
APPLY_HOME_BASE_URL = "https://api.odcloud.kr/api"

# 1개월 이전 날짜
last_date = date.today() - timedelta(days=10)

# APT 무순위/잔여세대 분양정보 API 함수
def apt_no_rank_api():

    # 주택관리번호, 공고번호, 주택구분코드, 모집공고일 값을 이용하여 APT 무순위/잔여세대 분양정보의 상세 정보를 제공
    API_URL = "/ApplyhomeInfoDetailSvc/v1/getRemndrLttotPblancDetail"

    # 호출 URL
    REQUEST_URL = APPLY_HOME_BASE_URL + API_URL

    RESPONSE_INFO = {
      "BSNS_MBY_NM": "사업주체명(시행사)",
      "CNTRCT_CNCLS_BGNDE": "계약 시작일",
      "CNTRCT_CNCLS_ENDDE": "계약 종료일",
      "GNRL_RCEPT_BGNDE": "일반공급접수 시작일",
      "GNRL_RCEPT_ENDDE": "일반공급접수 종료일",
      "HMPG_ADRES": "홈페이지주소",
      "HOUSE_MANAGE_NO": "주택관리번호",
      "HOUSE_NM": "주택명",
      "HOUSE_SECD": "주택구분코드",
      "HOUSE_SECD_NM": "주택구분코드명",
      "HSSPLY_ADRES": "주소",
      "HSSPLY_ZIP": "우편번호",
      "MDHS_TELNO": "문의처",
      "MVN_PREARNGE_YM": "입주예정월",
      "PBLANC_NO": "공고번호",
      "PBLANC_URL": "공고문 바로가기",
      "PRZWNER_PRESNATN_DE": "당첨자 발표일",
      "RCRIT_PBLANC_DE": "모집공고일",
      "SPSPLY_RCEPT_BGNDE": "특별공급 접수 시작일",
      "SPSPLY_RCEPT_ENDDE": "특별공급 접수 종료일",
      "SUBSCRPT_RCEPT_BGNDE": "청약접수 시작일",
      "SUBSCRPT_RCEPT_ENDDE": "청약접수 종료일",
      "TOT_SUPLY_HSHLDCO": "모집 세대수"
    }

    # Page 정보 설정
    PAGE = 1
    PER_PAGE = 50

    # 오늘 날짜 기준 1달전 모집공고 정보 API URL 
    FULL_URL = f"{REQUEST_URL}?page={PAGE}&perPage={PER_PAGE}&serviceKey={APPLY_HOME_KEY}&cond%5BRCRIT_PBLANC_DE%3A%3AGTE%5D={last_date}"

    article_summary_html = ""
    article_list = []

    # 총 게시글 개수를 위해 API 콜 
    response = requests.get(url=FULL_URL, headers=HEADER)
    if response.status_code == 200:
        
        # 공고 총 개수
        match_cnt = response.json()["matchCount"]
        
        # 공고 있을 경우 
        if match_cnt > 0:
            #마지막 페이지 넘버
            LAST_PAGE = math.ceil(match_cnt / PER_PAGE)

            # 페이지 별 게시글 FOR 문 실행 
            for i in range(1, LAST_PAGE + 1):
                FULL_URL = f"{REQUEST_URL}?page={i}&perPage={PER_PAGE}&serviceKey={APPLY_HOME_KEY}&cond%5BRCRIT_PBLANC_DE%3A%3AGTE%5D={last_date}"
                response = requests.get(url=FULL_URL, headers=HEADER)

                # return 값
                apt_json = {
                    "status" : ""
                }

                if response.status_code == 200:
                    apt_json["status"] = "SUCCESS"
                    apt_json["data"] = response.json()

                for data in apt_json["data"]["data"]:
                    # 공고번호가 이미 게시한 글인지 확인
                    # 이미 사용한 키워드 정보 가져오기
                    conn = pymysql.connect(host='YOUR_DB_HOST', user='YOUR_DB_USER', password='YOUR_DB_PASSWORD', db='WORDPRESS', charset='utf8')
                    sql_select = "SELECT COUNT(*) FROM WORDPRESS.AH_ARTICLE_LIST WHERE pblanc_no = %s"
                    with conn:
                        with conn.cursor() as cur:
                            cur.execute(sql_select, data["PBLANC_NO"])
                            article_cnt = cur.fetchall()[0][0]

                    # 등록된 게시글이 없을경우 게시글 셋팅
                    if article_cnt == 0:
                        article_info = {
                            RESPONSE_INFO["BSNS_MBY_NM"]: data["BSNS_MBY_NM"],
                            RESPONSE_INFO["CNTRCT_CNCLS_BGNDE"]: data["CNTRCT_CNCLS_BGNDE"],
                            RESPONSE_INFO["CNTRCT_CNCLS_ENDDE"]: data["CNTRCT_CNCLS_ENDDE"],
                            RESPONSE_INFO["GNRL_RCEPT_BGNDE"]: data["GNRL_RCEPT_BGNDE"],
                            RESPONSE_INFO["GNRL_RCEPT_ENDDE"]: data["GNRL_RCEPT_ENDDE"],
                            RESPONSE_INFO["HMPG_ADRES"]: data["HMPG_ADRES"],
                            RESPONSE_INFO["HOUSE_MANAGE_NO"]: data["HOUSE_MANAGE_NO"],
                            RESPONSE_INFO["HOUSE_NM"]: data["HOUSE_NM"],
                            RESPONSE_INFO["HOUSE_SECD"]: data["HOUSE_SECD"],
                            RESPONSE_INFO["HOUSE_SECD_NM"]: data["HOUSE_SECD_NM"],
                            RESPONSE_INFO["HSSPLY_ADRES"]: data["HSSPLY_ADRES"],
                            RESPONSE_INFO["HSSPLY_ZIP"]: data["HSSPLY_ZIP"],
                            RESPONSE_INFO["MDHS_TELNO"]: data["MDHS_TELNO"],
                            RESPONSE_INFO["MVN_PREARNGE_YM"]: data["MVN_PREARNGE_YM"],
                            RESPONSE_INFO["PBLANC_NO"]: data["PBLANC_NO"],
                            RESPONSE_INFO["PBLANC_URL"]: data["PBLANC_URL"],
                            RESPONSE_INFO["PRZWNER_PRESNATN_DE"]: data["PRZWNER_PRESNATN_DE"],
                            RESPONSE_INFO["RCRIT_PBLANC_DE"]: data["RCRIT_PBLANC_DE"],
                            RESPONSE_INFO["SPSPLY_RCEPT_BGNDE"]: data["SPSPLY_RCEPT_BGNDE"],
                            RESPONSE_INFO["SPSPLY_RCEPT_ENDDE"]: data["SPSPLY_RCEPT_ENDDE"],
                            RESPONSE_INFO["SUBSCRPT_RCEPT_BGNDE"]: data["SUBSCRPT_RCEPT_BGNDE"],
                            RESPONSE_INFO["SUBSCRPT_RCEPT_ENDDE"]: data["SUBSCRPT_RCEPT_ENDDE"],
                            RESPONSE_INFO["TOT_SUPLY_HSHLDCO"]: data["TOT_SUPLY_HSHLDCO"]
                        }
                        article_list.append(article_info)
                        
                    if len(article_list) == 1:
                        break
                time.sleep(1)

    # 게시글 HTML 형태로 작성
    article_summary_html = ""

    # 게시글 작성
    for article in article_list:
        public_url_response = requests.get(url=article["공고문 바로가기"], headers=HEADER)
        home_apply_public_html = BeautifulSoup(public_url_response.content, 'html.parser')
        html = first_comment_html(article)
        html += str(home_apply_public_html.select_one("#printArea"))
        sub_html = sub_info_html_list(article["주소"], article["주소"])
        html += sub_html
        result = create_article_to_wordpress(article["주택명"] + " 분양정보", html)

        if result == "SUCESS":
            conn = pymysql.connect(host='YOUR_DB_HOST', user='YOUR_DB_USER', password='YOUR_DB_PASSWORD', db='WORDPRESS', charset='utf8')
            sql = "INSERT INTO WORDPRESS.AH_ARTICLE_LIST (article_title, pblanc_no, article_type) VALUES (%s, %s, %s)"
            with conn:
                with conn.cursor() as cur:
                    cur.execute(sql, (article["주택명"], article["공고번호"], "100-001"))
                    conn.commit()
    
    sql_update = "UPDATE WORDPRESS.COM_CODE SET common_name = 'apt_detail_api' WHERE common_code = %s"
    conn = pymysql.connect(host='YOUR_DB_HOST', user='YOUR_DB_USER', password='YOUR_DB_PASSWORD', db='WORDPRESS', charset='utf8')
    with conn:
        with conn.cursor() as cur:
            cur.execute(sql_update, "101-001")
            conn.commit()

    return article_summary_html

def apt_detail_api():
    # 주택관리번호, 공고번호, 주택구분코드, 모집공고일 값을 이용하여 APT 무순위/잔여세대 분양정보의 상세 정보를 제공
    API_URL = "/ApplyhomeInfoDetailSvc/v1/getAPTLttotPblancDetail"

    # 호출 URL
    REQUEST_URL = APPLY_HOME_BASE_URL + API_URL

    RESPONSE_INFO = {
        "HOUSE_MANAGE_NO": "주택관리번호",
        "PBLANC_NO": "공고번호",
        "HOUSE_NM": "주택명",
        "HOUSE_SECD": "주택구분코드",
        "HOUSE_SECD_NM": "주택구분코드명",
        "HOUSE_DTL_SECD": "주택상세구분코드",
        "HOUSE_DTL_SECD_NM": "주택상세구분코드명",
        "RENT_SECD": "분양구분코드",
        "RENT_SECD_NM": "분양구분코드명",
        "SUBSCRPT_AREA_CODE": "공급지역코드",
        "SUBSCRPT_AREA_CODE_NM": "공급지역명",
        "HSSPLY_ZIP": "공급위치 우편번호",
        "HSSPLY_ADRES": "공급위치",
        "TOT_SUPLY_HSHLDCO": "공급규모",
        "RCRIT_PBLANC_DE": "모집공고일",
        "RCEPT_BGNDE": "청약접수시작일",
        "PBLANC_URL": "공고문 바로가기",
        "RCEPT_ENDDE": "청약접수종료일",
        "SPSPLY_RCEPT_BGNDE": "특별공급 접수시작일",
        "SPSPLY_RCEPT_ENDDE": "특별공급 접수종료일",
        "GNRL_RNK1_CRSPAREA_RCPTDE": "1 순위 해당지역 접수시작일",
        "GNRL_RNK1_CRSPAREA_ENDDE": "1 순위 해당지역 접수종료일",
        "GNRL_RNK1_ETC_GG_RCPTDE": "1 순위 경기지역 접수시작일",
        "GNRL_RNK1_ETC_GG_ENDDE": "1 순위 경기지역 접수종료일",
        "GNRL_RNK1_ETC_AREA_RCPTDE": "1 순위 기타지역 접수시작일",
        "GNRL_RNK1_ETC_AREA_ENDDE": "1 순위 기타지역 접수종료일"
    }

    # Page 정보 설정
    PAGE = 1
    PER_PAGE = 50

    # 오늘 날짜 기준 1달전 모집공고 정보 API URL 
    FULL_URL = f"{REQUEST_URL}?page={PAGE}&perPage={PER_PAGE}&serviceKey={APPLY_HOME_KEY}&cond%5BRCRIT_PBLANC_DE%3A%3AGTE%5D={last_date}"

    article_summary_html = ""
    article_list = []

    # 총 게시글 개수를 위해 API 콜 
    response = requests.get(url=FULL_URL, headers=HEADER)
    if response.status_code == 200:
        
        # 공고 총 개수
        match_cnt = response.json()["matchCount"]
        
        # 공고 있을 경우 
        if match_cnt > 0:
            #마지막 페이지 넘버
            LAST_PAGE = math.ceil(match_cnt / PER_PAGE)

            # 페이지 별 게시글 FOR 문 실행 
            for i in range(1, LAST_PAGE + 1):
                FULL_URL = f"{REQUEST_URL}?page={i}&perPage={PER_PAGE}&serviceKey={APPLY_HOME_KEY}&cond%5BRCRIT_PBLANC_DE%3A%3AGTE%5D={last_date}"
                response = requests.get(url=FULL_URL, headers=HEADER)

                # return 값
                apt_json = {
                    "status" : ""
                }

                if response.status_code == 200:
                    apt_json["status"] = "SUCCESS"
                    apt_json["data"] = response.json()

                for data in apt_json["data"]["data"]:
                    # 공고번호가 이미 게시한 글인지 확인
                    # 이미 사용한 키워드 정보 가져오기
                    conn = pymysql.connect(host='YOUR_DB_HOST', user='YOUR_DB_USER', password='YOUR_DB_PASSWORD', db='WORDPRESS', charset='utf8')
                    sql_select = "SELECT COUNT(*) FROM WORDPRESS.AH_ARTICLE_LIST WHERE pblanc_no = %s"
                    with conn:
                        with conn.cursor() as cur:
                            cur.execute(sql_select, data["PBLANC_NO"])
                            article_cnt = cur.fetchall()[0][0]
                    # 등록된 게시글이 없을경우 게시글 셋팅
                    if article_cnt == 0:
                        article_info = {
                            RESPONSE_INFO["HOUSE_MANAGE_NO"]: data["HOUSE_MANAGE_NO"],
                            RESPONSE_INFO["PBLANC_NO"]: data["PBLANC_NO"],
                            RESPONSE_INFO["HOUSE_NM"]: data["HOUSE_NM"],
                            RESPONSE_INFO["HOUSE_SECD"]: data["HOUSE_SECD"],
                            RESPONSE_INFO["HOUSE_SECD_NM"]: data["HOUSE_SECD_NM"],
                            RESPONSE_INFO["HOUSE_DTL_SECD"]: data["HOUSE_DTL_SECD"],
                            RESPONSE_INFO["HOUSE_DTL_SECD_NM"]: data["HOUSE_DTL_SECD_NM"],
                            RESPONSE_INFO["RENT_SECD"]: data["RENT_SECD"],
                            RESPONSE_INFO["RENT_SECD_NM"]: data["RENT_SECD_NM"],
                            RESPONSE_INFO["SUBSCRPT_AREA_CODE"]: data["SUBSCRPT_AREA_CODE"],
                            RESPONSE_INFO["SUBSCRPT_AREA_CODE_NM"]: data["SUBSCRPT_AREA_CODE_NM"],
                            RESPONSE_INFO["HSSPLY_ZIP"]: data["HSSPLY_ZIP"],
                            RESPONSE_INFO["PBLANC_URL"]: data["PBLANC_URL"],
                            RESPONSE_INFO["HSSPLY_ADRES"]: data["HSSPLY_ADRES"],
                            RESPONSE_INFO["TOT_SUPLY_HSHLDCO"]: data["TOT_SUPLY_HSHLDCO"],
                            RESPONSE_INFO["RCRIT_PBLANC_DE"]: data["RCRIT_PBLANC_DE"],
                            RESPONSE_INFO["RCEPT_BGNDE"]: data["RCEPT_BGNDE"],
                            RESPONSE_INFO["RCEPT_ENDDE"]: data["RCEPT_ENDDE"],
                            RESPONSE_INFO["SPSPLY_RCEPT_BGNDE"]: data["SPSPLY_RCEPT_BGNDE"],
                            RESPONSE_INFO["SPSPLY_RCEPT_ENDDE"]: data["SPSPLY_RCEPT_ENDDE"],
                            RESPONSE_INFO["GNRL_RNK1_CRSPAREA_RCPTDE"]: data["GNRL_RNK1_CRSPAREA_RCPTDE"],
                            RESPONSE_INFO["GNRL_RNK1_CRSPAREA_ENDDE"]: data["GNRL_RNK1_CRSPAREA_ENDDE"],
                            RESPONSE_INFO["GNRL_RNK1_ETC_GG_RCPTDE"]: data["GNRL_RNK1_ETC_GG_RCPTDE"],
                            RESPONSE_INFO["GNRL_RNK1_ETC_GG_ENDDE"]: data["GNRL_RNK1_ETC_GG_ENDDE"],
                            RESPONSE_INFO["GNRL_RNK1_ETC_AREA_RCPTDE"]: data["GNRL_RNK1_ETC_AREA_RCPTDE"],
                            RESPONSE_INFO["GNRL_RNK1_ETC_AREA_ENDDE"]: data["GNRL_RNK1_ETC_AREA_ENDDE"]
                        }
                        article_list.append(article_info)

                    if len(article_list) == 1:
                        break
                time.sleep(1)

    # 게시글 작성
    for article in article_list:
        public_url_response = requests.get(url=article["공고문 바로가기"], headers=HEADER)
        home_apply_public_html = BeautifulSoup(public_url_response.content, 'html.parser')
        html = first_comment_html(article)
        html += str(home_apply_public_html.select_one("#printArea"))
        sub_html = sub_info_html_list(article["공급지역명"], article["공급위치"])
        html += sub_html
        result = create_article_to_wordpress(article["주택명"] + " 분양정보", html)

        if result == "SUCESS":
            conn = pymysql.connect(host='YOUR_DB_HOST', user='YOUR_DB_USER', password='YOUR_DB_PASSWORD', db='WORDPRESS', charset='utf8')
            sql = "INSERT INTO WORDPRESS.AH_ARTICLE_LIST (article_title, pblanc_no, article_type) VALUES (%s, %s, %s)"
            with conn:
                with conn.cursor() as cur:
                    cur.execute(sql, (article["주택명"], article["공고번호"], "100-001"))
                    conn.commit()
    
    sql_update = "UPDATE WORDPRESS.COM_CODE SET common_name = 'apt_no_rank_api' WHERE common_code = %s"
    conn = pymysql.connect(host='YOUR_DB_HOST', user='YOUR_DB_USER', password='YOUR_DB_PASSWORD', db='WORDPRESS', charset='utf8')
    with conn:
        with conn.cursor() as cur:
            cur.execute(sql_update, "101-001")
            conn.commit()

def first_comment_html(article):
    address = article.get("주소") or article.get("공급위치")
    apt_name = article["주택명"]
    collect_date = article["모집공고일"]
    apply_start_date = article.get("청약접수시작일") or article.get("청약접수 시작일")
    apply_end_date = article.get("청약접수종료일") or article.get("청약접수 종료일")
    first_comment_html =  f'<div id="first_comment_area"><span>이번에 소개드릴 분양정보는 <span>{address}</span>에 위치한 <span>{apt_name}</span> 입니다. <br> 모집공고일은 <span>{collect_date}</span> 이고 청약 접수는 <span>{apply_start_date} ~ {apply_end_date}</span> 입니다. <br> <p>해당 내용 참고 부탁드리고 자세한 내용은 아래에서 확인하실 수 있습니다!<p></span></div>'
    first_comment_html += f"""
    <span id="sub_comment">
    <span style="color:red">단지의 위치, 교통 편의성, 주변 환경, 교육 여건, 생활 인프라</span> 등을 꼼꼼히 살펴보는 것이 중요합니다. 이 외에도 <span style="color:red;">분양가, 계약 조건, 입주 시기 </span>등을 미리 확인하여 자신의 재정 상황과 생활 계획에 맞는 선택을 해야 합니다.
    <span style="color:blue;">모집공고일, 청약 접수일, 당첨자 발표일, 계약일 </span>등을 미리 체크하여 일정에 맞춰 준비해야 합니다.
    {apt_name}뿐만 아니라 다른 분양 아파트도 동일하게 이러한 요소들을 검토하며 분양을 고려하는 모두에게 도움이 되길 바라며, 모집공고문을 참조하시기 바랍니다.
    </span>
    """
    return first_comment_html

def sub_info_html_list(area_name, address):
    html = ""
    dobule_meter_price_html = double_meter_price_each_area_table_html(area_name)
    dobule_meter_each_size_html = double_meter_price_each_size_html(area_name)
    new_distribution_html = new_distribution_cnt_html(area_name)
    html += dobule_meter_price_html
    html += dobule_meter_each_size_html
    html += new_distribution_html
    html += f"<div id='go_map_div'><a id='go_map' href='https://map.kakao.com/link/search/{address}'>KAKAO MAP 위치보기</a></div>"
    return html

def price_sale_each_month():
    html = ""
    page = 9
    perPage = 1000
    SUB_URL = f"/15061057/v1/uddi:09916f8a-3cfa-4c9f-8b04-e49969ae839d?page={page}&perPage={perPage}&serviceKey={APPLY_HOME_KEY}"
    FULL_URL = APPLY_HOME_BASE_URL + SUB_URL
    response = requests.get(url=FULL_URL, headers=HEADER)
    if response.status_code == 200:
        print(response.json())

 

 

hug_api_func.py

import requests
import json
import xmltodict
from datetime import datetime, timedelta

# 기본 header
HEADER = {
    "Accept": "*/*",
    'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36" 
}

BASE_URL = "https://www.khug.or.kr"

area_code = {
    "서울":"01",
    "부산":"02",
    "대구":"03",
    "인천":"04",
    "광주":"05",
    "대전":"06",
    "경기":"07",
    "강원":"08",
    "충북":"09",
    "충남":"10",
    "전북":"11",
    "전남":"12",
    "경북":"13",
    "경남":"14",
    "제주":"15",
    "울산":"16",
    "세종":"17"
}

area_full_name_code = {
    "서울":"01",
    "부산":"02",
    "대구":"03",
    "인천":"04",
    "광주":"05",
    "대전":"06",
    "경기":"07",
    "강원":"08",
    "충청북도":"09",
    "충청남도":"10",
    "전라북도":"11",
    "전라남도":"12",
    "경상북도":"13",
    "경상남도":"14",
    "제주":"15",
    "울산":"16",
    "세종":"17"
}

def double_meter_price_each_area_table_html(area_name):

    # 포함된 키와 값을 찾기
    included_key = next((key for key in area_code if key in area_name), None)
    table_html = ""

    area_code_temp = area_code

    if not included_key:
        included_key = next((key for key in area_full_name_code if key in area_name), None)
        area_code_temp = area_full_name_code
    if included_key:
        HUG_API_KEY = "YOUR_HUG_API_KEY_1"

        a=datetime.now()-timedelta(days=365)    
        START_YYM = str(a.strftime('%Y-%m')).replace("-", "")
        END_YYM = str(datetime.now().strftime('%Y-%m')).replace("-", "")
        SUB_URL = f"/priceDistributedPrice3dot3.do?API_KEY={HUG_API_KEY}&START_YYM={START_YYM}&END_YYM={END_YYM}&AREA_DCD={area_code_temp[included_key]}"
        FULL_URL = BASE_URL + SUB_URL
        response = requests.get(url=FULL_URL, headers=HEADER)
        
        if response.status_code == 200:
            xpars = xmltodict.parse(response.text)
            jsonDump = json.dumps(xpars)
            jsonBody = json.loads(jsonDump)
            double_meter_info = jsonBody["response"]["body"]["items"]["item"]
            area_name = included_key
            table_html = f"<h5 class='sub_sub_tit mt_30'>지역별 ㎡당 분양가격</h5>"
            table_html += "<table class='tbl_st tbl_row tbl_col tbl_center'>"
            table_html += "<tr>"
            table_html += "<th>지역</th>"
            table_html += "<th>연월</th>"
            table_html += "<th>가격</th>"
            table_html += "</tr>"
            for info in double_meter_info:
                year_mm = info["YEAR_MM"]
                year_mm =year_mm[0:4]+'-'+year_mm[4:]
                price = "-"
                print(info["YEAR_VAL"])
                if info["YEAR_VAL"] != None:
                    price = format(int(info["YEAR_VAL"]), ',d')
                table_html += "<tr>"
                table_html += f"<td>{area_name}</td>"
                table_html += f"<td>{year_mm}</td>"
                table_html += f"<td>{price}</td>"
                table_html += "</tr>"
            
            table_html += "</table>"
    return table_html


def double_meter_price_each_size_html(area_name):
    # 포함된 키와 값을 찾기
    included_key = next((key for key in area_code if key in area_name), None)
    table_html = ""

    area_code_temp = area_code

    if not included_key:
        included_key = next((key for key in area_full_name_code if key in area_name), None)
        area_code_temp = area_full_name_code

    if included_key:
        HUG_API_KEY = "YOUR_HUG_API_KEY_2"

        a=datetime.now()-timedelta(days=365)    
        START_YYM = str(a.strftime('%Y-%m')).replace("-", "")
        END_YYM = str(datetime.now().strftime('%Y-%m')).replace("-", "")
        SUB_URL = f"/distributedBySize.do?API_KEY={HUG_API_KEY}&START_YYM={START_YYM}&END_YYM={END_YYM}&AREA_DCD={area_code_temp[included_key]}"
        FULL_URL = BASE_URL + SUB_URL
        response = requests.get(url=FULL_URL, headers=HEADER)
        table_html = ""
        if response.status_code == 200:
            xpars = xmltodict.parse(response.text)
            jsonDump = json.dumps(xpars)
            jsonBody = json.loads(jsonDump)
            area_name = included_key
            if jsonBody["response"]["body"] is not None:
                double_meter_info = jsonBody["response"]["body"]["items"]["item"]
                table_html += f"<h5 class='sub_sub_tit mt_30'>규모별 ㎡당 분양가격 - {area_name}</h5>"
                table_html += "<table class='tbl_st tbl_row tbl_col tbl_center'>"
                table_html += "<tr>"
                table_html += "<th>연월</th>"
                table_html += "<th>전용면적 60㎡ 이하</th>"
                table_html += "<th>전용면적 60㎡초과 85㎡이하</th>"
                table_html += "<th>전용면적 85㎡초과 102㎡이하</th>"
                table_html += "<th>전용면적 102㎡초과</th>"
                table_html += "</tr>"
                for info in double_meter_info:
                    year_mm = info["YEAR_MM"]
                    year_mm =year_mm[0:4]+'-'+year_mm[4:]
                    below60 = int(info["BELOW60"])
                    below85 = int(info["BELOW85"])
                    below102 = int(info["BELOW102"])
                    excess102 = int(info["EXCESS102"])
                    table_html += "<tr>"
                    table_html += f"<td>{year_mm}</td>"
                    table_html += f"<td>{format(below60, ',d')}</td>"
                    table_html += f"<td>{format(below85, ',d')}</td>"
                    table_html += f"<td>{format(below102, ',d')}</td>"
                    table_html += f"<td>{format(excess102, ',d')}</td>"
                    table_html += "</tr>"
            
                table_html += "</table>"
    return table_html

def new_distribution_cnt_html(area_name):
    # 포함된 키와 값을 찾기
    included_key = next((key for key in area_code if key in area_name), None)
    table_html = ""

    area_code_temp = area_code

    if not included_key:
        included_key = next((key for key in area_full_name_code if key in area_name), None)
        area_code_temp = area_full_name_code

    if included_key:
        HUG_API_KEY = "YOUR_HUG_API_KEY_3"

        a=datetime.now()-timedelta(days=365)    
        START_YYM = str(a.strftime('%Y-%m')).replace("-", "")
        END_YYM = str(datetime.now().strftime('%Y-%m')).replace("-", "")
        SUB_URL = f"/newDistributionNumber.do?API_KEY={HUG_API_KEY}&START_YYM={START_YYM}&END_YYM={END_YYM}&AREA_DCD={area_code_temp[included_key]}"
        FULL_URL = BASE_URL + SUB_URL
        response = requests.get(url=FULL_URL, headers=HEADER)
        if response.status_code == 200:
            xpars = xmltodict.parse(response.text)
            jsonDump = json.dumps(xpars)
            jsonBody = json.loads(jsonDump)
            double_meter_info = jsonBody["response"]["body"]["items"]["item"]
            area_name = included_key
            table_html = f"<h5 class='sub_sub_tit mt_30'>신규 분양세대수</h5>"
            table_html += "<table class='tbl_st tbl_row tbl_col tbl_center'>"
            table_html += "<tr>"
            table_html += "<th>지역</th>"
            table_html += "<th>연월</th>"
            table_html += "<th>세대수</th>"
            table_html += "</tr>"
            for info in double_meter_info:
                year_mm = info["YEAR_MM"]
                year_mm =year_mm[0:4]+'-'+year_mm[4:]
                new_distribution_cnt = info["YEAR_VAL"]
                table_html += "<tr>"
                table_html += f"<td>{area_name}</td>"
                table_html += f"<td>{year_mm}</td>"
                table_html += f"<td>{new_distribution_cnt}</td>"
                table_html += "</tr>"
            
            table_html += "</table>"
    return table_html

 

 

slack_alert.py

import requests

# Slack Webhook URL
SLACK_WEBHOOK_URL = 'YOUR_SLACK_WEBHOOK_URL'

def SendMessage(msg, title='myAutobot'):
    
    try:
        # 메시지 전송
        requests.post(
            SLACK_WEBHOOK_URL,
            headers={  # 'header'가 아닌 'headers'로 수정
                'content-type': 'application/json'
            },
            json={
                'text': title,
                'blocks': [
                    {
                        'type': 'section',
                        'text': {
                            'type': 'mrkdwn',
                            'text': msg
                        }
                    }
                ]
            }
        )
    except Exception as ex:
        print(ex)

 

 

wordpress_article_func.py (해당 부분에는 구글 인덱스 잡는 코드도 있는 부분 참고!)

import json
import requests
from urllib.parse import urljoin
from slack_alert import SendMessage
import random
from oauth2client.service_account import ServiceAccountCredentials
import httplib2
from PIL import Image, ImageDraw, ImageFont
import textwrap
import random
import os

def run(file_path, file_name, astr):

    para = textwrap.wrap(astr, width=11)

    MAX_W, MAX_H = 480, 480
    bg_color = 'rgb(214, 230, 245)'

    im = Image.new('RGB', (MAX_W, MAX_H), bg_color) 
    draw = ImageDraw.Draw(im)
    current_dir = os.path.dirname(os.path.abspath(__file__))
    font_path = os.path.join(current_dir, "font", "NanumSquareRoundB.ttf")
    font = ImageFont.truetype(font_path, size=46)
    font_color = 'rgb(0, 0, 0)'

    current_h, pad = 160, 10 

    for line in para:
        _, _, w, h = draw.textbbox((0, 0), text=line, font=font)
        draw.text(((MAX_W - w) / 2, current_h), line, font=font, fill=font_color)
        current_h += h + pad 
    im.save(f'{file_path}')

# 워드프레스 기본 정보
WP_URL = 'YOUR_WORDPRESS_URL'  # 자신의 워드프레스 주소
WP_USERNAME = 'YOUR_WP_USERNAME'  # 워드프레스 사용자이름 
WP_PASSWORD = 'YOUR_WP_APPLICATION_PASSWORD'  # 어플리케이션 비밀번호

status = 'publish' # 즉시발행:publish, 임시저장:draft
tag_ids = [1] # 태그아이디도 카테고리 아이디 찾는 방법과 동일   --> TODO: DB 로 코드 관리 필요
category_ids = [1] # 카테고리 아이디는 글/카테고리/ 해당카테고리에 커서를 가져가면 하다나에 카테고리 아이디값이 나온다. 숫자다 --> TODO: DB 로 코드 관리 필요

res_from_wordpress = requests.get(urljoin(WP_URL, "/wp-json/wp/v2/posts"),
headers={'Content-type': "application/json"},
auth=(WP_USERNAME, WP_PASSWORD))

title_list = []

def create_article_to_wordpress(title, article_content):
    title_list.append(f'{title} 놓치지 말아야 할 주요 포인트')
    title_list.append(f'이번 달 놓칠 수 없는 분양 아파트: {title}')
    title_list.append(f'분양 신청 전 필독! {title} 청약 관련 모든 정보')
    title_list.append(f'{title}의 모든것')
    title_list.append(f'{title} 분양과 함께하는 내 집 마련의 꿈')
    title_list.append(f'{title} 분양 시작, 일정 및 상세한 정보 확인')

    random_num = random.randint(0, 5)

    result = ""
    wp_title = title_list[random_num]
    slug = title
    indexing_url = f'{WP_URL}/{slug}'
    post_list = []

    article_content +=  '  <div id="article_footer_coment">'
    article_content +=  '    출처: 청약홈, 주택도시보증공사 '
    article_content +=  '  </div><br><br>'

    article_content +=  '  <div id="another_aritcle_area">'
    article_content +=  '  <h3 id="another_aritcle_area_title">LAND MARKET 의 분양정보</h3>'
    # 랜드마켓 홈페이지에 있는 게시글 랜덤 3개
    for j in range(0, 3):
        num = 0
        while num in post_list :
            num = random.randrange(0, len(res_from_wordpress.json()))
        post_list.append(num)

        article_content += '<a href="' + res_from_wordpress.json()[num]['link'] + '">' + res_from_wordpress.json()[num]['title']['rendered'] + '</a><br>'
    article_content += '</div>'
    content = article_content
    current_dir = os.path.dirname(os.path.abspath(__file__))
    file_path = os.path.join(current_dir, "thumb_img", f"{title}.png")
    file_name = f"{title}.png"

    run(file_path, file_name, f"{title}")
    # 저장된 파일 업로드할 이미지 셋팅
    url = urljoin(WP_URL, '/wp-json/wp/v2/media/')  
    f = open(file_path, 'rb')
    image_data = f.read()
    f.close()
    espSequence = bytes(file_name, "utf-8").decode("unicode_escape")  

    headers = {
        'Content-Type': 'image/png',
        'Content-Disposition': 'attachment; filename=%s' % espSequence,                                 
    }
    
    res2 = requests.post(
        url,
        data=image_data,
        headers=headers,
        auth=(WP_USERNAME, WP_PASSWORD),
        )

    media_info = res2.json()
    media_id = media_info['id']

    payload = {"status": status,
                "slug": slug,
                "title": wp_title,
                "content": content,
                "categories": category_ids,
                "tags": tag_ids,
            }
    
    # 이미지 있을 경우 이미지 정보도 삽입
    if media_id is not None:
        payload['featured_media'] = media_id

    res = requests.post(urljoin(WP_URL, "/wp-json/wp/v2/posts"),
                        data=json.dumps(payload),
                        headers={'Content-type': "application/json"},
                        auth=(WP_USERNAME, WP_PASSWORD))
    if res.ok:
        print(f'''성공 code:{res.status_code}
        {wp_title}
        {WP_URL}
        {slug}
        {category_ids}
        {tag_ids}
        ''')
        SendMessage(f"분양정보 게시글 등록완료 : {wp_title}")

        # 구글 인덱스 요청 API 
        # TODO : 경로 변경 후 정상적으로 GA 인덱스 콜 하는지 확인
        # JSON_KEY_FILE = "YOUR_GOOGLE_API_CREDENTIALS_PATH"
        
        # SCOPES = [ "https://www.googleapis.com/auth/indexing" ]
        # ENDPOINT = "https://indexing.googleapis.com/v3/urlNotifications:publish"
        
        # # Authorize credentials
        # credentials = ServiceAccountCredentials.from_json_keyfile_name(JSON_KEY_FILE, scopes=SCOPES)
        # http = credentials.authorize(httplib2.Http())
        
        # # Build the request body
        # content = {}
        # content['url'] = indexing_url
        # content['type'] = "URL_UPDATED"
        # json_content = json.dumps(content)
        
        # response, content = http.request(ENDPOINT, method="POST", body=json_content)
        # result = json.loads(content.decode())
        result = "SUCESS"
    else:
        print(f"실패 code:{res.status_code} reason:{res.reason} msg:{res.text}")
        result = "FAIL"
    
    return result

 

 

위 코드 공유 드리고 참고하여 자동화 게시글 코드 구현해보면 나름 좋은 경험이라고 생각합니다!

개발자들 화이팅

728x90
Comments