Data Crawling - 네이버 금융, 주식 가격 수집하기

19년 3월부터 카이스트 데이터사이언스 연구실 (KAIST DS LAB)에서 일하기 시작했다.

가장 처음 맡은 일이 파이썬으로 특정 데이터들을 웹에서 크롤링하는 것인데, 예전에 BeautlfulSoup4으로 간단하게 몇 가지 다루어 본 것을 복습하는 겸 포스트를 작성하기로 했다.

기본적으로 작업은 파이참 (pyCharm)으로 진행했다.

네이버 금융 웹에서 봉차트 데이터 수집하기

아래와 같은 순서로 진행한다.

  • Step 1: 특정 종목의 가격 받아오기
  • Step 2: 여러 종목의 가격 받아오기
  • Step 3: 특정 종목의 봉차트 데이터 받아오기
  • Step 4: 여러 종목의 봉차트 데이터 받아오기

시작하기 전, interpreter가 제대로 설치되어 있는지 체크하자.

우리가 이번에 사용할 패키지는 requestsbeautifulsoup4이다.

맥에서는 preference -> project interpreter에 가면 다운로드 및 확인이 가능하고,

윈도우에서는 file -> setting -> project interpreter에 가면 마찬가지로 확인이 가능하다.

맥에서 파이참 preference을 열었을 때

특정 종목의 가격 받아오기

요즘 펄어비스가 신작을 발표하면서 주식 가격이 떡상(?)하고 있다. 개인적으로 관심이 가는 회사니까.. 여기 데이터를 한번 가져와 보자.

먼저 네이버 금융에 접속해서 펄어비스를 검색해 보자.

빨간색 네모가 우리가 가져가고 싶은 데이터

저 빨간색 네모 안의 숫자가 우리가 크롤링 하고 싶은 펄어버스 주식의 현재 가격이다. 크롬 (chrome)의 개발자 도구를 켜서 위치를 확인하자.



이제 코드를 짜면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
import requests
from bs4 import BeautifulSoup

url = “https://finance.naver.com/item/main.nhn?code=263750"
result = requests.get(url)
bs_obj = BeautifulSoup(result.content, “html.parser”)

no_today = bs_obj.find(“p”, {“class”: “no_today”}) # 태그 p, 속성값 no_today 찾기
blind = no_today.find(“span”, {“class”: “blind”}) # 태그 span, 속성값 blind 찾기
now_price = blind.text

print(now_price)

실행하면 now_price가 187,500이 제대로 출력됨을 확인할 수 있다.
(실시간으로 가격 변동이 발생 ㅠㅠ)

여러 종목의 가격 받아오기

자세히 보면, 우리가 입력한 url의 제일 뒤 숫자 6자리가 회사 코드임을 알 수 있다.

이를 원하는 코드로 바꿈으로써, 여러 회사들의 주식 가격을 가져올 수 있다.

위 코드에 대해서 company_code를 입력하면 now_price를 출력할 수 있도록 리팩토링 (refactoring) 해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import requests
from bs4 import BeautifulSoup

# company_code를 입력받아 bs_obj를 출력
def get_bs_obj(company_code):
url = “https://finance.naver.com/item/main.nhn?code=" + company_code
result = requests.get(url)
bs_obj = BeautifulSoup(result.content, “html.parser”)
return bs_obj

# company_code를 입력받아 now_price를 출력
def get_price(company_code):
bs_obj = get_bs_obj(company_code)
no_today = bs_obj.find(“p”, {“class”: “no_today”})
blind = no_today.find(“span”, {“class”: “blind”})
now_price = blind.text
return now_price

# 펄어비스 회사 코드는 ”263750”
# 삼성전자 회사 코드는 ”005930”
# 셀트리온 회사 코드는 ”068270”
company_codes = [“263750”, “005930”, “068270”]

for item in company_codes:
now_price = get_price(item)
print(now_price)

실행하면, 펄어비스와 삼성전자, 그리고 셀트리온의 현재 주식 가격을 잘 받아오고 있음을 확인할 수 있다.

특정 종목의 봉차트 데이터 받아오기

이번에는 펄어비스의 전일, 고가, 시가, 저가 주식 데이터를 가져와 보자.

아까와 마찬가지로 먼저 데이터의 위치를 개발자 도구를 사용하여 알아보자.



빨간색 네모 안에 전일 주식 가격이 들어있음을 확인한 후, 코드를 짜보자.

1
2
3
4
5
6
7
8
9
10
11
12
import requests
from bs4 import BeautifulSoup

url = “https://finance.naver.com/item/main.nhn?code=263750"
result = requests.get(url)
bs_obj = BeautifulSoup(result.content, “html.parser”)

td_first = bs_obj.find(“td”, {“class”: “first”}) # 태그 td, 속성값 first 찾기
blind = td_first.find(“span”, {“class”: “blind”}) # 태그 span, 속성값 blind 찾기
close = blind.text

print(close)

전일 (close)에 해당하는 펄어비스의 주식 가격이 제대로 출력되고 있다.

위와 같은 방법으로, 고가 (high), 시가 (open), 저가 (low)에 대한 데이터의 위치를 찾아서 코딩하면 된다.

