import os import requests from bs4 import BeautifulSoup import pandas as pd import gradio as gr from openpyxl import load_workbook from openpyxl.utils import get_column_letter from openpyxl.styles import Alignment # 스크래핑 함수 def scrape_naver_stock(): url = "https://finance.naver.com/sise/sise_rise.naver?sosok=1" response = requests.get(url) response.encoding = 'euc-kr' # BeautifulSoup으로 HTML 파싱 soup = BeautifulSoup(response.text, 'html.parser') table = soup.find('table', class_='type_2') # 테이블에서 데이터 추출 rows = table.find_all('tr') data = [] for row in rows: cols = row.find_all('td') if len(cols) > 1: rank = cols[0].text.strip() name = cols[1].text.strip() price = cols[2].text.strip().replace(",", "") diff = cols[3].text.strip().replace("상한가", "▲").replace("상승", "▲").replace(",", "") change_rate = cols[4].text.strip().replace("%", "").replace("+", "") volume = cols[5].text.strip().replace(",", "") buy_price = cols[6].text.strip().replace(",", "") sell_price = cols[7].text.strip().replace(",", "") buy_volume = cols[8].text.strip().replace(",", "") sell_volume = cols[9].text.strip().replace(",", "") per = cols[10].text.strip() roe = cols[11].text.strip() data.append([rank, name, price, diff, change_rate, volume, buy_price, sell_price, buy_volume, sell_volume, per, roe]) # Pandas DataFrame으로 변환 df = pd.DataFrame(data, columns=['순위', '종목명', '현재가', '전일비', '등락률', '거래량', '매수호가', '매도호가', '매수총잔량', '매도총잔량', 'PER', 'ROE']) # 숫자 컬럼을 숫자 형식으로 변환 numeric_columns = ['현재가', '전일비', '등락률', '거래량', '매수호가', '매도호가', '매수총잔량', '매도총잔량'] df[numeric_columns] = df[numeric_columns].apply(pd.to_numeric, errors='coerce') return df # 엑셀 파일 저장 및 스타일 적용 함수 def save_to_excel(): df = scrape_naver_stock() directory = "/mnt/data" # 경로가 존재하지 않으면 생성 if not os.path.exists(directory): os.makedirs(directory) file_path = os.path.join(directory, "naver_stock_data.xlsx") # 엑셀로 저장 df.to_excel(file_path, index=False, engine='openpyxl') # 엑셀 파일 불러오기 wb = load_workbook(file_path) ws = wb.active # 숫자 데이터가 있는 열을 우측 정렬로 설정 alignment = Alignment(horizontal='right') # 숫자 형식 적용할 열들 (1번째는 순위이므로 제외) for col in range(3, ws.max_column + 1): for row in range(2, ws.max_row + 1): # 첫 번째 행은 헤더이므로 제외 cell = ws[f"{get_column_letter(col)}{row}"] cell.alignment = alignment # 엑셀 파일 저장 wb.save(file_path) return file_path # 그라디오 UI def display_stocks(): df = scrape_naver_stock() return df # 그라디오 인터페이스 with gr.Blocks() as iface: # 스크래핑된 데이터 테이블 출력 stock_table = gr.DataFrame(label="상승 TOP 종목") download_button = gr.Button("엑셀 파일 다운로드") # 버튼 클릭 시 엑셀 파일 저장 및 다운로드 제공 download_output = gr.File() # 버튼 클릭 시 데이터 업데이트 download_button.click(save_to_excel, outputs=download_output) # 스크래핑된 데이터를 UI에 로드 iface.load(fn=display_stocks, inputs=[], outputs=stock_table) iface.launch(share=True)