본문 바로가기
취미/웹 크롤링 연습

네이버 증권에서 상한가 크롤링하기 (2탄)

by 배당금 2024. 7. 2.
반응형

안녕하세요 어제에 이어 2탄을 써보고자 합니다.

 

어제자 링크가 필요하신 분은 보고 와주세요~

어제자 이고싶었는데 작성할게 많네요..

2024.06.30 - [웹 크롤링 연습] - 네이버 증권에서 상한가 크롤링하기 (1탄)

 

네이버 증권에서 상한가 크롤링하기 (1탄)

안녕하세요 오늘은 네이버 증권에서상한가를 크롤링해보려고 합니다. 상한가와 코스피, 코스닥 3개이며 체크와 적용하기를 통해 리스트를 변경할 수 있습니다.저는 여기서 PER(배),고가, 저가를

jusikhouse.tistory.com

 

지난 글의 코드입니다.

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

wd = webdriver.Chrome()
wd.get(upper_url)
time.sleep(2)

wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/table/tbody/tr[1]/td[6]/input').click()
time.sleep(0.3)
btn = wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/table/tbody/tr[3]/td[1]/input')
btn.click()
time.sleep(0.3)
btn = wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/table/tbody/tr[4]/td[1]/input')
btn.click()
time.sleep(0.3)
btn = wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/div/a[1]/img')
btn.click()
time.sleep(5)

 

맨 밑의 time.sleep은 뒤의 값을 조정해주세요.

오늘은 이제 필요한 값을 저장하여 엑셀로 저장하는 것을 해보겠습니다.

 

오늘자에도 코스피는 있질 않습니다.. 중요한 건 아니니까요..

이것을 하기 전에는 코드가 달라질 수 있으므로

1탄에서 셀레니움을 통해 해제한 체크박스를 동일하게 해제시킨 후 적용을 눌러

가져올 데이터 값이 동일할 수 있도록 해줍니다. 

 

그 후 ctrl + U를 해 페이지 소스를 봐줍니다.

거기서 ctrl + F를 통해 위 사진에 있는 인벤티지랩을 찾으면 쉽게 찾을 수 있습니다.

맨 위에 이름, 그 밑으로 현재가, 전일비, 등락률, 거래량, 시가가 순서대로 존재합니다.

 

BeautifulSoup

 

우선 html에서 데이터를 긁어야 하니 BeautifulSoup 을 불러옵니다.

 

셀레니움은 웹페이지를 동적으로 작동하기위에 만든 테스트 모듈이지만,

BeautifulSoup 은 진짜 엡 데이터 크롤링 라이브러리 입니다. 중요하죠..

from bs4 import BeautifulSoup

다시 맨 밑으로 내려가서

 

html에 웹 드라이버를 이용하여 그 페이지의 소스를 추출합니다.

그것을 BeautifulSoup을 이용해 html을 파서합니다.

html = wd.page_source
soup = BeautifulSoup(html, 'html.parser')

 

저희는 여기서 코스피와 코스닥을 분리 해야 하는데

페이지 원본을 보시면 코스피와 코스닥이 <div class="box_type_l"> 안에

코스피와 코스닥 글자로만 구별이 가능하게 해놓았습니다..

그래서 저희는 두개를 분리해서 데이터를 저장해야 합니다.

 

kospi_header = soup.find('h4', string='코스피') #h4에서 코스피라는 단어를 찾음

#h4 코스피 상위에서 div태그에 클래스가 box_type_l 인것을 찾음
kospi_section = kospi_header.find_parent('div', class_='box_type_l') 

kosdaq_header = soup.find('h4', string='코스닥')
kosdaq_section = kosdaq_header.find_parent('div', class_='box_type_l')

이렇게 분리시킨 두 항목에서 각각의 데이터를 뽑아내야 하는데

구조가 동일하니 def로 함수를 만들어 사용합니다.

 

section을 통해 HTML 을 입력받는데 바로위의 코스피 코스닥 섹션을 받게 할겁니다.

그리고 데이터를 초기화 시킵니다.

def parse_table(section):
    data = []
 

 

각행에 반복작업을 수행하기 위해

for row in rows: 를 사용해줍니다.

 

