본문으로 건너뛰기
실습하기

Yahoo Finance에서 주식 데이터를 실시간으로 수집하기

시시각각 변하는 주식 시장! 실시간으로 주식 데이터를 수집해 주기적으로 저장하고 싶다면 어떻게 해야 할까요?

이번 수업에서는 Selenium을 활용하여 Yahoo Finance에서 주식 데이터를 동적으로 추출하는 방법을 알아보겠습니다.


동적 데이터 추출하기

동적 데이터는 웹 페이지의 두뇌 역할을 하는 JavaScript로 생성되는 데이터로, 사용자가 웹사이트에 접속한 후에 생성되거나 특정 행동을 취하면 변경될 수 있습니다.

이와 같은 동적 데이터는 BeautifulSoupRequests로는 가져올 수 없습니다.

하지만 Selenium을 사용하면 웹 페이지에서 JavaScript를 실행하고, 동적 데이터를 가져올 수 있습니다.

실습 화면의 코드를 단계별로 살펴보겠습니다.

실습 코드내 이해하기 어려운 부분은 학습 도구의 AI 튜터를 활용해 질문해 보세요.


1. 필요한 패키지 불러오기

  • selenium: 웹 페이지에서 동적인 데이터를 가져옵니다.

  • pandas: 데이터를 표 형태로 정리하고 처리합니다.

  • webdriver: Selenium을 사용해 웹 브라우저를 제어합니다.

  • By: 웹 페이지에서 요소를 찾는 방법을 지정합니다.

  • ActionChains: 웹 페이지에서 마우스와 키보드 동작을 수행합니다.

  • EC: 웹 페이지에서 요소가 나타날 때까지 기다립니다.


2. 웹 브라우저 열기

웹 브라우저 열기
# Chrome 웹드라이버를 실행하여 브라우저 창 열기
driver = webdriver.Chrome()

# Yahoo Finance의 'Markets' 페이지로 이동
driver.get('https://finance.yahoo.com/markets/')

크롬 브라우저를 실행하고 Yahoo Finance의 'Markets' 페이지로 이동합니다.

참고로 Selenium은 크롬, 파이어폭스 등 다양한 브라우저를 지원합니다.


3. 페이지가 완전히 로드될 때까지 대기

페이지 로드 대기
# 페이지가 완전히 로드될 때까지 대기 (최대 10초 대기)
wait = WebDriverWait(driver, 10)

웹 페이지가 완전히 로드될 때까지 최대 10초 동안 기다립니다.

웹 페이지는 로드 시간이 필요할 수 있기 때문에, 요소들이 준비될 때까지 기다리는 시간을 설정합니다.


4. 'Americas' 섹션을 찾고, 스크롤 이동하기

Americas 섹션 찾기
# 'Americas'라는 텍스트를 가진 h3 태그 찾기
americas_section = wait.until(EC.presence_of_element_located((By.XPATH, "//h3[text()='Americas']")))

# 'Americas' 섹션까지 스크롤 이동
actions = ActionChains(driver)

# 'Americas' 섹션으로 마우스 이동
actions.move_to_element(americas_section).perform()

XPATH는 XML 문서의 특정 부분을 찾기 위한 경로 표현 방법입니다.

예를 들어 위와 같이 'Americas'라는 텍스트를 가진 h3 요소/h3[text()='Americas']로 표현할 수 있습니다.

XPATH는 웹 페이지에서 요소를 찾을 때 사용하는 방법 중 하나입니다.

move_to_element는 'Americas' 섹션으로 화면을 스크롤합니다.


5. 'Americas' 섹션에서 테이블 찾기

지수 데이터 테이블 찾기
# 'Americas' 섹션의 부모 요소에서 테이블 찾기
parent_section = americas_section.find_element(By.XPATH, "./ancestor::section[contains(@data-testid, 'world-indices')]")

# 테이블 찾기
table = parent_section.find_element(By.XPATH, ".//table")

"Americas" 섹션이 속한 상위 section 태그에서 table 요소를 찾습니다.

"./ancestor::section[contains(@data-testid, 'world-indices')]"는 "Americas" 섹션의 부모 요소인 section 태그를 찾는 XPATH입니다.

이 테이블에는 우리가 필요한 데이터(예: 지수 이름, 가격 등)가 포함되어 있습니다.


6. 테이블의 헤더와 데이터 수집

테이블 헤더 및 데이터 수집
# 테이블의 헤더 추출
headers = [header.text for header in table.find_elements(By.XPATH, ".//th")]

# 테이블의 행 추출
rows = table.find_elements(By.XPATH, ".//tbody/tr")

table.find_elements(By.XPATH, ".//th")는 테이블 내에서 th 태그를 찾아 헤더를 추출합니다.

th(Table Header) 태그는 테이블의 열 이름(예: "Name", "Price")을 나타내는 HTML 태그입니다.

테이블의 각 열(th)에 해당하는 헤더(예: "Name", "Price")를 리스트에 저장합니다.

tbody/tr을 통해 테이블의 각 행(tr, table row)에 있는 데이터를 추출합니다.


7. 각 행에서 'Name'과 'Price' 값을 추출하여 저장

행 데이터 추출 및 저장
 # 데이터 저장을 위한 리스트 초기화
table_data = []

# 각 행의 열 데이터를 추출하여 리스트에 추가
for row in rows:
# 각 행의 열 데이터를 추출
columns = row.find_elements(By.XPATH, ".//td")

row_data = {} # 먼저 빈 딕셔너리 생성

# headers 리스트와 columns 리스트의 길이가 같다고 가정
for i in range(len(headers)):
# headers 리스트의 i번째 요소를 가져옴
header = headers[i]

# columns 리스트의 i번째 요소의 텍스트를 가져옴
column_value = columns[i].text

# header를 키로, column_value를 값으로 하여 딕셔너리에 추가
row_data[header] = column_value

# 데이터를 리스트에 추가
table_data.append(row_data)

각 행에 있는 데이터를 반복(for문)하면서, td 태그에 있는 데이터(열 값들)를 추출합니다.

이 데이터를 row_data 변수에 딕셔너리 형태로 저장합니다.

딕셔너리의 키는 header(헤더)이고, 값은 column_value(열 값)입니다.

마지막으로, table_data 리스트에 딕셔너리를 추가합니다.


8. pandas를 사용해 데이터프레임으로 변환

데이터프레임으로 변환
# 추출된 데이터를 판다스 데이터프레임으로 변환
df = pd.DataFrame(table_data)

# 'Symbol'과 'Price' 컬럼만 선택하여 정렬된 데이터프레임 출력
df_filtered = df[['Symbol', 'Price']]

# 정렬된 데이터 출력
print(df_filtered)

추출한 데이터를 pandas.DataFrame으로 변환합니다.

데이터 프레임에는 테이블의 데이터가 아래와 같이 저장됩니다.

NamePrice
......
......

9. 'Name'과 'Price' 컬럼만 선택하고 정렬

Name과 Price 컬럼 선택 및 정렬
df_filtered = df[['Symbol', 'Price']]

데이터프레임에서 'Name'과 'Price' 컬럼만 선택하고, 'Name' 컬럼을 기준으로 정렬합니다.

다음 내용이 궁금하다면?

코드프렌즈 PLUS 멤버십 가입 or 강의를 등록해 주세요!