위키피디아 한국어 페이지에서 "평화의 소녀상"을 검색하면 다음과 같은 화면이 나타난다. 해당 URL을 requests 모듈을 이용하여 접속하고, html 소스를 가져온다. 

 

위키피디아 검색 결과 페이지

 

BeautifulSoup 클래스의 find( ) 메소드에 HTML 요소의 태그 이름(‘img’)을 전달하면, 해당 태그 부분을 찾아서 객체로 return 해준다. find( ) 명령은 HTML 문서에서 가장 처음으로 만나는 태그를 한 개 찾는다. 앞의 위키피디아 화면에서 가장 먼저 나오는 사진(img 태그)은 "주한 일본 대사관 앞 평화비"라는 설명이 붙어 있는 사진이다. 

 

"평화의 소녀상, 속초"라는 설명이 있는 사진을 나타내는 ‘img’ 태그를 선택하려면, attrs 매개변수에 해당 태그에만 해당하는 고유의 속성을 추가해야 한다. 개발자 도구를 이용하여 해당 태그를 확인할 수 있는데, alt 속성 값으로 이미지 소스 URL 값을 갖는다. 이 속성을 find( ) 메소드의 attrs 매개변수에 입력하는 방식으로, 특정 태그를 선택할 수 있다. 

 

import requests
from bs4 import BeautifulSoup

url = "https://ko.wikipedia.org/wiki/%ED%8F%89%ED%99%94%EC%9D%98_%EC%86%8C%EB%85%80%EC%83%81"
resp = requests.get(url)
html_src = resp.text

soup = BeautifulSoup(html_src, 'html.parser')
                    
photo_first = soup.find(name='img')
print(photo_first)
print("\n")

photo_sockcho = soup.find(name='img', attrs={'src':'//upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/220px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg'})
print(photo_sockcho)

 

 

실행 결과는 다음과 같다. 두 개의 img 태그를 찾아서 내용을 확인할 수 있다. 이처럼, find( ) 메소드는 특정한 태그를 하나만 찾는 경우에 사용되고, 메모리 관리 측면이나 실행 시간에서 유리하다는 장점을 갖는다. 

 

<img alt="" class="thumbimage" data-file-height="3000" data-file-width="4000" decoding="async" height="173" src="//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG/230px-Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG/345px-Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/3/36/Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG/460px-Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG 2x" width="230"/>

 

 

<img alt="" class="thumbimage" data-file-height="2268" data-file-width="4032" decoding="async" height="124" src="//upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/220px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/330px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/440px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg 2x" width="220"/>

 

웹사이트에서 정보를 가져올 때, 기본적인 윤리규정과 저작권 등 법률적 이슈에 대하여 유의하여야 한다. 

 

