티스토리 뷰
인터넷 HTML 소스 얻기
VisualStudio2017 프로젝트 유니코드 문자집합
인터넷 검색해서 얻은 HTML소스에 한글이 포함되어 있으면, 멀티코드 문자집합에서는 한글 깨짐 없이 잘 되던것이 유니코드 문자집합으로 변경하니 한글이 깨진다.
http://petra.tistory.com/1252 코드 162행에서 사용한 Convert_UTF8_toASCII() 에서 UTF8->UNICODE->ASCII 바꿔주는 함수에서 UTF8->UNICODE 로 코드 수정한다.
문제는 멀티바이트일때와 유니코드일때 각각 다른 함수 인자의 데이터형이 필요해서 #ifdef _UINICODE 로 구분해서 각각의 함수가 사용하도록 하여 MFC 프로젝트 문자집합이 어느것이라도 한글 깨짐없이 얻게된다.
웹에서 얻은 HTML소스를
유니코드 일때는 CStringA 에 저장하고,
멀티바이트 일때는 CString 에 저장한다.
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 |
class CDlg : public CDialogEx
{
...
public:
#ifdef _UNICODE
void Convert_UTF8_to_UNICODE(CStringA &parm_src_string);
#else
void Convert_UTF8_to_UNICODE(CString &parm_src_string);
#endif
};
#ifdef _UNICODE
void CDlg::Convert_UTF8_to_UNICODE(CStringA &parm_src_string) // 유니코드용
#else
void CDlg::Convert_UTF8_to_UNICODE(CString &parm_src_string) // 멀티바이트용
#endif
{
// 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();
}
_정보 CDlg::인터넷검색(CString str번호)
{
// TODO: 여기에 구현 코드 추가.
//CString str전화번호 = TEXT("0424719988"); //TEXT("15883366"); //
HANDLE mh_wait_event = CreateEvent(NULL, TRUE, FALSE, TEXT("Test"));
//http://www.tipssoft.com/bulletin/board.php?bo_table=update&wr_id=719
CString html_url_string, page_name_string;
//html_url_string.Format(TEXT("http://www.whoiscall.net/?phone=%s"), str전화번호);
html_url_string = TEXT("www.samsung.com"); // 도메인명만 온다
page_name_string = TEXT("/sec");
// 인터넷 세션을 연다.
HINTERNET h_session = ::InternetOpen(TEXT("Test2"),
PRE_CONFIG_INTERNET_ACCESS, NULL, INTERNET_INVALID_PORT_NUMBER, 0);
// 사용자가 입력한 URL에 해당하는 사이트에 접속한다.
HINTERNET h_connect = ::InternetConnect(h_session, html_url_string,
INTERNET_INVALID_PORT_NUMBER, TEXT(""), TEXT(""), INTERNET_SERVICE_HTTP, 0, 0);
char error_count = 0;
// 페이지 정보를 요청한다.
HINTERNET h_http_file = ::HttpOpenRequest(h_connect, TEXT("GET"), page_name_string,
HTTP_VERSION, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
#ifdef _UNICODE
CStringA strHtml;
#else
CString strHtml;
#endif
BOOL request_flag = ::HttpSendRequest(h_http_file, NULL, 0, 0, 0);
if (request_flag == TRUE) {
char buffer[1025]; // buffer_size + 1
DWORD read_byte = 0, buffer_size = 1024;
// 최대 1024 크기만큼 웹페이지 정보를 읽는다.
while (::InternetReadFile(h_http_file, buffer, buffer_size, &read_byte)) {
if (read_byte == 0)
break;
// 읽은 정보(문자열)의 끝에 NULL(EOL)을 명시한다.
buffer[read_byte] = 0;
// 1024단위로 읽어들인 정보를 str 변수에 계속 추가한다.
strHtml += buffer;
if (read_byte < 1024) {
// 1024 보다 적은 경우를 읽은 경우, 렉에 의해서 못읽는 경우도 있기 때문에
// 최대 5번까지 재시도한다. 재시도를 하는 경우 50ms의 지연시간을 부여하여
// 전송을 기다리도록 한다.
error_count++;
if (error_count > 5) break;
else
::WaitForSingleObject(mh_wait_event, 50);
ZeroMemory(buffer, buffer_size);
}
else error_count = 0;
}
// 읽어들인 웹페이지 파일을 에디트 컨트롤에 제대로 출력하기 위해서
// 개행문자를 보정한다.
// strHtml.Replace("\n", "\r\n"); // 빈줄생겨 무시 20190110
// 해당 페이지 정보를 얻기 위해 사용한 핸들을 닫는다.
::InternetCloseHandle(h_http_file);
}
// 인터넷을 사용하기 위해서 연결한 핸들과 세션 핸들을 닫는다.
::InternetCloseHandle(h_connect);
::InternetCloseHandle(h_session);
CloseHandle(mh_wait_event);
Convert_UTF8_to_UNICODE(strHtml); // 홈페이지에서 받은 strHtml에서 한글이 깨지므로 UTF8->UniCode 로 변환한다.
CString strLine(strHtml);
int curPos, i;
i = curPos = 0;
CString strCol[11 + 1];
strLine.Tokenize(_T("<"), curPos); // '<' 구분자로 행 구분
while (i < 11 + 1) // 검색결과 상호가 나올때까지 반복
strCol[i++] = strLine.Tokenize(_T("<"), curPos); // "<" 문자열 구분자로 찾음, 문자열 구분자는 " ,.!"과 같이 여러개 올 수 있다.
strLine = strCol[11].Trim(); // 아래 HTML소스 중 143행 한줄을 얻음.
curPos = i = 0;
strLine.Tokenize(_T(","), curPos);
while (i < 3 + 1) // 상호가 있는 행에서 ',' 구분자로 다시 찾음
strCol[i++] = strLine.Tokenize(_T(","), curPos); // "," 문자열 구분자로 찾음
CString str상호 = strCol[1].Trim();
if (str상호.IsEmpty() == TRUE)
str상호 = TEXT("<미등록 번호>");
_정보 정보;
정보.str상호 = str상호;
정보.str번호 = str번호;
return 정보;
/*
0:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1:<html xmlns="http://www.w3.org/1999/xhtml">
2:<head>
3:<title>1588-3366 / +8215883366</title>
4:
5:<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6:<meta http-equiv="Content-language" content="ko,en" />
7:<meta http-equiv="Cache-Control" content="No-Cache">
8:<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
9:<META name="Author-Date(Date)" content="2014-09-18 오전 3:41:03">
10:<meta name="Author" content="15883366">
11:<meta name="Keywords" content="1588-3366,15883366,삼성전자서비스 아산센터,충청남도 아산시 모종동 371-10 디지털프라자 모종점 1층,충청남도 아산시 모종로 9-17">
*/
} |
cs |
(한글 코드변환 코드는 www.tipssoft.com 참조)
프로젝트 문자집합에 따라 인수의 데이터형을 바꾸는 코드가 복잡해서, template 변수로 고쳐 쓴다
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 |
class CDlg : public CDialogEx
{
...
template <class T>
void Convert_UTF8_to_UNICODE(T &parm_src_string);
};
template <class T> // 반드시 CStringA, CString 형으로만 사용해야 한다.
void CDlg::Convert_UTF8_to_UNICODE(T &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();
}
_정보 CDlg::인터넷검색(CString str번호)
{
...
#ifdef _UNICODE
CStringA strHtml;
#else
CString strHtml;
#endif
...
Convert_UTF8_to_UNICODE(strHtml);
...
}
|
cs |
간단히 아래와 같이 1~5행을 7행으로 바꾼다.
1
2
3
4
5
6
7 |
#ifdef _UNICODE
CStringA strHtml;
#else
CString strHtml;
#endif
CStringA strHtml; |
cs |
수정된 전체 코드>
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 |
class CDlg : public CDialogEx
{
...
void Convert_UTF8_to_UNICODE(CStringA &parm_src_string);
};
void CDlg::Convert_UTF8_to_UNICODE(CStringA &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();
}
_정보 CDlg::인터넷검색(CString str번호)
{
...
CStringA strHtml;
...
Convert_UTF8_to_UNICODE(strHtml);
...
} |
cs |