import re
import requests
import pandas as pd
import gradio as gr
# 디버깅: 스크래핑 과정을 로그로 확인하기 위함
def debug_print(*args):
print("[DEBUG]", *args)
def scrape_data(market_type: str):
"""
market_type (str): '0' -> 코스피, '1' -> 코스닥
네이버 증권의 '상승 종목' 페이지에서 해당 market_type의 정보를 스크래핑.
(BeautifulSoup / lxml 없이 정규표현식만 사용)
"""
# market_type에 따라 URL 설정
# '0'이면 코스피, '1'이면 코스닥
base_url = "https://finance.naver.com/sise/sise_rise.naver?sosok="
url = base_url + market_type
debug_print("Requesting URL:", url)
response = requests.get(url)
debug_print("Status Code:", response.status_code)
# HTML 전체 텍스트
html_text = response.text
# 1)
구간 추출
pattern_table = re.compile(
r']*class=["\']type_2["\'][^>]*>(.*?)
',
re.DOTALL | re.IGNORECASE
)
match_table = pattern_table.search(html_text)
if not match_table:
debug_print("Error: Target table not found.")
return []
table_html = match_table.group(1)
# 2) table 내부의 단위로 나누기
pattern_tr = re.compile(r'
]*>(.*?)
', re.DOTALL | re.IGNORECASE)
rows = pattern_tr.findall(table_html)
debug_print(f"Found total {len(rows)} blocks in table.")
data_list = []
row_count = 0
for row_html in rows:
# 3) | 태그 추출
pattern_td = re.compile(r' | ]*>(.*?) | ', re.DOTALL | re.IGNORECASE)
cols = pattern_td.findall(row_html)
# 유효한 데이터 열이 아닌 경우(또는 공백행 등) 스킵
if len(cols) < 12:
continue
# HTML 태그 제거 헬퍼 함수
def clean_html(raw_html):
# 모든 태그 제거
text = re.sub(r'<.*?>', '', raw_html, flags=re.DOTALL)
return text.strip()
rank = clean_html(cols[0])
name = clean_html(cols[1])
current = clean_html(cols[2])
diff = clean_html(cols[3])
change_rate = clean_html(cols[4])
volume = clean_html(cols[5])
buy_price = clean_html(cols[6])
sell_price = clean_html(cols[7])
total_buy = clean_html(cols[8])
total_sell = clean_html(cols[9])
per_ = clean_html(cols[10])
roe_ = clean_html(cols[11])
debug_print(f"[Row {row_count}] rank={rank}, name={name}, current_price={current}")
row_count += 1
data_list.append({
"순위": rank,
"종목명": name,
"현재가": current,
"전일비": diff,
"등락률": change_rate,
"거래량": volume,
"매수호가": buy_price,
"매도호가": sell_price,
"매수총잔량": total_buy,
"매도총잔량": total_sell,
"PER": per_,
"ROE": roe_
})
return data_list
def make_table(market_choice):
"""
market_choice (str): "코스피" 또는 "코스닥"
해당 선택에 따라 scrape_data()를 실행한 뒤 DataFrame으로 반환.
"""
debug_print(f"Scraping data for market_choice={market_choice}...")
# 사용자가 선택박스에서 "코스피" 선택 -> '0'
# 사용자가 선택박스에서 "코스닥" 선택 -> '1'
market_type = "0" if market_choice == "코스피" else "1"
data = scrape_data(market_type)
if not data:
debug_print("No data retrieved or table not found.")
return pd.DataFrame(["데이터를 가져오지 못했습니다."])
debug_print("Scraping done. Converting to DataFrame.")
return pd.DataFrame(data)
def main():
"""
Gradio 인터페이스 실행
"""
with gr.Blocks() as demo:
gr.Markdown("# 네이버 증권 스크래핑 : 코스피 / 코스닥 선택")
# 선택박스: 코스피 / 코스닥
market_choice = gr.Dropdown(
label="종목 선택",
choices=["코스피", "코스닥"],
value="코스피" # 기본값
)
# 버튼과 결과용 DataFrame
scrape_btn = gr.Button("데이터 가져오기")
output_df = gr.DataFrame(label="스크래핑 결과")
# 버튼 클릭 시 스크래핑 함수 호출
scrape_btn.click(fn=make_table,
inputs=market_choice,
outputs=output_df)
demo.launch()
if __name__ == "__main__":
main()