[Python] Daum 주가 가져오기
아시는 분은 아시겠지만, 얼마전부터 다음 파이낸스의 layout이 변경되었습니다. 이에 따라 python에서 주가를 가져오기 위해서는 코드 변경이 필요합니다. 그동안 공부했던 내용을 바탕으로 주가를 가져오는 코드를 정리해봅니다. 참고로 저는 개발자가 아니므로 내용에 전문성이 떨어지거나 비체계적인 접근법을 이용할 수 있습니다.
주가를 어떻게 가져올까?
다음파이낸스에서 주가를 제공하는 창은 여러가지가 있습니다. 그중에서 저는 차트를 택해보았습니다. 차트가 가장 장기간의 주가 DATA를 제공하고 있다는 판단에서 였습니다. 물론 차트가 아닌 다른 창에서도 주가를 가져올 수 있습니다.
차트 창은 다음과 같습니다.
페이지의 형식에 따라 주가를 가져오는 방법은 다른데, 기존의 HTML페이지는 고정된 정보를 가지고 있어서 페이지 주소만으로 주가 정보를 직접 가져올 수 있었습니다. 즉, 뷰티풀숲(Beautiful soup) 등의 HTML문서를 분석해주는 라이브러리를 이용해 정보를 가져올 수 있다는 말입니다. 하지만 변경된 페이지에서는 JavaScript를 이용해 동적으로 정보를 가져기 때문에 주소 정보 만으로는 데이터를 수집할 수 없습니다. 이 때 이용할 수 있는 방법은 바로 시행착오법입니다. 페이지를 돌아다니면서 각각의 정보를 파악하고, 내게 필요한 정보를 가져오는 방법입니다.
다음 주가 차트 창을 예로 들어보겠습니다. 차트 창에서 개발자모드로 진입(크롬의 경우 F12를 누릅니다)한 후 F5를 눌러 페이지를 새로고침 합니다. 개발자 모드에 이런저런 내용들이 주르륵 나타납니다. 각종 탭들중에서 Network > XHR 부분을 눈여겨 봐야 합니다.
각 라인을 누르면 여러가지 정보를 볼 수 있는데, 먼저 확인할 곳은 Preview입니다. Preview는 각 라인이 실행된 결과물을 보여주므로 클릭해보면서 원하는 DATA가 들어있는 곳을 찾습니다. 마지막라인을 클릭해보니 날짜와 주가 DATA가 들어있는 것이 보입니다. 참고로 {}안에 들어있는 데이터 형식을 웹에서는 JSON이라고 부르며, 파이썬에서는 Dictionary라고 부릅니다.
이제 해당 DATA가 어떤 요청에 의해 return 된 것인지 확인 하기 위해 Headers부분을 살펴봅니다. Headers는 다음의 정보를 담고 있습니다.
- General : 요청 URL / 요청형식 (POST 또는 GET)
Request URL: http://finance.daum.net/api/charts/A069500/days?limit=200&adjusted=true
Request Method: GET
Status Code: 200 OK
Remote Address: 211.231.100.72:80
Referrer Policy: no-referrer-when-downgrade
- Response Headers : 요청된 결과값의 Header
Cache-Control: max-age=0, private, must-revalidate
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Wed, 07 Nov 2018 04:45:51 GMT
ETag: W/"9cd001e7a9874fb2f751fb32403eb41b"
Set-Cookie: _dfs=MVE1bTFyWjc2eGlRRDkrMWVOWjczS2hCTCtESkcremtkYkYzdXFzYkFxc2dkcVV2ZzZnL2NFZUEvbFdXcm5HWEJLbnEvT1ppME9IYUN4cDQwR0RSc1E9PS0tSU5YS05xUkNIQThvOE02VHB6NmVXQT09--04e853987ce3a4712a20f937750b7a425e21a121; domain=.daum.net; path=/; expires=Wed, 07 Nov 2018 05:45:51 -0000; HttpOnly
Transfer-Encoding: chunked
Vary: Accept-Encoding
Vary: Origin
X-Request-Id: 4c9361ed-8732-4e5f-950d-bdefae6c80b2
X-Runtime: 0.512505
- Request Headers : 요청할 Header 정보
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Cookie: GS_font_Name_no=0; GS_font_size=16; _ga=GA1.3.937989519.1493034297; webid=bb619e03ecbf4672b8d38a3fcedc3f8c; _ga=GA1.2.937989519.1493034297; _gid=GA1.2.215330840.1541556419; KAKAO_STOCK_RECENT=[%22A069500%22]; recentMenus=[{%22destination%22:%22chart%22%2C%22title%22:%22%EC%B0%A8%ED%8A%B8%22}%2C{%22destination%22:%22current%22%2C%22title%22:%22%ED%98%84%EC%9E%AC%EA%B0%80%22}]; TIARA=C-Tax5zAJ3L1CwQFDxYNxe-9yt4xuvAcw3IjfDg6hlCbJ_KXLZZhwEPhrMuSc5Rv1oty5obaYZzBQS5Du9ne5x7XZds-vHVF; webid_sync=1541565778037; _gat_gtag_UA_128578811_1=1; _dfs=VFlXMkVwUGJENlVvc1B3V2NaV1pFdHhpNTVZdnRZTWFZQWZwTzBPYWRxMFNVL3VrODRLY1VlbXI0dHhBZlJzcE03SS9Vblh0U2p2L2V2b3hQbU5mNlE9PS0tcGI2aXQrZ21qY0hFbzJ0S1hkaEhrZz09--6eba3111e6ac36d893bbc58439d2a3e0304c7cf3
Host: finance.daum.net
If-None-Match: W/"23501689faaaf24452ece4a039a904fd"
Referer: http://finance.daum.net/quotes/A069500
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
- Query String Parameters : 요청할 파라미터
limit: 200
adjusted: true
파이썬에서 요청해보기
위에서 수집한 정보를 Python의 requests 모듈에 담아 요청해봅니다.
import requests
url = 'http://finance.daum.net/api/charts/A069500/days?limit=200&adjusted=true'
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
'Connection': 'keep-alive',
'Cookie': 'GS_font_Name_no=0; GS_font_size=16; _ga=GA1.3.937989519.1493034297; webid=bb619e03ecbf4672b8d38a3fcedc3f8c; _ga=GA1.2.937989519.1493034297; _gid=GA1.2.215330840.1541556419; KAKAO_STOCK_RECENT=[%22A069500%22]; recentMenus=[{%22destination%22:%22chart%22%2C%22title%22:%22%EC%B0%A8%ED%8A%B8%22}%2C{%22destination%22:%22current%22%2C%22title%22:%22%ED%98%84%EC%9E%AC%EA%B0%80%22}]; TIARA=C-Tax5zAJ3L1CwQFDxYNxe-9yt4xuvAcw3IjfDg6hlCbJ_KXLZZhwEPhrMuSc5Rv1oty5obaYZzBQS5Du9ne5x7XZds-vHVF; webid_sync=1541565778037; _gat_gtag_UA_128578811_1=1; _dfs=VFlXMkVwUGJENlVvc1B3V2NaV1pFdHhpNTVZdnRZTWFZQWZwTzBPYWRxMFNVL3VrODRLY1VlbXI0dHhBZlJzcE03SS9Vblh0U2p2L2V2b3hQbU5mNlE9PS0tcGI2aXQrZ21qY0hFbzJ0S1hkaEhrZz09--6eba3111e6ac36d893bbc58439d2a3e0304c7cf3',
'Host': 'finance.daum.net',
'If-None-Match': 'W/"23501689faaaf24452ece4a039a904fd"',
'Referer': 'http://finance.daum.net/quotes/A069500',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
r = requests.get(url, headers = headers)
복잡해보일 수도 있지만, General에 있던 url정보와 Request.Headers의 정보를 그대로 입력한 후 requests.get함수에 담아서 요청하는 간단한 코드 입니다. 만약 general에서 메소드가 post로 지정되어 있다면 requests.post 함수에 담아서 요청하면 됩니다.
요청결과는 r.text를 통해서 확인할 수 있습니다. 날짜와 숫자들이 많은 걸 보니 DATA를 잘 불러온 것 같습니다.
함수로 만들기
이제 다른 주식의 주가도 불러올 수 있도록 함수로 만들어 봅니다. url 부분과 headers에서 공통적으로 주식 코드를 볼 수 있으므로 이부분을 변경하면 될 것 같습니다. 추가로 url부분의 limit부분은 가져올 주가의 갯수를 의미하는 것 같으니 이부분도 함수에 포함해봅니다. 마지막으로 가져온 DATA를 보기 좋게 DataFrame 형식으로 변경하기로 합니다.
import requests
import json
import pandas as pd
def get_price(code, n):
# DATA를 불러오는 부분 입니다.
url = 'http://finance.daum.net/api/charts/A%s/days?limit=%d&adjusted=true'%(code, n)
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
'Connection': 'keep-alive',
'Cookie': 'GS_font_Name_no=0; GS_font_size=16; _ga=GA1.3.937989519.1493034297; webid=bb619e03ecbf4672b8d38a3fcedc3f8c; _ga=GA1.2.937989519.1493034297; _gid=GA1.2.215330840.1541556419; KAKAO_STOCK_RECENT=[%22A069500%22]; recentMenus=[{%22destination%22:%22chart%22%2C%22title%22:%22%EC%B0%A8%ED%8A%B8%22}%2C{%22destination%22:%22current%22%2C%22title%22:%22%ED%98%84%EC%9E%AC%EA%B0%80%22}]; TIARA=C-Tax5zAJ3L1CwQFDxYNxe-9yt4xuvAcw3IjfDg6hlCbJ_KXLZZhwEPhrMuSc5Rv1oty5obaYZzBQS5Du9ne5x7XZds-vHVF; webid_sync=1541565778037; _gat_gtag_UA_128578811_1=1; _dfs=VFlXMkVwUGJENlVvc1B3V2NaV1pFdHhpNTVZdnRZTWFZQWZwTzBPYWRxMFNVL3VrODRLY1VlbXI0dHhBZlJzcE03SS9Vblh0U2p2L2V2b3hQbU5mNlE9PS0tcGI2aXQrZ21qY0hFbzJ0S1hkaEhrZz09--6eba3111e6ac36d893bbc58439d2a3e0304c7cf3',
'Host': 'finance.daum.net',
'If-None-Match': 'W/"23501689faaaf24452ece4a039a904fd"',
'Referer': 'http://finance.daum.net/quotes/A069500',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
headers['Referer'] = 'http://finance.daum.net/quotes/A%s'%code
r = requests.get(url, headers = headers)
# DATA를 보기 좋게 편집하는 부분 입니다.
data = json.loads(r.text)
df = pd.DataFrame(data['data'])
df.index = pd.to_datetime(df['candleTime'])
return df
데이터 부분이 좀 잘리긴 했지만 잘 출력 됩니다.
주의사항
각 싸이트에는 크롤링가능 범위를 robots.txt로 알려주고 있습니다. daum에서는 원칙적으로 크롤링을 허용하지 않고 있습니다. 따라서 대량의 정보를 크롤링하는 경우 제재를 받을 수 있습니다.
Robots.txt란? https://namu.wiki/w/robots.txt
짱짱맨 호출에 응답하여 보팅하였습니다.
짱짱맨은 저자응원 프로그램입니다. 더 많은 저자 분들에게 더 큰 혜택을 드리고자 스파임대 스폰서를 받고 있습니다. 스폰서 참여방법과 짱짱맨 프로그램에 관해서는 이 글을 읽어 주세요. 기업형 예비증인 북이오(@bukio)가 짱짱맨 프로그램을 운영하고 있습니다. 여러분의 증인 보팅은 큰 힘이 됩니다. Vote for @bukio