주간책톡(부산 도서관) 크롤링 -4 표의 형태를 어떻게 api 로 전송하지?(tabulate, matplotlib)

2023. 4. 26. 01:23프로젝트/주간책톡

앞서서

이런 형태의 dataframe 을 얻었다!

 

그런데 이걸 슬랙 api 를 이용해 봇으로 보내려면 어떤 방법이 있을까?

  1.  크롤링 한 순서대로 1. 제목[1], 2. 저자[1], 3.출판사[1] .... 이런식으로 하나씩 보내기.
  2.  리스트 형태로 묶어서 리스트 씩 보내기
  3.  표 형태로 사진으로 보내기
  4. 등등..
당신이 한 생각은 이미 누군가가 생각 했었다.

사업할때나 뭔가 아이템을 가지고 상업적으로 이용해보려면 화가나는 말이지만, 문제를 해결 하는 입장에서는 정말 기쁜 말이다. 뉴턴이 거인의 어깨위에 앉았기 때문에 더 멀리 볼수 있었다.말처럼. 누가 먼저 고민을 해줬다는 것이다!

물론 (대부분의) 해결방법도!

 

import pandas as pd
import matplotlib.pyplot as plt
import os

def dataframe_to_table(df):
    fig, ax = plt.subplots(figsize=(df.shape[1]*1.5, df.shape[0]*0.5))
    ax.axis("off") # 축의 테두리 숨김 (: 표를 깔끔하게)
    table = ax.table(cellText=df.values, colLabels=df.columns, cellLoc="center", loc="center") # cellLoc 셀 내 텍스트 정렬
    table.set_fontsize(10)
    fig.tight_layout() # 요소들 간격 최적화
    plt.show()
    
data = {
    "A": [1, 2, 3],
    "B": [4, 5, 6],
    "C": [7, 8, 9]
}

df = pd.DataFrame(data)

dataframe_to_table(df)

위 코드를 실행하면 이런 표를 얻을수 있다!

 

ax.axis("off") # 축의 테두리 숨김 (: 표를 깔끔하게)

이 코드가 없다면 축의 테두리가 나타나

mapplotlib 을 주로 사용하는 목적대로 나오지만, 내가 원하는 건 깔끔한 표의 이미지이기에 축을 숨겼다.

 

이 이미지 파일을 전송하면 된다!

 

 

import pandas as pd
import matplotlib.pyplot as plt
import os

def dataframe_to_image(df, image_path):
    fig, ax = plt.subplots(figsize=(df.shape[1]*1.5, df.shape[0]*0.5))
    ax.axis("off")
    table = ax.table(cellText=df.values, colLabels=df.columns, cellLoc="center", loc="center")
    table.set_fontsize(10)
    fig.tight_layout()
    plt.savefig(image_path, dpi=300, bbox_inches="tight") # bbox_inches='tight' 이미지의 경계를 테이블 주위에 타이트하게!
    plt.close() # 리소스 관리 차원에서 해제. 다음 그림 생성 할떄 이전 그림의 리소스가 중첩x, 메모리 누수 방지!

data = {
    "A": [1, 2, 3],
    "B": [4, 5, 6],
    "C": [7, 8, 9]
}
df = pd.DataFrame(data)

# DataFrame을 이미지로 변환
image_path = "dataframe_image.png"
dataframe_to_image(df, image_path)

# Slack에 이미지 전송
api_token = "슬랙 api 토큰값"
channel = "#채널명"
message = "표 형태 보내기 연습" #이미지와 함께 말할 내용
send_slack_image(api_token, channel, image_path, message=message)

# 전송 후 이미지 파일 삭제
os.remove(image_path)

위 코드를 실행하면

텍스트와 함께 이미지의 형태로 잘 보내어 진다.

 

아까 뽑아내었던 books_df 를 보내면

 

뭣?

글이 너무 작고 글이 깨진다.

 

표의 스케일이나 auto_set_font_size 를건드려봐도

글이 너무 길어서 ? 한글 문제? 일단 나중에 해결하도록 기록해두고,

