어제 배운 내용을 활용하여 한국은행 통계 openapi에 접속해 봅시다.
https://ecos.bok.or.kr/api/#/DevGuide/DevSpeciflcation 아래에서 API 접속 양식을 확인하실 수 있습니다.
서비스 이름 | 와이 | 통계검색 | API 서비스 이름 |
---|---|---|---|
인증키 | 와이 | 견본 | 한국은행에서 발급한 Open API 인증키 |
요청 유형 | 와이 | XML | 결과 값 파일 형식 – xml, json |
언어 분류 | 와이 | ~에 | 결과 언어 – kr(한국어), en(영어) |
시작된 요청 수 | 와이 | 하나 | 모든 결과의 시작 번호 |
마감된 요청 수 | 와이 | 10 | 모든 결과의 끝 번호 |
통계표 코드 | 와이 | 200Y001 | 통계표 코드 |
주다 | 와이 | ㅏ | 기간(년:A, 반기:S, 분기:Q, 월:M, 반월:SM, 일:D) |
시작일 찾기 | 와이 | 2015년 | 검색 시작일(기간에 맞는 형식으로 입력: 2015, 2015Q1, 201501, 20150101 등) |
종료 날짜 찾기 | 와이 | 2021년 | 검색 시작일(주기에 맞는 형식으로 입력: 2021, 2021Q1, 202101, 20210101 등) |
깃허브와 달리 URL을 /로 구분하고 키워드만 입력하면 간단히 접근할 수 있다.
물론 인증키를 받아야 합니다.
통계표 코드는 통계표를 검색합니다.
https://ecos.bok.or.kr/api/#/DevGuide/StatisticalCodeSearch 체크인 할 수 있습니다
get 메서드를 사용하여 샘플에 액세스합니다.
import requests as rq
gdp = rq.get('https://ecos.bok.or.kr/api/StatisticSearch/XYPOYKDP47WYCIRCVWP6/json/kr/1/10/200Y001/A/2012/2021/10101/?/?/?')
print('Response Code', gdp.status_code)
key = 'XYPOYKDP47WYCIRCVWP6'
Response Code 200
액세스를 정상적으로 확인했습니다.
원하는 정보를 지금 얻으십시오. 예를 들어, 저는 오후 8시부터 9시까지 월간 주식 거래를 받았습니다.
stock_key = '901Y055'
stock_url = f'https://ecos.bok.or.kr/api/StatisticSearch/{key}/json/kr/1/10/{stock_key}/M/202001/202112/S22B/?/?/?'
stock = rq.get(stock_url)
print(stock.status_code)
stock_dict = stock.json()
print(stock_dict('StatisticSearch')('row')(0))
200
{'STAT_CODE': '901Y055', 'STAT_NAME': '1.5.1.3. 투자자별 주식거래', 'ITEM_CODE1': 'S22B', 'ITEM_NAME1': '매수 1)', 'ITEM_CODE2': 'VO', 'ITEM_NAME2': '거래량', 'ITEM_CODE3': None, 'ITEM_NAME3': None, 'ITEM_CODE4': None, 'ITEM_NAME4': None, 'UNIT_NAME': '천주 ', 'TIME': '202001', 'DATA_VALUE': '13096066'}
자료 잘 받았습니다.
이 중 우리가 관심을 두는 정보는 “TIME”과 “DATA_VALUE”이므로 이 중 하나만 선택하여 데이터 프레임에 넣자.
%matplotlib inline
import matplotlib as plt
import datetime as dt
stock_df = pd.DataFrame(stock_dict('StatisticSearch')('row'))
stock_df = stock_df(('TIME', 'DATA_VALUE'))
stock_df('TIME') = stock_df('TIME').astype(int)
stock_df('DATA_VALUE') = stock_df('DATA_VALUE').astype(int)
print(stock_df)
stock_df.plot()
TIME DATA_VALUE
0 202001 13096066
1 202002 13959767
2 202003 17091025
3 202004 21045121
4 202005 16206497
5 202006 19863704
6 202007 18866787
7 202008 17643124
8 202009 19606897
9 202010 15705577
플롯은 나중에 시각화를 다룰 것이므로 그때 정리하겠습니다.
다른 정보를 얻으려면 아래 코드와 같이 루프를 사용하십시오.
import requests as rq
key = 'XYPOYKDP47WYCIRCVWP6'
stock_key = '901Y055'
stock_key_strings = ('S22AA', 'S22AB', 'S22AC', 'S22AD', 'S22BA', 'S22BB', 'S22BC')
for x in stock_key_strings:
temp = rq.get(f'https://ecos.bok.or.kr/api/StatisticSearch/{key}/json/kr/1/10/{stock_key}/M/202001/202112/{x}/?/?/?')
print(temp.status_code)
temp_dict = temp.json()
stock_full.append(temp_dict('StatisticSearch')('row'))
200
200
200
200
200
200
200
어쨌든 좋은 수익. 그러나 모든 코드에 데이터가 있는 것은 아니므로 예외 처리가 필수적입니다.
크롤링 및 스크래치
웹 크롤링 대 웹 스크래핑 웹 사이트 데이터를 이해하고 웹 사이트 데이터를 수집하는 데 사용되는 두 가지 데이터 마이닝 개념인 웹 크롤링 및 스크래핑에 대해 알아보겠습니다.
웹 크롤러 또는 웹 스파이 또는 크롤러라고 하는 프로그램은 웹에서 콘텐츠 및 기타 데이터를 자동으로 검색하고 인덱싱합니다.
이를 통해 불특정 URL과 도메인을 몰라도 데이터를 수집할 수 있습니다.
예를 들어, 검색 엔진은 페이지를 인덱싱하고 검색 결과에 표시할 수 있도록 웹을 크롤링합니다.
스크래핑에서는 인터넷에서 원시 데이터를 수집하고 검사합니다.
이 작업은 도구를 사용하여 수동 또는 자동으로 수행할 수 있습니다.
최소한 스크래핑을 하려면 도메인을 알아야 합니다(특정 웹 사이트를 대상으로 하기 때문에).
크롤러는 URL을 수집하고 각 특정 페이지의 전체 콘텐츠를 인덱싱하고 인덱싱된 데이터를 데이터베이스에 저장합니다.
스크래핑을 통해 먼저 대상 웹 사이트를 결정하고 HTML 파일을 요청 및 수신한 다음 이 문서에서 필요한 데이터를 추출합니다.
크롤링은 웹 페이지를 찾아 인덱싱하고 스크래핑은 해당 페이지에서 데이터를 추출합니다.
따라서 일반적으로 인터넷에서 데이터를 효율적으로 추출하기 위해서는 두 가지를 결합해야 합니다.
HTML 문서를 가져오려면 URL을 캡처해야 하는데 이는 쉬운 작업이 아닙니다.
Google과 같은 주요 검색 엔진은 크롤링된 페이지에 대한 색인을 생성할 때 “서비스 약관”과 같은 콘텐츠를 개별적으로 검토할 수 없습니다.
따라서 로봇을 제외하기 위한 robots.txt 표준 프로토콜이 탄생했습니다.
봇은 인덱싱을 시작하기 전에 먼저 웹 상단에 있는 robots.txt 파일을 확인하고 여기에 지정된 프로토콜에 따라 작동합니다.
경우에 따라 파일에 Disallow:가 없으면 다운로드 가능한 것으로 해석됩니다.
Reuter의 뉴스 기사를 살펴보겠습니다.
먼저 robots.txt를 확인하십시오. https://www.reuters.com/robots.txt
robots_allow.txt에 대한 www.reuters.com 금지: //key-developments/article/
사용자 에이전트: * 금지: /finance/stocks/option 금지: /finance/stocks/financialHighlights 금지: /search 금지: /site-search/ 금지: /beta 금지: /designtech* 금지: /featured-optimize 금지: / energy-test 허용하지 않음: /article/beta 허용하지 않음: /sponsored/previewcampaign 허용하지 않음: /sponsored/previewarticle 허용하지 않음: /test/ 허용하지 않음: /commentary 허용하지 않음: /news/archive/commentary 허용하지 않음: /brandfeatures/venture-capital* 허용하지 않음: / 저널리스트/ 허용하지 않음: /assets/siteindex 허용하지 않음: /article/api/
페이지 디렉토리: https://www.reuters.com/arc/outboundfeeds/sitemap-index/?outputType=xml 페이지 디렉토리: https://www.reuters.com/arc/outboundfeeds/news-sitemap-index/?outputType=xml 페이지 디렉토리: https://www.reuters.com/sitemap_video_index.xml 페이지 디렉토리: https://www.reuters.com/brandfeature/sitemap
사용자 에이전트: Pipl 허용하지 않음: /
지금부터 분석해 보겠습니다.
다음 코드를 사용하여 특정 사용자 에이전트가 특정 URL에 액세스할 수 있는지 확인할 수 있습니다.
import urllib.robotparser as rbpsr
rp = rbpsr.RobotFileParser()
rp.set_url("https://reuters.com/robots.txt")
rp.read()
rp.can_fetch(useragent="*", url="https://reuters.com/sitemap.xml")
True
이제 사이트맵도 사용해 봅시다.
sitemaps = rp.site_maps()
sitemaps
('https://www.reuters.com/arc/outboundfeeds/sitemap-index/?outputType=xml',
'https://www.reuters.com/arc/outboundfeeds/news-sitemap-index/?outputType=xml',
'https://www.reuters.com/sitemap_video_index.xml',
'https://www.reuters.com/brandfeature/sitemap')
여기에서 loc에 대한 링크가 뉴스 기사임을 알 수 있습니다.
이제 XML 파서를 사용해 봅시다.
import xmltodict as xtd
import requests as rq
sitemaps = rp.site_maps()
url = sitemaps(0)
sitemaps = xtd.parse(rq.get(url).text)
sitemaps('sitemapindex')('sitemap')
sitemap_urls = (sitemap('loc') for sitemap in sitemaps('sitemapindex')('sitemap'))
('https://www.reuters.com/arc/outboundfeeds/sitemap/?outputType=xml',
'https://www.reuters.com/arc/outboundfeeds/sitemap/?outputType=xml&from=100',
'https://www.reuters.com/arc/outboundfeeds/sitemap/?outputType=xml&from=200',
...
'https://www.reuters.com/arc/outboundfeeds/sitemap/?outputType=xml&from=9500')
위와 같이 사이트맵 URL만 추출이 가능합니다.
다음은 다음과 같이 상위 url을 선택하고 그 안에 있는 메시지 url만 추출하는 코드입니다.
response = rq.get(sitemap_urls(0))
news_dict = xtd.parse(response.text)
news_urls = (news('loc') for news in news_dict('urlset')('url'))
news_urls(:5)
('https://www.reuters.com/world/europe/russian-offensive-eastern-ukraine-focused-bakhmut-2023-02-28/',
'https://www.reuters.com/world/asia-pacific/rust-belt-province-got-old-before-it-got-rich-much-china-will-2023-02-28/',
'https://www.reuters.com/business/saudis-sabic-posts-94-drop-q4-net-profit-lower-average-sales-prices-2023-02-28/',
'https://www.reuters.com/business/retail-consumer/french-retailer-casinos-sales-growth-slows-fourth-quarter-2023-02-28/',
'https://www.reuters.com/business/bayer-sees-lower-2023-operating-profit-cost-inflation-2023-02-28/')
뉴스 기사 URL만 캡처 및 추출할 수 있습니다.
크롤링이 완료되면 이러한 기사를 스크랩할 수 있도록 텍스트 형식으로 저장합니다.
Jupyter Lab에서 Datas 폴더를 만들고 다음 코드를 실행합니다.
%%time
#session 추상화
session = rq.Session()
#앞 5개의 링크만 가져온다.
ㅠ
for url in news_urls(:5):
file = url.split('/')(-2) + '.html'
response = session.get(url)
if response.ok:
with open("datas/"+file, "w+b") as f:
f.write(response.text.encode("utf-8"))
else:
print(f"error with URL : {url}")
CPU times: user 104 ms, sys: 47.2 ms, total: 151 ms
Wall time: 5.04 s
다시 읽으려면 os를 호출하고 listdir()로 파일 이름을 나열하십시오.
import os
path="./datas/"
files = (path + file for file in os.listdir(path))
files
('./datas/rust-belt-province-got-old-before-it-got-rich-much-china-will-2023-02-28.html',
'./datas/bayer-sees-lower-2023-operating-profit-cost-inflation-2023-02-28.html',
'./datas/french-retailer-casinos-sales-growth-slows-fourth-quarter-2023-02-28.html',
'./datas/russian-offensive-eastern-ukraine-focused-bakhmut-2023-02-28.html',
'./datas/.ipynb_checkpoints',
'./datas/saudis-sabic-posts-94-drop-q4-net-profit-lower-average-sales-prices-2023-02-28.html')
with open(files(2), "r") as f:
html = f.read()
beautifulsoup로 HTML을 파싱할 수 있습니다.
페이지를 방문하여 검사 기능으로 원하는 부품을 선택하십시오. 제목을 예로 들어봤습니다.
from bs4 import BeautifulSoup as bsp
soup = bsp(html, 'html.parser')
title = soup.select_one('#main-content > article > div.article__main__33WV2 > div.article__content__6hMn9 > header > div > div > h1')
print(title.text)
French retailer Casino's sales growth slows in fourth quarter
다음 명령을 사용하여 액세스할 수도 있습니다.
soup.h1
<h1 class="text__text__1FZLe text__dark-grey__3Ml43 text__medium__1kbOh text__heading_3__1kDhc heading__base__2T28j heading__heading_3__3aL54 article-header__title__3Y2hh" data-testid="Heading">French retailer Casino's sales growth slows in fourth quarter</h1>
soup.h1.text
"French retailer Casino's sales growth slows in fourth quarter"
이제 전체 텍스트를 가져오도록 합시다.
r = soup.select('div > p')
r = (x.text for x in r)
r
('PARIS, Feb 28 (Reuters) - French retailer Casino (CASP.PA) said group sales slowed in the fourth quarter of 2022, as a robust performance in Latin America was offset by weakness in the domestic market, where same-store sales at its Geant hypermarkets fell 6.2%.',
'The company, which has been facing concerns over high debts and low cash flow, reports its full year earnings on March 10.',
"Casino, which also controls Brazil's Grupo Pao de Acucar (PCAR3.SA), said group sales for the fourth quarter reached 9.155 billion euros ($9.7 billion), a 4.4% rise on a same store basis but a deceleration from 5.4% growth in the third quarter.",
'In France alone, sales rose just 0.1% on a same store basis after rising 3.9% in the third quarter.',
'($1 = 0.9447 euros)',
'Our Standards: The Thomson Reuters Trust Principles.',
"Oil prices were steady in Asian trade on Tuesday, supported by hopes a solid economic rebound in China will drive up fuel demand, offsetting worries about further U.S. interest rate hikes potentially hurting demand in the world's biggest economy.",
"Reuters, the news and media division of Thomson Reuters, is the world’s largest multimedia news provider, reaching billions of people worldwide every day. Reuters provides business, financial, national and international news to professionals via desktop terminals, the world's media organizations, industry events and directly to consumers.",
'Build the strongest argument relying on authoritative content, attorney-editor expertise, and industry defining technology.',
'The most comprehensive solution to manage all your complex and ever-expanding tax and compliance needs.',
'The industry leader for online information for tax, accounting and finance professionals.',
' Access unmatched financial data, news and content in a highly-customised workflow experience on desktop, web and mobile.',
' Browse an unrivalled portfolio of real-time and historical market data and insights from worldwide sources and experts.',
'Screen for heightened risk individual and entities globally to help uncover hidden risks in business relationships and human networks.',
'All quotes delayed a minimum of 15 minutes. See here for a complete list of exchanges and delays.',
'© 2023 Reuters. All rights reserved')
import가 제대로 안 되는 것 같아서 HTML 표준에 대해 좀 더 알아야 할 것 같습니다.