위키피디아(https://ko.wikipedia.org/wiki/)는 로봇 배제 표준에 대하여 웹 사이트에 로봇이 접근하는 것을 방지하기 위한 규약으로, 일반적으로 접근 제한에 대한 설명을 robots.txt에 기술한다.” 라고 말한다. 무분별한 서버 접속은 서버의 안정성을 해치기도 하고, 대부분의 웹 사이트들은 로봇배제표준을 제정하여 게시하고 있다. 

 

 

권고안이기는 하지만 웹 페이지에 접근하기 전에 반드시 로봇 배제 표준을 확인하고 가이드라인을 준수할 필요가 있다.또한, 사이트에 반복적으로 접속하는 행위는 사이트를 공격하는 행위로 받아들여질 수 있기 때문에 서버에 부담을 주지 않는 선에서 제한하는 것이 필요하다. 

 

마지막으로취득한 데이터를 임의로 배포하거나 변경하는 등의 행위는 저작권을 침해할 가능성이 있기 때문에, 로봇배제표준 이외에 저작권 규정을 준수해야 한다. 

 

로봇배제표준을 확인하는 가장 간단한 방법은 웹브라우저 주소창에 "홈페이지 메인 주소/robots.txt"라고 입력하는 것이다.

 

네이버(www.naver.com)의 경우는 다음과 같다. 네이버는 기본적으로 스크래핑(크롤링) 봇의 접근을 금지하고 있다. 

다만, 루트 디렉터리(www.naver.com/)에 대해서는 허용하고 있는 것으로 볼 수 있다. $ 표시는 웹 주소의 마지막을 뜻하기 때문에, 루트 디렉터리의 경우 Allow하고 있다고 해석할 수 있다. 

 

로봇배제표준

로봇배제표준에 대한 상세 설명은 다음 위키피디아 링크를 참조하기 바란다. 

https://ko.wikipedia.org/wiki/%EB%A1%9C%EB%B4%87_%EB%B0%B0%EC%A0%9C_%ED%91%9C%EC%A4%80

 

파이썬 requests 모듈은 웹 서버에 요청을 보내고 응답 객체를 받는데 사용한다. 응답 객체 중에서 HTML 소스 코드를 얻는 방법을 알아본다. 

 

import requests

url = "https://www.wikipedia.org/"
resp = requests.get(url)

html = resp.text
print(html[:1000])

1. requests 모듈을 불러온다.

 

2. 위키피디아 웹 주소를 변수에 저장한다. 

 

3. 웹 서버에 GET 요청을 보내고, 서버가 응답한 객체를 변수에 저장한다.

 

4. text 속성에 HTML 소스코드가 들어 있다. 

 

5. 문자열로 저장되어 있는 HTML 소스코드를 출력한다. 앞에서 1000개의 글자를 지정하여 일부 소스코드만 확인한다. 


<실행 결과 > HTML 소스코드 확인

<!DOCTYPE html>
<html lang="mul" class="no-js">
<head>
<meta charset="utf-8">
<title>Wikipedia</title>
<meta name="description" content="Wikipedia is a free online encyclopedia, created and edited by volunteers around the world and hosted by the Wikimedia Foundation.">
<![if gt IE 7]>
<script>
document.documentElement.className = document.documentElement.className.replace( /(^|\s)no-js(\s|$)/, "$1js-enabled$2" );
</script>
<![endif]>
<!--[if lt IE 7]><meta http-equiv="imagetoolbar" content="no"><![endif]-->
<meta name="viewport" content="initial-scale=1,user-scalable=yes">
<link rel="apple-touch-icon" href="/static/apple-touch/wikipedia.png">
<link rel="shortcut icon" href="/static/favicon/wikipedia.ico">
<link rel="license" href="//creativecommons.org/licenses/by-sa/3.0/">
<style>
.sprite{background-image:url(portal/wikipedia.org/assets/img/sprite-3f2e1b8f.png);background-image:linear-gradient(transparent,transparent),url(portal/wikipedia.org/assets/img/sprite-3f2e1b8f.svg);background

 

네이버 등 포털 사이트에서 제공하는 주식시세(주가정보) 데이터를 가져와서, 그래프로 간략하게 그려보는 예제를 만들어 봅니다. 처음에는 코드 한줄 한줄 전부 이해하는 것보다는 예제 코드를 최대한 타이핑해보면서 실행 결과를 확인해 보면서 흥미를 갖는 것이 중요합니다.

 

지난 포스팅에서 설명드린 pandas.read_html 함수를 사용해서 네이버 주식 시세 테이블을 dataframe으로 가져옵니다. 아래 그림처럼 주식시세가 웹페이지 여러 페이지에 걸쳐 있기 때문에, 페이지를 한장씩 넘어가면서 pandas.read_html 함수를 사용하여 표를 여러 번 나누어서 읽어야 합니다.

 

 

 

 

 

우선, 필요한 패키지(pandas, datetime)를 불러온다. 네임스페이스를 사용하여 pd, dt 등 약칭으로 부른다

 

 
 import pandas as pd 
# 데이터프레임을 다루는 패키지

 import datetime as dt  # 시간을 다루는 패키지

 import matplotlib.pyplot as plt  # 그래프 시각화 패키지
 from matplotlib import style 

 

 

 

이제 본격적으로 웹 스크래핑을 처리하는 함수(function)을 정의합니다. url 주소에 들어 있는 종목코드(6자리)와 주식시세 페이지 번호(page)를 유의해서 살펴보시기 바랍니다.

 

 

 
 def read_stock_price_page(stock_code, page_num):
    '''
    네이버 주식시세 페이지에 접속하여 table을 dataframe으로 가져와서 정리
    '''
    target_url = ('http://finance.naver.com/item/sise_day.nhn?code='+ stock_code + '&page=' + str(page_num))
    data = pd.read_html(target_url)
    data = data[0]
    data.columns = ['날짜', '당일종가', '전일종가', '시가', '고가', '저가', '거래량']
    price_data = data.dropna(axis=0, how='any')
    price_data = price_data.drop(price_data.index[0])
    price_data = price_data.reset_index(drop=True)
    price_data['날짜'] = pd.to_datetime(price_data['날짜'], format='%Y/%m/%d')
    return price_data

 

 

 

오늘부터 과거로 소급해서 일정한 기간 동안의 주가 정보만을 가져오는 기능을 추가해 봅니다. days_limit이라는 변수를 함수 인자로 받아서, datetime 시간 클래스를 활용하여 기간을 계산합니다. 앞서 정의한 read_stock_price_page( ) 함수를 사용하여 매 페이지의 주가 정보를 가져 옵니다.

 

 

 
 def stock_price_pages_to_df(code, days_limit=30):
    '''
    오늘부터 days_limit 일수 만큼 이전 날짜 주가를 가져온다.
    '''
   
    df_list_price = []
    page = 1
    while True:
        try:   
            data = read_stock_price_page(code, page)
            time_limit = dt.datetime.now() - data['날짜'][0] 
            if time_limit.days > days_limit: break  
            df_list_price.append(data)                    
            page = page + 1
   
        except: break
    df_price = pd.concat(df_list_price)
    df_price = df_price.reset_index(drop=True)

    return df_price

 

 

 

앞서 정의한 stock_price_pages_to_df( )함수에 종목코드와 기간(날짜)을 인자로 입력해서 dataframe 형태로 정리된 데이터를 return값으로 전달받습니다.

 

 

 
 # 함수를 실행하여 KH바텍(060720)의 과거 30일 주가정보를 가져온다.    
 stock_code = '060720'
 days_limit = 30
 df = stock_price_pages_to_df(stock_code, days_limit)

 

 

 

df 변수에 할당된 데이터프레임을 아래와 같이 잘 정리가 되었습니다.

 

 

날짜

당일종가

전일종가

시가

고가

저가

거래량

0

2018-07-02 0:00:00

10100

600

10850

10900

10000

137977

1

2018-06-29 0:00:00

10700

300

10550

10900

9990

170253

2

2018-06-28 0:00:00

10400

500

10900

10950

10150

155769

3

2018-06-27 0:00:00

10900

100

10800

11050

10500

133548

4

2018-06-26 0:00:00

10800

350

10900

11000

10700

63039

5

2018-06-25 0:00:00

11150

150

11400

11450

11000

55519

6

2018-06-22 0:00:00

11300

100

11250

11450

10750

134805

7

2018-06-21 0:00:00

11200

350

11350

11750

11200

133002

8

2018-06-20 0:00:00

11550

250

11200

11600

10900

308596

9

2018-06-19 0:00:00

11300

700

11850

11950

11300

180656

10

2018-06-18 0:00:00

12000

1400

13400

13400

12000

309787

11

2018-06-15 0:00:00

13400

50

13600

13600

12900

201376

12

2018-06-14 0:00:00

13450

250

13200

13700

13150

347451

13

2018-06-12 0:00:00

13200

1250

12200

13300

12050

558148

14

2018-06-11 0:00:00

11950

0

12000

12250

11950

62293

15

2018-06-08 0:00:00

11950

0

11950

12200

11800

59258

16

2018-06-07 0:00:00

11950

200

12200

12300

11900

49088

17

2018-06-05 0:00:00

12150

250

11800

12250

11800

42485

18

2018-06-04 0:00:00

11900

0

11900

12200

11700

25171

19

2018-06-01 0:00:00

11900

100

11800

12100

11750

32062

 

 

 

 

matplotlib 패키지를 사용하면, 그래프를 쉽게 그릴 수 있습니다. ggplot 스타일을 지정하고, 날짜를 x축으로 하고 당일종가 그래프를 그리게 됩니다.

 

 

 
 # 주식 시세(당일종가) 그래프를 그린다.
 style.use('ggplot')   #그래프 스타일 지정
 plt.plot(df.날짜, df.당일종가.astype(int))  
 plt.show()

 

  

 

필요한 패키지(pandas, datetime)를 불러온다. 네임스페이스 pd, dt, plt등 약칭으로 간단하게 부른다.

ggplot 스타일로 그래프가 그려집니다. KH바텍은 6월 한 달 동안 주가가 급등 후에 급락하는 패턴을 보이네요.

 

늘은 인터넷에서 CSV 파일을 다운로드받아서, 필요한 정보만을 추출해서 정리하는 작업을 해보겠습니다.

 

코딩을 이제 배우기 시작하는 직장인의 입장에서 파이썬 문법 기초부터 차근차근 배워나가는 것도 필요하지만, 당장 실무에 적용할 수 있는 파이썬 라이브러리 위주로 집중 학습하는 것도 좋은 방법이라고 생각합니다.

 

이런 관점에서 지난 번 포스팅(http://pydata.tistory.com/1)에서 사용했던 판다스(pandas) 모듈을 계속 활용합니다. 지난 번에는 판다스(pandas) 모듈의 read_html 함수를 사용하여 html 웹 페이지에 있는 모든 표를 가져오는 방법을 배웠는데요. 이번에는 read_csv 함수를 사용하여 CSV 파일을 읽어들이는 과정을 만나보겠습니다.  

 


 

CSV 파일 다운로드

  

오늘 활용할 데이터는 KOSPI 상장 주식 종목 리스트입니다. 한국증권거래소(KRX) 홈페이지에 들어가면 상장종목현황(http://marketdata.krx.co.kr/mdi#document=040601)을 제공합니다. KOSPI와 KOSDAQ 종목을 구분하고 있고, 다운받을 컬럼 항목을 선택할 수도 있습니다. 파일 형식은 Excel과 CSV를 지원하는데 우리는 CSV 부분을 클릭해서 CSV 파일을 PC에 저장합니다. 이때 파일명을 'kospi_stock_code.csv'로 바꾸고 파이썬(Python) 실행파일이 위치한 폴더에 저장합니다. 

 

 

<KRX 한국거래소 상장종목 현황>

 

 

<'kospi_stock_code.csv' 파일>

 


 

 

파이썬 실행 코드 작성

다운로드한 CSV 파일을 살펴 보면, 위와 같이 표(table) 형식으로 정리된 자료입니다. 파이썬에서 CSV 파일의 데이터에 접근하기 위해서는 파이썬이 인식할 수 있는 자료형으로 변환해주어야 합니다. 판다스(pandas)에서는 데이터프레임(dataframe)이라는 자료형을 주로 사용하기 때문에, read_csv 함수로 CSV 파일을 읽어 오면 데이터프레임(dataframe)으로 저장됩니다. 실행코드는 주석을 제외하고 세 줄이면 충분합니다.

 

# 판다스 모듈 불러오기 (편의 상, pd라는 이름으로 사용)
import pandas as pd

 

# csv 파일을 해석하여 dataframe으로 변환하고, stock_data 변수에 저장
stock_data = pd.read_csv('kospi_stock_code.csv')

 

#종목코드 컬럼만 선택하여 stock_code 변수에 저장
stock_code = stock_data[['종목코드', '기업명']]

 

 

결과(stock_code) 확인하기

 

 

 

 

stock_code 변수에 저장된 데이터프레임(dataframe) 내용을 확인합니다. 제일 왼쪽 컬럼(column)의 숫자는 인덱스(index)라고 부르며, '종목코드'와 '기업명'은 컬럼(columns)명이라고 합니다. 

 

데이터프레임에서 컬럼(열)을 선택할 때는 데이터프레임['컬럼명'] 형식으로 지정하는데, 종목코드만 선택하고 싶을 때는 stock_code['종목코드']라고 입력합니다. 로우(행)을 선택하려면 데이터프레임.iloc[인덱스]라고 입력합니다. stock_code.iloc[1]라고 입력하면 AJ렌터카에 대한 정보만을 선택해서 볼 수 있습니다.    

 

 

 

 

요약하며...

 

코드를 모아서 정리하면 모두 3줄입니다. 다음 포스팅에서는 종목코드를 이용하여 개별 주식 종목에 대한 정보를 가져오는 방법에 대해서 알아보겠습니다. 

+ Recent posts