슬랙 봇의 목적인 데이터셋 확보에는 이미지 보다는 텍스트가 접근성이 좋다. 고 자기합리화를 한뒤

 

그렇다면 표의 형식을 유지한 채로 텍스트의 형태로 보내주고 싶은데.. 어떻게 해야할까 찾아보았다.

import pandas as pd
import requests

def send_slack_dataframe(api_token, channel, dataframe, message=None):
    url = "https://slack.com/api/chat.postMessage"
    headers = {
        "Authorization": f"Bearer {api_token}",
        "Content-Type": "application/json"
    }
    
    # DataFrame을 텍스트 형식으로 변환
    texted_dataframe = dataframe.to_string(index=False) #df 를 str 로 변환하고 index 를 생략
    
    # 코드 블록 형식으로 감싸기
    code_block = f"```\n{texted_dataframe}\n```" 
    ''' 
    f : f-string 임을 나타냄. {} 포매팅을 사용하게해줌
    ``` ``` slack 에서 코드블록을 만들때 사용되는 마크다운 문법 <- 이놈이 포인트
    \n 개행
    {} 포매팅
    '''
    
    # 메시지와 함께 전송
    if message: 
        payload = {
            "channel": channel,
            "text": f"{message}\n{code_block}"
        }
    else:
        payload = {
            "channel": channel,
            "text": code_block
        }

    response = requests.post(url, headers=headers, json=payload)
    print(response.json())

data = {
    "A": [1, 2, 3],
    "B": [4, 5, 6],
    "C": [7, 8, 9]
}

df = pd.DataFrame(data)


# Slack에 DataFrame 전송
api_token = "api 토큰"
channel = "#채널명"
message = "이미지 말고 코드블록 형태로 보내기연습" #이미지와 함께 말할 내용
send_slack_dataframe(api_token, channel, df, message=message)

오...

괜찮은것 같기도하나 글이 길어진다면?

 

생각보다 보기 좋게 나왔다. 데이터 셋으로는 괜찮아 보인다.

하지만 시각적으로 좀 정렬이 됬으면 좋겠는데..

 

그 답은 tabulate 패키지.

나중에 tablutate 에 대해서 정리하기로 하고, 한줄요약 하자면

tabulate : Python에서 테이블 형식의 데이터를 깔끔하게 출력하기 위한 도구

 

 

import pandas as pd
import requests
from tabulate import tabulate

def send_slack_dataframe_with_grid(api_token, channel, dataframe, message=None):
    url = "https://slack.com/api/chat.postMessage"
    headers = {
        "Authorization": f"Bearer {api_token}",
        "Content-Type": "application/json"
    }
    
    # DataFrame을 격자가 있는 텍스트 형식의 표로 변환
    texted_dataframe = tabulate(
                                    dataframe, # 바꿀 객체
                                    headers='keys', # 테이블의 헤더로 열 이름을 사용, keys 는 기본값
                                    tablefmt='grid',  # 테이블의 출력 형식
                                    showindex=True # DF의 인덱스를 테이블 왼쪽에 출력, 숨기려면 false
                                  )
    
    # 코드 블록 형식으로 감싸기
    code_block = f"```\n{texted_dataframe}\n```"
    
    # 메시지와 함께 전송
    if message:
        payload = {
            "channel": channel,
            "text": f"{message}\n{code_block}"
        }
    else:
        payload = {
            "channel": channel,
            "text": code_block
        }

    response = requests.post(url, headers=headers, json=payload)
    print(response.json())

df = pd.DataFrame(books_df)

# Slack에 격자가 있는 표 형식의 DataFrame 전송
api_token = "api 토큰"
channel = "#채널명"
message = "tabulate 를 이용한 표형식 보내기 연습"
send_slack_dataframe_with_grid(api_token, channel, df, message=message)

 

괜찮게 정리가 되었다.

 

옛날 하이텔 느낌이 난달까?

 

 

 

다음 목표는

link 로 들어가서 요약내용 크롤링해서 정리 (요약된 글의 양이 오디오는 약 20~30분 정도 의 내용),

슬랙 봇에 올렸던 것을 역으로 다시 크롤링해 데이터셋으로 만드는 것이 목표!

728x90