for row in rows:
        cols = row.find_all('td') # 주어진 열에서 모든 td 태그를 찾습니다.
        if cols and len(cols) >= 9:  # 필요한 td 요소가 9개 이상인지 확인
            item = {} # 각 행 저장을 위해 데이터열 초기화
            try:
                item['no'] = cols[0].text.strip()
                item['name'] = cols[3].text.strip()
                item['current_price'] = cols[4].text.strip()
                item['change'] = cols[5].find('span', class_='tah p11 red02').text.strip()
                item['rate'] = cols[6].find('span', class_='tah p11 red01').text.strip()
                item['volume'] = cols[7].text.strip()
                item['open_price'] = cols[8].text.strip()
                data.append(item)
            except AttributeError: #데이터 추출중 AttributeError가 발생하면 해당 행을 넘깁니다. 에러가 나오면 넘김.
                continue
    return data  # 추출된 데이터리스트를 반환합니다.

 

아이템을 설명하기 위해 페이지 원본에서 가져왔습니다. 

cols = row.find_all('td' 에서 td 태그값을 불러오기로 했는데 열은 0번부터 시작합니다.

그래서 td 태그의 맨 위부터 0번 입니다. 0번부터 시작하죠

그래서 0번의 1, 3번의 이름, 4번의  현재가 등등으로요..

 

 

반응형

 

 

 

5번과 6번은 td 안의 span에 포함되어 있어서,  한번 더 찾은 값으로 데이터를 반환시킵니다.

밑에 원본은 제가 체크박스를 해제를안해서 몇개가 더있네요..

        <tr>
                    <td class="no" >1</td>0
                    <td class="number" style="padding-right:10px;">1</td>
                    <td class="number" style="padding-right:10px;">1</td>
                    <td style="padding-left:15px;"><a href="/item/main.naver?code=365330">에스와이스틸텍</a></td>
                    <td class="number" style="padding-right:15px;">2,975</td>
                    <td class="rate_up" style="padding-right:15px;">
                <em class="bu_p bu_pup2"><span class="blind">상한가</span></em><span class="tah p11 red02">
                685
                </span>
            </td>
                    <td class="rate_up" style="padding-right:15px;">
                <span class="tah p11 red01">
                +29.91%
                </span>
            </td>
                    <td class="number" style="padding-right:20px;">20,094,764</td>
                    <td class="number" style="padding-right:20px;">2,290</td>
                    <td class="number" style="padding-right:20px;">2,975</td>
                    <td class="number" style="padding-right:20px;">2,235</td>
                    <td class="number" style="padding-right:20px;">6.73</td>
        </tr>

 

만약 데이터를 출력해보고 싶으시면

# 추출된 데이터 출력
for item in kospi_data:
    print(f"No: {item['no']}, Name: {item['name']}, Current Price: {item['current_price']}, "
          f"Change: {item['change']}, Rate: {item['rate']}, Volume: {item['volume']}, "
          f"Open Price: {item['open_price']}")


for item in kosdaq_data:
    print(f"No: {item['no']}, Name: {item['name']}, Current Price: {item['current_price']}, "
          f"Change: {item['change']}, Rate: {item['rate']}, Volume: {item['volume']}, "
          f"Open Price: {item['open_price']}")

 

이제 마무리 입니다..

pandas를 통해 데이터 프레임을 저장할수 있게 해주고, 엑셀로 저장합니다.

참 판다스 불러오셔야 합니다.

import pandas as pd

위에서 만든 데이터들을 판다스의 dataframe으로 변환 후에

판다스를 통해 엑셀로 변활할 겁니다. 근데 저희는

코스피와 코스닥이다 보니 시트를 분리시켜 저장하는게 좋아보입니다.

 

with 문을 사용하여 pd.ExcelWriter 객체를 생성하고, writer 변수를 선언한 후에,

이렇게하면 writer문이 with을 벗어나면 자동으로 닫힙니다.

 

엑셀 문서로 만드는데, sheet_name을 각각 설정해주고, 인덱스값는 제거합니다. 왜냐면,,
이미 no로 숫자가 정렬되기때문에 굳이 필요가없습니다.

경로와 파일명은 밑에 보이실거같아요..

# DataFrame 생성
kospi_df = pd.DataFrame(kospi_data)
kosdaq_df = pd.DataFrame(kosdaq_data)

# Excel 파일로 저장
with pd.ExcelWriter("D:/stock_data.xlsx") as writer:
    kospi_df.to_excel(writer, sheet_name="KOSPI", index=False)
    kosdaq_df.to_excel(writer, sheet_name="KOSDAQ", index=False)

 

 

이로써 동일하게 완성됬는데 오늘도 코스피의 상한가가 없어서 확인하지는 못했습니다.

그러나 코스피 시트는 깨끗합니다..

 

전체코드

from selenium import webdriver
from selenium.webdriver.common.by import By
import time
from bs4 import BeautifulSoup
import pandas as pd


wd = webdriver.Chrome()
wd.get(upper_url)
time.sleep(2)

wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/table/tbody/tr[1]/td[6]/input').click()
time.sleep(0.3)
btn = wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/table/tbody/tr[3]/td[1]/input')
btn.click()
time.sleep(0.3)
btn = wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/table/tbody/tr[4]/td[1]/input')
btn.click()
time.sleep(0.3)
btn = wd.find_element(By.XPATH, '/html/body/div[3]/div[2]/div[2]/div[1]/div[2]/form/div/div/div/a[1]/img')
btn.click()
time.sleep(5)

html = wd.page_source
soup = BeautifulSoup(html, 'html.parser')

kospi_header = soup.find('h4', string='코스피')
kospi_section = kospi_header.find_parent('div', class_='box_type_l')
#kospi_section = kospi_header.find_parent('div', class_='box_type_l') if kospi_header else None
kosdaq_header = soup.find('h4', string='코스닥')
kosdaq_section = kosdaq_header.find_parent('div', class_='box_type_l')
#kospi_section = kospi_header.find_parent('div', class_='box_type_l') if kospi_header else None

def parse_table(section):
    data = []
    rows = section.find_all('tr')
    for row in rows:
        cols = row.find_all('td')
        if cols and len(cols) >= 9:  # 필요한 td 요소가 9개 이상인지 확인
            item = {}
            try:
                item['no'] = cols[0].text.strip()
                item['name'] = cols[3].text.strip()
                item['current_price'] = cols[4].text.strip()
                item['change'] = cols[5].find('span', class_='tah p11 red02').text.strip()
                item['rate'] = cols[6].find('span', class_='tah p11 red01').text.strip()
                item['volume'] = cols[7].text.strip()
                item['open_price'] = cols[8].text.strip()
                data.append(item)
            except AttributeError:
                continue
    return data

# 코스닥 데이터 파싱
kospi_data = parse_table(kospi_section)
#kospi_data = parse_table(kospi_section) if kospi_section else []
kosdaq_data = parse_table(kosdaq_section)
#kosdaq_data = parse_table(kosdaq_section) if kosdaq_section else []

# 추출된 데이터 출력
for item in kospi_data:
    print(f"No: {item['no']}, Name: {item['name']}, Current Price: {item['current_price']}, "
          f"Change: {item['change']}, Rate: {item['rate']}, Volume: {item['volume']}, "
          f"Open Price: {item['open_price']}")


for item in kosdaq_data:
    print(f"No: {item['no']}, Name: {item['name']}, Current Price: {item['current_price']}, "
          f"Change: {item['change']}, Rate: {item['rate']}, Volume: {item['volume']}, "
          f"Open Price: {item['open_price']}")

# DataFrame 생성
kospi_df = pd.DataFrame(kospi_data)
kosdaq_df = pd.DataFrame(kosdaq_data)

# Excel 파일로 저장
#with pd.ExcelWriter("D:/deajeon/stock_data.xlsx") as writer:
with pd.ExcelWriter("D:/stock_data.xlsx") as writer:
    kospi_df.to_excel(writer, sheet_name="KOSPI", index=False)
    kosdaq_df.to_excel(writer, sheet_name="KOSDAQ", index=False)
반응형

'취미 > 웹 크롤링 연습' 카테고리의 다른 글

네이버 증권에서 상한가 크롤링하기 (1탄)  (0) 2024.06.30
크롤링 연습  (0) 2024.06.29