요즈음 공공기관에서 제공하는 API를 활용경험이 면접 등에서 당연히 질문하고 있어서 나도 경험해 보고자 간단한 연동을 해 봤다.
이왕이면 쓸모있는 것을 하기 위해 주식시세를 연동하여 내가 보유하고 있는 주식의 주식시세를 챠트로 보여주는 것으로 하기로 했다.
먼저 공공데이터포털에서 “주식”으로 검색하여 API로 제공되는 것을 확인하니, 36건이나 나왔다. 난 간단하게 내가 보유한 주식의 일별 시세만 알면 되기 때문에 “금융위원회_주식시세정보”를 선택하고 활용신청을 했다. 그러면 바로 인증키를 보여준다.
Open API 명세확인 가이드를 클릭하면 어떤식으로 BaseUrl와 호출주소가 연동되는지 보여주고 자세한 설명까지 보여준다. 이것은 공공API를 통해 직접 데이터포털에 호출할 때 공통으로 사용하는 방법이다. 다만, 각 기관에서 서비스를 제공하는 경우에는 호출주소가 별도 있지 않고 URL만 제공된다.
상세기능을 선택하면 직접 사이트에서 테스트로 요청하고 결과값을 확인해 볼 수도 있다.
인증키를 설정하고 주식시세정보 서비스 중에서 /getStockPriceInfo를 선택하여 “OpenApi실행준비”를 클릭하면 변수창에 직접 값을 입력할 수 있게 된다. 다만 인증키 설정할때 인코딩되지 않은 인증키를 사용해야 한다. 기관에서 직접 서비스를 제공할 때에는 인코딩된 서비스키를 사용해야 한다.
itmsNm값으로 “삼성전자”만 입력하고 OpenAPI호출를 실행하면 결과가 XML형태로 나온다. 최근 일별 시세가 10개가 조회되며, 전체 데이터가 510개이며, 첫번째 페이지라는 결과요약정보를 확인할 수 있다.
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?><response><header><resultCode>00</resultCode><resultMsg>NORMAL SERVICE.</resultMsg></header><body><numOfRows>10</numOfRows><pageNo>1</pageNo><totalCount>1</totalCount><items><item><basDt>20220119</basDt><srtnCd>005930</srtnCd><isinCd>KR7005930003</isinCd><itmsNm>삼성전자</itmsNm><mrktCtg>KOSPI</mrktCtg><clpr>76300</clpr><vs>-700</vs><fltRt>-.91</fltRt><mkp>76500</mkp><hipr>76900</hipr><lopr>76100</lopr><trqu>10598290</trqu><trPrc>810150634900</trPrc><lstgStCnt>5969782550</lstgStCnt><mrktTotAmt>455494408565000</mrktTotAmt></item></items></body></response>
일단 공공API로 연동하여 데이터가 어떻게 나오는지를 확인했으면 본격적으로 호출하는 것과 XML를 파싱하고 저장하는 프로그램을 만들어야 한다.
나는 일단 간단하게 java로 만들었다.
public static void main(String argv[]) throws SQLException {
db.connect();
if (getStockList(conn) != 0) return;
}
private static int getStockList(Connection conn) {
String query = "select isincd from stockinfo where own like ?";
...
try {
PreparedStatement pstmt = conn.prepareStatement(query);
String condition = "Y";
pstmt.setString(1, condition);
rs = pstmt.executeQuery();
while(rs.next()) {
isinCd = rs.getString(1);
StringBuffer stringBuffer = getStockPrice(isinCd, frdt, todt);
if (stringBuffer.length() == 0) continue;
deleteStockPrice(conn, isinCd, frdt, todt);
insertStockPrice(conn, stringBuffer);
}
} catch (Exception e) {
...
}
return 0;
}
private static StringBuffer getStockPrice(String isinCd, String frdt, String todt) {
BufferedReader in = null;
StringBuffer strBuffer = new StringBuffer();
try {
String urlStr = "https://api.odcloud.kr/api/GetStockSecuritiesInfoService/v1/getStockPriceInfo?";
urlStr += "serviceKey="+serviceKey;
urlStr += "&beginBasDt="+frdt;
urlStr += "&endBasDt="+todt;
urlStr += "&isinCd="+isinCd;
URL obj = new URL(urlStr);
HttpURLConnection con = (HttpURLConnection)obj.openConnection();
con.setRequestMethod("GET");
in = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String line;
while((line = in.readLine()) != null) {
strBuffer.append(line);
}
} catch(Exception e) {
...
}
return strBuffer;
}
private static int insertStockPrice(Connection conn, StringBuffer strBuffer) {
// XML Parsing + db insert
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
InputStream istream = new ByteArrayInputStream(strBuffer.toString().getBytes("utf-8"));
Document doc = dBuilder.parse(istream);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("item");
int result = 0;
PreparedStatement ps = conn.prepareStatement("INSERT INTO StockPriceInfo (" +
"basDt, srtnCd, isinCd, itmsNm, mrktCtg, clpr, vs, fltRt, mkp, hipr, lopr, trqu, trPrc, lstgStCnt, mrktTotAmt)" +
" VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
String basDt = eElement.getElementsByTagName("basDt") .item(0).getTextContent();
...
ps.setString(1, basDt);
...
ps.addBatch();
}
}
ps.executeBatch();
ps.close();
} catch (Exception e) {
...
}
return 0;
}
조회하려는 회사 목록을 조회하고 회사별로 오픈API로 결과값을 가져와서 XML파싱을 하고 DB에 저장한다.
이클립스에서 개발은 잘 되었는데, 서버에 올려놓고 cron으로 실행해야 하는데 동작을 하지 않는다. 클래스패스가 적용되지 않아 db 연동을 위하 라이브러리를 찾지 못한다. 결국 실행시에 설정해야 하고 현재 위치를 포함해야 한다는 것을 알았다.
java -cp “.:/java/mysql-connector-java-8.0.28.jar” LoadStockPriceInfo
그리고 기존에 사용하던 주식정보를 보여주는 그래프와 연동을 했다. 6자리 주식 고유코드가 일치해서 뷰를 하나 만들어서 참조 테이블만 수정했더니, 잘 조회가 된다.
연초부터 수익률이 안좋다. 차를 사야 하는데, 자꾸 돈을 까먹고 있는중이다.






공공API로 호출시 XML형태로 결과가 나오지 않은 경우가 있다. 예를 들면 브라우저에서는 잘 나오는데, java로 호출하면 결과가 나오지 않는 경우가 있다.
conn.setRequestProperty(“Accept”, “application/xml”);
위와 같이 결과 값을 xml형태로 달라고 설정해야 한다. 브라우저에서는 xml으로 자동으로 설정되나 보다.
자세한 내용은 아래 사이트를 참고하시길..
Android Studio setRequestProperty 설명 및 설정
공공API로 주식을 가져오는 것은 실행시점에 보유중이라고 표시된 자료를 가져오기 때문에 비보유시간의 자료도 가져오게 된다. 이럴 경우 아래 SQL로 보유기간이 아닌 주식의 시세정보를 삭제할 수 있다. (mysql은 subquery로 삭제방법이 조금 다르다.)
—–
delete p
from stockin i, stockpriceinfo p
where i.code = p.srtncd
and p.basdt not between i.frdt and i.todt