주의할 점은, find() 함수는 가장 처음 만나는 태그를 반환하므로, 그 뒤의 동일한 이름의 태그를 찾고 싶다면 find_all() 함수를 사용해야 한다.

또한, find_all()은 리스트 (list)를 반환한다.

대략적으로 각 데이터의 위치를 아래에 그려 보았다.

tr 태그가 두 개, 그리고 각각의 태그 안에 td 태그가 세 개씩 있고, 첫 번째 td는 다행히도 속성값이 명시되어 있지만 두 번째 td부터는 그렇지 않다.

위와 같은 형태일 때는 모두를 포함하면서 속성값을 가지고 있어, 전체 데이터에서 특정지을 수 있는 태그부터 찾아서 narrow down해야 한다.

이번에는 그 역할로 table 태그의 속성값 no_info를 사용할 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
from bs4 import BeautifulSoup

url = “https://finance.naver.com/item/main.nhn?code=263750"
result = requests.get(url)
bs_obj = BeautifulSoup(result.content, “html.parser”)

#close 종가(전일)
td_first = bs_obj.find(“td”, {“class”: “first”}) # 태그 td, 속성값 first 찾기
blind = td_first.find(“span”, {“class”: “blind”}) # 태그 span, 속성값 blind 찾기
close = blind.text

# high 고가
table = bs_obj.find(“table”, {“class”: “no_info”}) # 태그 table, 속성값 no_info 찾기
trs = table.find_all(“tr”) # tr을 list로 []
first_tr = trs[0] # 첫 번째 tr 지정
tds = first_tr.find_all(“td”) # 첫 번째 tr 안에서 td를 list로
second_tds = tds[1] # 두 번째 td 지정
high = second_tds.find(“span”, {“class”: “blind”}).text

# open 시가
second_tr = trs[1] # 두 번째 tr 지정
tds_second_tr = second_tr.find_all(“td”) # 두 번째 tr 안에서 td를 list로
first_td_in_second_tr = tds_second_tr[0] # 첫 번째 td 지정
open = first_td_in_second_tr.find(“span”, {“class”: “blind”}).text

# low 저가
second_td_in_second_tr = tds_second_tr[1] # 두 번째 td 지정
low = second_td_in_second_tr.find(“span”, {“class”: “blind”}).text

print(close)
print(high)
print(open)
print(low)

위 코드를 실행시키면, 펄어비스의 봉차트 주식 데이터가 제대로 출력됨을 확인할 수 있다.

여러 종목의 봉차트 데이터 받아오기

이제 위 코드에 대해서 company_code를 입력하면 봉차트 데이터를 출력할 수 있도록 리팩토링 (refactoring) 해보자.

입력값은 company_code이고, 리턴값은 close, high, open, low인 함수를 짜면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import requests
from bs4 import BeautifulSoup

def get_bs_obj(company_code):
url = “https://finance.naver.com/item/main.nhn?code=" + company_code
result = requests.get(url)
bs_obj = BeautifulSoup(result.content, “html.parser”)
return bs_obj

def get_candle_chart(company_code):
bs_obj = get_bs_obj(company_code)

# close 종가(전일)
td_first = bs_obj.find(“td”, {“class”: “first”}) # 태그 td, 속성값 first 찾기
blind = td_first.find(“span”, {“class”: “blind”}) # 태그 span, 속성값 blind 찾기
close = blind.text

# high 고가
table = bs_obj.find(“table”, {“class”: “no_info”}) # 태그 table, 속성값 no_info 찾기
trs = table.find_all(“tr”) # tr을 list로 []
first_tr = trs[0] # 첫 번째 tr 지정
tds = first_tr.find_all(“td”) # 첫 번째 tr 안에서 td를 list로
second_tds = tds[1] # 두 번째 td 지정
high = second_tds.find(“span”, {“class”: “blind”}).text

# open 시가
second_tr = trs[1] # 두 번째 tr 지정
tds_second_tr = second_tr.find_all(“td”) # 두 번째 tr 안에서 td를 list로
first_td_in_second_tr = tds_second_tr[0] # 첫 번째 td 지정
open = first_td_in_second_tr.find(“span”, {“class”: “blind”}).text

# low 저가
second_td_in_second_tr = tds_second_tr[1] # 두 번째 td 지정
low = second_td_in_second_tr.find(“span”, {“class”: “blind”}).text

return {“close”: close, “high”: high, “open”: open, “low”: low}

# 펄어비스 회사 코드는 ”263750”
# 삼성전자 회사 코드는 ”005930”
# 셀트리온 회사 코드는 ”068270”
company_codes = [“263750”, “005930”, “068270”]

for item in company_codes:
candle_chart = get_candle_chart(item)
print(candle_chart)

위 코드를 실행시키면 펄어비스, 삼성전자, 셀트리온의 주식 봉차트 데이터가 순서대로 출력됨을 확인할 수 있다.

다음 포스트에서는 조금 더 복잡한 데이터 크롤링을 다루어 보겠다.

위 포스트는 Kyeongrok Kim님의 데이터 크롤링 예시를 실습해보고, 이를 간단히 정리한 것임을 밝힙니다.