티스토리 뷰
전자공시 API (MFC XML)
========================
추가>
2020.01.21 현재 기준 OPEN API서비스 도메인이 http://dart.fss.or.kr 에서 http://opendart.fss.or.kr 로 변경 예정으로 시범서비스 이후 2020.04.01 부터 openDart 로만 서비스 한다고 함.
========================
윈도우10, VisualStudio2017 Community 버전 기준으로 64비트, 멀티바이트로 프로젝트 만듬.
msxml6.dll 혹은 6 이하 버전의 msxmlX.dll 파일이 없으면, MS XML파서를 MSDN 에서 다운로드해서 설치해야한다. (인터넷 익스플로러가 설치된 PC에서 MSXML 지원한는거 같음)회사코드 084180 의 전자공시 제목에서 '전환사채'로 검색해서 찾아지면 화면 출력하고 끝낸다.
====== 주의점
아래 코드에서 94행 pDoc->loadXML(xml) 가 FALSE를 반환 하는 오류나면, 49행 do ~ while 루프에서 XML 코드를 정상적으로 읽어 오지 못한 원인이 크다.
HTTP 서버와 Client 연결이 계속 유지하는것이 아니라 한번에 읽어올 수 있는 크기를 얻고(InternetQueryDataAvailable()), 그 크기 만큼 반복해서 읽어와야 한다. (InternetReadFile())
한번만 읽어 오면 가끔 pDoc->loadXML() 에서 오류가 발생한다.
꼭, 데이터 용량이 적어 한번에 전부 읽어 올 수 있더라도 do ~ while 로 반복해서 읽어와야 한다.
그래서 do~while 루프 안에 51행 처럼 InternetQueryDataAvailable(hurl, &dwAvailableSize, 0, 0); 코드를 둬야 한다.
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 |
#include <Wininet.h> // HTTP 용 (FTP에도 필요)
#pragma comment(lib, "wininet.lib") // 이게 없으면 링크에러 난다.
#define _XML_BUFFER_SIZE 5000
////// XML
// C:/Windwos\system32 에 dll 파일 있음
#import <msxml6.dll> // InternetExplorer 에서 지원
using namespace MSXML2;
////// XML
void Convert_UTF8_to_ASCII(CString &parm_src_string);
void CMFCRESTTelegramDlg::OnBnClickedButtonMfcdart()
{
// HTTP 서버로 부터 XML 코드를 읽어온다.
CString strDart인증키 = TEXT("8c921==================c219850d13");
CString strCompanyCode = TEXT("084180");
int nType = 1; //
CString strURL = TEXT("http://dart.fss.or.kr/api/search.xml?auth=") + strDart인증키;
strURL += TEXT("&crp_cd=") + strCompanyCode + TEXT("&start_dt=19990101");
if (nType == 0)
strURL += TEXT("&dsp_tp=");
else
strURL += TEXT("&dsp_tp=I"); // i (대문자)
HINTERNET hInet = InternetOpen(TEXT("HTTP-POST"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInet == NULL)
{
AfxMessageBox(TEXT("InternetOpen() 호출 실패!!!"));
return;
}
CString strURL_UTF8;
AsciiToUTF8(strURL, strURL_UTF8);
HINTERNET hurl = InternetOpenUrl(hInet, strURL, NULL, 0, 0, 0);
if (hurl == NULL)
AfxMessageBox(TEXT("전자공시 조히 전송 실패!!!"));
//=================
DWORD dwAvailableSize;// = 512;
DWORD dwRead;
DWORD dwReadOffset = 0;
char result_buff[_XML_BUFFER_SIZE] = { 0. };
BOOL bExitFlag = FALSE;
do
{
BOOL bResult = InternetQueryDataAvailable(hurl, &dwAvailableSize, 0, 0); // HTTP 서버와 연결상태 유지되는 것이 아니라 일어올수 있는 데이터 수를 얻는다.
BOOL b = InternetReadFile(hurl, result_buff + dwReadOffset, dwAvailableSize, &dwRead); // HTTP 로 요청한 결과인 xml 을 dwAvailableSize 만큼 반복해서 read_buff 로 읽어온다.
dwReadOffset += dwRead;
if (dwReadOffset >= _XML_BUFFER_SIZE)
{
bExitFlag = TRUE;
break;
}
} while (dwRead != 0);
InternetCloseHandle(hurl);
InternetCloseHandle(hInet);
if (dwReadOffset + dwAvailableSize >= _XML_BUFFER_SIZE)
{
CString str;
str.Format(TEXT("_XML_BUFFER_SIZE =%d \n\r버퍼 크기를 늘려 주세요!!!"), _XML_BUFFER_SIZE);
AfxMessageBox(str);
return;
}
if (dwReadOffset == 0) // 아무 값도 받지 못한 경우
return;
CString parm_src_string(result_buff);
Convert_UTF8_to_ASCII(parm_src_string); // 전자공시 서버로 부터 받은 XML 이 UTF-8 라서 한글이 깨지므로 ASCII 로 변환한다.
// 여기서 코드변환 하지 않으면 글씨가 깨져 xml 포맷 에러가 난다.
// 아래 코드는 HTTP 서버로 부터 읽어온 XML 을 파싱한다.
_bstr_t xml = parm_src_string.AllocSysString();
//--------- XML
//출처: http://khie74.tistory.com/1169521455 [광수의 일본(日本)과 IT이야기]
CoInitialize(NULL);
CString str종목명, str검색어 = TEXT("전환사채"), str공시제목;
MSXML2::IXMLDOMDocument2Ptr pDoc = NULL;
MSXML2::IXMLDOMNamedNodeMapPtr pNodeMap = NULL;
MSXML2::IXMLDOMNodeListPtr pNodeList = NULL;
HRESULT hResult = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
if (!pDoc)
return; // DOMDocument인스턴스 생성 실패
if (pDoc->loadXML(xml) == FALSE) // 웹에서 읽어온 XML 을 로드한다.
{
//xmlDoc.load("books.xml"); // 파일을 읽음
if (pDoc->parseError->errorCode != 0) {
auto myErr = pDoc->parseError;
BSTR str = myErr->reason;
CString sstr = xml;
AfxMessageBox(CString(str) + TEXT("\r\n") + sstr);
}
else {
//currNode = xmlDoc.documentElement.childNodes.item(1);
//WScript.Echo(currNode.xml);
}
pDoc.Release();
CoUninitialize();
return; // XML파싱 실패
}
//pDoc->xml;
bExitFlag = FALSE;
pNodeList = pDoc->selectNodes(L"result"); // 제일 상위 노드를 지정한다.
if (pNodeList) {
MSXML2::IXMLDOMNodePtr pNode = pNodeList->Getitem(0);
MSXML2::IXMLDOMNodeListPtr pNodeList = pNode->GetchildNodes(); // 자식노드
if (pNodeList) {
MSXML2::IXMLDOMNodePtr pNode2 = NULL;
while ((pNode2 = pNodeList->nextNode())) // 자식노드 순환
{
CString nodeName = pNode2->GetnodeName();
if (!nodeName.Compare(TEXT("list"))) // list 노드 찾기
{
MSXML2::IXMLDOMNodeListPtr pNodeList2 = pNode2->GetchildNodes();
MSXML2::IXMLDOMNodePtr pNodeList2Child = NULL;
while (pNodeList2Child = pNodeList2->nextNode()) // list 자식노드
{
CString nodeName = pNodeList2Child->GetnodeName();
if (!nodeName.Compare(TEXT("crp_nm"))) // 회사코드, crp_nm : 회사명
str종목명 = pNodeList2Child->Gettext().GetBSTR();
if (!nodeName.Compare(TEXT("rpt_nm")))
{
str공시제목 = pNodeList2Child->Gettext().GetBSTR();
if (!str공시제목.Find(str검색어))
{
bExitFlag = TRUE;
AfxMessageBox(str종목명 + TEXT(" : ") + str공시제목);
break;
}
}
}
if (bExitFlag == TRUE) // 원하는 정보 찾으면 loop 탈출
break;
/*
LPCCH szDecodeParam = str.GetBuffer(0);
WCHAR wzDecodeParam[1000] = { 0, };
int nLen = MultiByteToWideChar(CP_UTF8, 0, szDecodeParam, strlen(szDecodeParam), NULL, NULL);
MultiByteToWideChar(CP_UTF8, 0, szDecodeParam, strlen(szDecodeParam), wzDecodeParam, nLen); // http://duzi077.tistory.com/27
b = wzDecodeParam;
CString strr(b); // UTF-8 to UICODE ?
*/
}
}
}
}
pDoc.Release();
CoUninitialize();
//--------- XML
}
void Convert_UTF8_to_ASCII(CString &parm_src_string)
{
// UTF8 코드로 된 문자열을 유니코드 형식의 문자열로 변경하기 위해 필요한 크기를 얻는다.
int temp_length = MultiByteToWideChar(CP_UTF8, 0, parm_src_string, -1, NULL, 0);
if (temp_length > 0) {
// 변환된 유니코드를 저장할 공간을 할당한다.
BSTR unicode_str = SysAllocStringLen(NULL, temp_length);
// 유니 코드로 변환한다.
MultiByteToWideChar(CP_UTF8, 0, parm_src_string, -1, unicode_str, temp_length);
parm_src_string = unicode_str;
// 유니코드 형식의 문자열을 저장하기 위해 생성했던 메모리를 삭제한다.
SysFreeString(unicode_str);
}
else parm_src_string.Empty();
} |
cs |
<실행>