Naver Korean Dictionary/English Dictionary Search Tool Operation Method and Source Code
The Naver Korean Dictionary/English Dictionary search tool operation method and source code are explained.
This is a continuation of the previous article.
Overview of Naver Korean Dictionary/English Dictionary Search Tool
1. Naver Korean Dictionary/English Dictionary Search Tool Operation Method and Precautions
A user makes a search request to the Naver service using a web browser, and the Naver server responds with a processing result for the request.
(For more information on how the web works, please read the Google search results article below.)
https://www.google.co.kr/search?q=web+action+method
Let's take a closer look at the search request and response of Naver's dictionary service.
1.1. Naver dictionary search request and response
There are several ways to check the contents exchanged with the server through a web browser, and here we will explain using Fiddler Web Debugger.
The following is the result of checking the request and response contents in Fiddler when searching for the word “sign up” in the Naver Korean dictionary.
- URL, Content-Type: You can check the contents below.
- Protocol: HTTPS
- Host: en.dict.naver.com
- URL: /api3/koko/search?query=%EA%B0%80%EC%9E%85&m=pc&hid=162470754628591300
- 여기에서 “%EA%B0%80%EC%9E%85″는 “가입”이 URL Encoding된 문자열이다.
- Request Header
- User-Agent, Cookie, etc. can be checked.
- Response contents
- Content-Type: application/json;charset=UTF-8
- You can see that the response contents are in json format and the character-set is encoded in UTF-8.
- Content-Length: 50814
- It can be seen that the contents of the response are 50,814 bytes, approximately 50KB.
- Content-Body: {“searchResultMap”:{“searchResultListMap”:{“WORD”:{“query”:”Join”, …
- It is a JSON string, and if you check it in the “JSON” tab, it has a hierarchical structure as follows.
- Content-Type: application/json;charset=UTF-8
1.2. Change the response result format (HTML -> JSON)
This tool does not use Naver Open API, but uses Web Request and Response methods.
Although not accurate, the format of the response results changed around December 2018. Prior to that, it was in HTML format, but at this time, when I accidentally checked it with Fiddler, I found that the response was changed to JSON format.
The first version of this tool was created when the response was in HTML format. I extracted the necessary items from HTML, but whenever Naver changed the HTML structure, it did not work properly, so I had to change the source code every time to match the changed HTML structure. Since the response result format was changed to JSON, it is working well without changing the source code.
1.3. Precautions for use
It is not possible to confirm whether Naver has officially announced that it provides dictionary search results in JSON format. Documentation of the structure of JSON also appears to be unpublished.
(If there is any news or data that has been released, please let us know in the comments.)
For this reason, it may suddenly not work one day, so please be careful.
2. Implementation
2.1. Overall flow summary
URL-encode the word to be searched for and execute the GetDataFromURL function to parse the fetched JSON search result to extract the necessary items.
Dim aWord As String, sBaseURL As String, sWord As String
aWord = "가입"
sBaseURL = "https://ko.dict.naver.com/api3/koko/search?query=%s" '기본 URL
sWord = URLEncodeUTF8(aWord) '검색어 URL Encoding
Dim sURL As String, sURLData As String, oParsedDic As Dictionary
sURL = Replace(sBaseURL, "%s", sWord) '기본 URL에 검색어 대입
sURLData = GetDataFromURL(sURL, "GET", "", "utf-8") 'URL에서 결과 가져오기
Set oParsedDic = JsonConverter.ParseJson(sURLData) 'JSON결과를 Dictionary로 변환
'JSON이 변환된 Dictionary에서 검색결과에 해당하는 항목 추출
'시작 Path: oParsedDic("searchResultMap")("searchResultListMap")("WORD")("items")
Let's take a look at the main functions.
2.2. URL Encoding (URLEncodeUTF8 source code)
Returns the search request URL as a URLEncoded string. The ADODB.Stream class is used.
Public Function URLEncodeUTF8( _
StringVal As String, _
Optional SpaceAsPlus As Boolean = False _
) As String
Dim bytes() As Byte, b As Byte, i As Integer, space As String
If SpaceAsPlus Then space = "+" Else space = "%20"
If Len(StringVal) > 0 Then
With New ADODB.Stream
.Mode = adModeReadWrite
.Type = adTypeText
.CharSet = "UTF-8"
.Open
.WriteText StringVal
.Position = 0
.Type = adTypeBinary
.Position = 3 ' skip BOM
bytes = .Read
End With
ReDim Result(UBound(bytes)) As String
For i = UBound(bytes) To 0 Step -1
b = bytes(i)
Select Case b
Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126
Result(i) = Chr(b)
Case 32
Result(i) = space
Case 0 To 15
Result(i) = "%0" & Hex(b)
Case Else
Result(i) = "%" & Hex(b)
End Select
Next i
URLEncodeUTF8 = Join(Result, "")
End If
End Function
To use the ADODB library, “Microsoft ActiveX Data Object 6.1 Library” must be referenced. on the excel screen Alt + F11 Just press the key and switch to the VBA Editor to add it.
2.3. Request & Get Response (GetDataFromURL function source code)
Use “WinHttp.WinHttpRequest” class to set request header and option information, visit search URL, and get result. Since it is a late binding method that creates objects with CreateObject, there is no need to add a library reference.
Function GetDataFromURL(strURL, strMethod, strPostData, Optional strCharSet = "UTF-8")
Dim lngTimeout
Dim strUserAgentString
Dim intSslErrorIgnoreFlags
Dim blnEnableRedirects
Dim blnEnableHttpsToHttpRedirects
Dim strHostOverride
Dim strLogin
Dim strPassword
Dim strResponseText
Dim objWinHttp
lngTimeout = 59000
strUserAgentString = "http_requester/0.1"
intSslErrorIgnoreFlags = 13056 ' 13056: ignore all err, 0: accept no err
blnEnableRedirects = True
blnEnableHttpsToHttpRedirects = True
strHostOverride = ""
strLogin = ""
strPassword = ""
Set objWinHttp = CreateObject("WinHttp.WinHttpRequest.5.1")
'--------------------------------------------------------------------
'objWinHttp.SetProxy 2, "xxx.xxx.xxx.xxx:xxxx", "" 'Proxy를 사용하는 환경에서 설정
'--------------------------------------------------------------------
objWinHttp.SetTimeouts lngTimeout, lngTimeout, lngTimeout, lngTimeout
objWinHttp.Open strMethod, strURL
If strMethod = "POST" Then
objWinHttp.SetRequestHeader "Content-type", "application/x-www-form-urlencoded; charset=UTF-8"
Else
objWinHttp.SetRequestHeader "Content-type", "text/html; charset=euc-kr"
End If
If strHostOverride <> "" Then
objWinHttp.SetRequestHeader "Host", strHostOverride
End If
objWinHttp.Option(0) = strUserAgentString
objWinHttp.Option(4) = intSslErrorIgnoreFlags
objWinHttp.Option(6) = blnEnableRedirects
objWinHttp.Option(12) = blnEnableHttpsToHttpRedirects
If (strLogin <> "") And (strPassword <> "") Then
objWinHttp.SetCredentials strLogin, strPassword, 0
End If
On Error Resume Next
objWinHttp.Send (strPostData)
objWinHttp.WaitForResponse
If Err.Number = 0 Then
If objWinHttp.Status = "200" Then
'GetDataFromURL = objWinHttp.ResponseText
GetDataFromURL = BinaryToText(objWinHttp.ResponseBody, strCharSet)
Else
GetDataFromURL = "HTTP " & objWinHttp.Status & " " & _
objWinHttp.StatusText
End If
Else
GetDataFromURL = "Error " & Err.Number & " " & Err.Source & " " & _
Err.Description
End If
On Error GoTo 0
Set objWinHttp = Nothing
End Function
2.4. Response (search result) JSON string
The Response (search result) JSON string contains quite a bit of information. It is difficult to see because there is no indentation and line separation. (partial excerpts)
{ "searchResultMap": { "searchResultListMap": { "WORD": { "query": "Join", "queryRevert": "", "items": [ { "rank": "1", "gdid": " 8800000f_4002c436c93d4bb38d3e58632fe00af0", "matchType": "exact:entry", "entryId": "4002c436c93d4bb38d3e58632fe00af0", "serviceCode": "1", "languageCode": "KOKO", "expTypeDictTypeForm": "word", "dict 2", "sourceDictnameKO": "Standard Korean Dictionary", "sourceDictnameOri": "Standard Korean Dict.", "sourceDictnameLink": "https://stdict.korean.go.kr/main/main.do", .. ."expEntry": "<strong>join</strong>", ... "destinationLink": "#/entry/koko/4002c436c93d4bb38d3e58632fe00af0", ... "meansCollector": [ { "partOfSpeech": "noun", "partOfSpeech2": "noun", "means": [ { "order": "1", "value": "Applying for a product to join an organization or organization or to provide a service.", ... "exampleOri": "<strong>join</strong> Application form.", ... }, { "order": "2", "value": "Newly inserted.", ... "exampleOri": "Any corrections made in the middle of the manuscript <strong>join</strong>has been found.", ... }, { "order": "3", "value": "Acts to be bound by the treaty without certification of the text. Legal community by allowing parties to become parties only by expression of intent...", ... "languageGroup": "Law", ... "exampleTrans": null, ... } ] } ], "similarWordList": [] , "antonymWordList": [ { "antonymWordName": "Leave", "antonymWordLink": "#/entry/koko/14e89175152b46569c2a2b6360e835ad" } ], "expAliasEntryAlwaysList": [], "expAliasGeneralAlwaysList": [ { "originLanguageValue": "加入" } ], ... }, { "rank": "2", "gdid": "881857e6_e12c4e3432cf458c929bd49c929fd80b", "matchType": "exact:entry", "entryId": "e12c4e3432cf458c929bd49c929fd80b", "serviceCode": "1 ", "languageCode": "KOKO", "expDictTypeForm": "Word", "dictTypeForm": "2", "sourceDictnameKO": "Urimalsaem", "sourceDictnameOri": "Urimalsaem", "sourceDictnameLink": "https: //opendict.korean.go.kr/main", ... "expEntry": "<strong>join</strong>", ... "destinationLink": "#/entry/koko/e12c4e3432cf458c929bd49c929fd80b", ... "meansCollector": [ { "partOfSpeech": "noun", "partOfSpeech2": "noun", "means": [ { "order": "", "value": "The addition of a new individual to a population. However, only objects that have reached a certain stage of development are applicable.", ... } ] } ], "similarWordList": [], "antonymWordList": [], ... }, ], "total": 96, "sectionType": "WORD", "revert": "", "orKEquery": null } } } }
2.5. JSON parser
You can extract the desired item from the JSON string using string functions (MID, INSTR, etc.), but the search is complicated and the code becomes very messy.
If implemented in Python, simply import the json module and use the json class. There are not many open libraries for VBA, but fortunately there is a JSON parser published on github, so I used it well.
https://github.com/VBA-tools/VBA-JSON
The source code of this JSON parser is 1,123 lines long, so it is not posted on the blog. If you need it, please check the source code at the URL above. A simple example using the JSON parser is as follows (code published on github above):
Dim Json As Object
Set Json = JsonConverter.ParseJson("{""a"":123,""b"":[1,2,3,4],""c"":{""d"":456}}")
' Json("a") -> 123
' Json("b")(2) -> 2
' Json("c")("d") -> 456
Json("c")("e") = 789
Debug.Print JsonConverter.ConvertToJson(Json)
' -> "{"a":123,"b":[1,2,3,4],"c":{"d":456,"e":789}}"
Debug.Print JsonConverter.ConvertToJson(Json, Whitespace:=2)
' -> "{
' "a": 123,
' "b": [
' 1,
' 2,
' 3,
' 4
' ],
' "c": {
' "d": 456,
' "e": 789
' }
' }"
2.6. Search button click event source code
This code is executed when the “Naver Dictionary Search” button is clicked on the “Dictionary Search” sheet. The following is implemented:
- Check if the options are set properly.
- A dictionary search is repeatedly executed for a search term and the result is displayed in a sheet.
- The displayed results are matchType, searchEntry, meaning, link, synonym, and antonym.
- If the “Stop Search” button is pressed during execution, the repetition stops.
Private Sub cmdRunDicSearch_Click()
Range("A1").Select
DoEvents
Dim bIsKorDicSearch As Boolean, bIsEngDicSearch As Boolean, sTargetDic As String
bIsKorDicSearch = chkKorDic.Value: bIsEngDicSearch = chkEngDic.Value
If (Not bIsKorDicSearch) And (Not bIsEngDicSearch) Then
MsgBox "검색 대상 사전중 적어도 1개는 선택해야 합니다", vbExclamation + vbOKOnly, "검색 대상 사전 확인"
Exit Sub
End If
Dim bIsMatchTypeExact As Boolean, bIsMatchTypeTermOr As Boolean, bIsMatchTypeAllTerm As Boolean '검색결과 표시 설정
bIsMatchTypeExact = chkMatchTypeExact.Value: bIsMatchTypeTermOr = chkMatchTypeTermOr.Value: bIsMatchTypeAllTerm = chkMatchTypeAllTerm.Value
If (bIsMatchTypeExact Or bIsMatchTypeTermOr Or bIsMatchTypeAllTerm) = False Then
MsgBox "검색결과 표시 설정중 적어도 하나는 선택해야 합니다.", vbExclamation + vbOKOnly, "확인"
Exit Sub
End If
If bIsKorDicSearch And Not bIsEngDicSearch Then sTargetDic = "국어사전"
If Not bIsKorDicSearch And bIsEngDicSearch Then sTargetDic = "영어사전"
If bIsKorDicSearch And bIsEngDicSearch Then sTargetDic = "국어사전, 영어사전"
Dim lMaxResultCount As Long
lMaxResultCount = CInt(txtMaxResultCount.Value)
If MsgBox("사전 검색을 시작하시겠습니까?" + vbLf + _
"대상 사전: " + sTargetDic + vbLf + _
"결과출력 제한개수: " + CStr(lMaxResultCount) _
, vbQuestion + vbYesNoCancel, "확인") <> vbYes Then Exit Sub
Dim i As Long, iResultOffset As Long
bIsWantToStop = False
DoEvents
Dim sWord As String, oKorDicSearchResult As TDicSearchResult, oEngDicSearchResult As TDicSearchResult
Dim oBaseRange As Range
Set oBaseRange = Range("검색결과Header").Offset(1, 0)
oBaseRange.Select
For i = 0 To 100000
If bIsWantToStop Then
MsgBox "사용자의 요청으로 검색을 중단합니다.", vbInformation + vbOKOnly, "확인"
Exit For
End If
If chkSkipIfResultExists.Value = True And _
oBaseRange.Offset(i, 1) <> "" Then GoTo Continue_For '이미 내용이 있으면 Skip
sWord = oBaseRange.Offset(i)
If sWord = "" Then Exit For
oBaseRange.Offset(i).Select
Application.ScreenUpdating = False
If bIsKorDicSearch Then '국어사전 검색결과 표시
oKorDicSearchResult = DoDicSearch(dtsKorean, sWord, bIsMatchTypeExact, bIsMatchTypeTermOr, bIsMatchTypeAllTerm, lMaxResultCount)
oBaseRange.Offset(i, 1).Select
With oKorDicSearchResult
oBaseRange.Offset(i, 1) = .sMatchType
oBaseRange.Offset(i, 2) = .sSearchEntry
oBaseRange.Offset(i, 3) = .sMeaning
If oKorDicSearchResult.sLinkURL <> "" Then
With ActiveSheet.Hyperlinks.Add(Anchor:=oBaseRange.Offset(i, 4), Address:=.sLinkURL, TextToDisplay:="네이버국어사전 열기: " & .sLinkWord)
.Range.Font.Size = 8
End With
End If
oBaseRange.Offset(i, 5) = .sSynonymList
oBaseRange.Offset(i, 6) = .sAntonymList
End With
End If
If bIsEngDicSearch Then '영어사전 검색결과 표시
oEngDicSearchResult = DoDicSearch(dtsEnglish, sWord, bIsMatchTypeExact, bIsMatchTypeTermOr, bIsMatchTypeAllTerm, lMaxResultCount)
'oBaseRange.Offset(i, 7).Select
With oEngDicSearchResult
oBaseRange.Offset(i, 7) = .sMatchType
oBaseRange.Offset(i, 8) = .sSearchEntry
oBaseRange.Offset(i, 9) = .sMeaning
If oKorDicSearchResult.sLinkURL <> "" Then
With ActiveSheet.Hyperlinks.Add(Anchor:=oBaseRange.Offset(i, 10), Address:=.sLinkURL, TextToDisplay:="네이버영어사전 열기: " & .sLinkWord)
.Range.Font.Size = 8
End With
End If
oBaseRange.Offset(i, 11) = .sSynonymList
oBaseRange.Offset(i, 12) = .sAntonymList
End With
End If
Application.ScreenUpdating = True
Continue_For:
DoEvents
Next i
MsgBox "사전 검색을 완료하였습니다", vbOKOnly + vbInformation
End Sub
2.7. Dictionary search (DoDicSearch source code)
This function sends a search request for one search word, receives the result, extracts the required item, and returns it.
- Parsing a JSON string into a Dictionary: line 49
- Extract matchType, searchEntry, meaning, link, synonym, antonym entry: lines 53 to 106
Const DICT_ROOT_URL_KO As String = "https://ko.dict.naver.com/"
Const DICT_BASE_URL_KO As String = "https://ko.dict.naver.com/api3/koko/search?query=%s"
Const DICT_ROOT_URL_EN As String = "https://en.dict.naver.com/"
Const DICT_BASE_URL_EN As String = "https://en.dict.naver.com/api3/enko/search?query=%s"
Public Enum DicToSearch
dtsKorean = 1
dtsEnglish = 2
dtsAll = 10
End Enum
Public Type TDicSearchResult
sWord As String
sMatchType As String
sSearchEntry As String
sMeaning As String
sLinkURL As String
sLinkWord As String
sSynonymList As String
sAntonymList As String
End Type
Public Function DoDicSearch(aDicToSearch As DicToSearch, aWord As String, _
bIsMatchTypeExact As Boolean, bIsMatchTypeTermOr As Boolean, bIsMatchTypeAllTerm As Boolean, _
aMaxResultCount As Long) As TDicSearchResult
Dim sDicRootURL As String, sBaseURL As String, sURL As String, sURLData As String, sWord As String, oDicSearchResult As TDicSearchResult
Dim oParsedDic As Dictionary
Dim oItem As Dictionary, oMeansCollector As Dictionary, oMeans As Dictionary
Dim oSimWords As Dictionary, oAntWord As Dictionary
Dim sPOS As String, sMeaning As String, sLinkURL As String, sLinkWord As String
Dim s유의어 As String, s유의어목록 As String, s반의어 As String, s반의어목록 As String
Dim sMatchType As String, sSearchEntry As String, sHandleEntry As String
Select Case aDicToSearch
Case dtsKorean
sDicRootURL = DICT_ROOT_URL_KO
sBaseURL = DICT_BASE_URL_KO
Case dtsEnglish
sDicRootURL = DICT_ROOT_URL_EN
sBaseURL = DICT_BASE_URL_EN
End Select
If aWord = "" Then Exit Function
sWord = URLEncodeUTF8(aWord)
sURL = Replace(sBaseURL, "%s", sWord)
sURLData = GetDataFromURL(sURL, "GET", "", "utf-8") 'URL에서 결과 가져오기
Set oParsedDic = JsonConverter.ParseJson(sURLData) 'JSON결과를 Dictionary로 변환
Dim lMatchIdx As Long: lMatchIdx = 0
Dim lResultCount As Long: lResultCount = 0
For Each oItem In oParsedDic("searchResultMap")("searchResultListMap")("WORD")("items")
lResultCount = lResultCount + 1
If (aMaxResultCount <> 0) And (lResultCount > aMaxResultCount) Then Exit For '결과출력 제한개수 초과시 Loop 종료
s유의어 = "": s반의어 = ""
lMatchIdx = lMatchIdx + 1
'If oItem("matchType") <> "exact:entry" Then Exit For
sHandleEntry = oItem("handleEntry")
Select Case oItem("matchType")
Case "exact:entry"
sLinkWord = sHandleEntry
sLinkURL = sDicRootURL + oItem("destinationLink")
If Not bIsMatchTypeExact Then GoTo Continue_InnerFor
Case "term:or"
If Not bIsMatchTypeTermOr Then GoTo Continue_InnerFor
Case "allterm:proximity:1.000000"
If Not bIsMatchTypeAllTerm Then GoTo Continue_InnerFor
Case Else
End Select
sMatchType = sMatchType + IIf(sMatchType = "", "", vbLf) & CStr(lMatchIdx) & ". " & oItem("matchType")
sSearchEntry = sSearchEntry + IIf(sSearchEntry = "", "", vbLf) & CStr(lMatchIdx) & ". " & sHandleEntry
For Each oMeansCollector In oItem("meansCollector")
'Debug.Print "품사: " & oMeansCollector("partOfSpeech")
sPOS = ""
If oMeansCollector.Exists("partOfSpeech") Then
If Not IsNull(oMeansCollector("partOfSpeech")) Then sPOS = oMeansCollector("partOfSpeech")
End If
For Each oMeans In oMeansCollector("means")
'Debug.Print "뜻: " & oMeans("value")
If oMeans.Exists("value") Then
If Not IsNull(oMeans("value")) Then _
sMeaning = sMeaning + IIf(sMeaning = "", "", vbLf) & CStr(lMatchIdx) & ". " & IIf(sPOS = "", "", "[" & sPOS & "] ") & RemoveHTML(oMeans("value"))
End If
Next oMeans
Next oMeansCollector
For Each oSimWords In oItem("similarWordList")
If oSimWords.Exists("similarWordName") Then _
s유의어 = s유의어 + IIf(s유의어 = "", "", ", ") & RemoveHTML(oSimWords("similarWordName"))
Next oSimWords
If s유의어 <> "" Then _
s유의어목록 = s유의어목록 & IIf(s유의어목록 = "", "", vbLf) & CStr(lMatchIdx) & ". " & sHandleEntry & ": " & s유의어
For Each oAntWord In oItem("antonymWordList")
If oAntWord.Exists("antonymWordName") Then _
s반의어 = s반의어 + IIf(s반의어 = "", "", ", ") & RemoveHTML(oAntWord("antonymWordName"))
Next oAntWord
If s반의어 <> "" Then _
s반의어목록 = s반의어목록 & IIf(s반의어목록 = "", "", vbLf) & CStr(lMatchIdx) & ". " & sHandleEntry & ": " & s반의어
Continue_InnerFor:
Next oItem
If sMeaning = "" Then
sMeaning = "#NOT FOUND#": sMatchType = sMeaning: sSearchEntry = sMeaning
End If
'결과값 반환
With oDicSearchResult
.sWord = aWord
.sMatchType = sMatchType
.sSearchEntry = sSearchEntry
.sMeaning = sMeaning
.sLinkWord = sLinkWord
.sLinkURL = Replace(sLinkURL, "#", "%23") 'Excel에서 #기호를 내부적으로 #20 - #20 으로 치환하는 것을 방지
.sSynonymList = s유의어목록
.sAntonymList = s반의어목록
End With
DoDicSearch = oDicSearchResult
End Function
Above, we looked at the operation method, precautions, and source code of this tool. Please leave comments from those who have used the tool, questions, and necessary features.
<< List of related articles >>







Absolutely with you it agree. It is an excellent idea. I support you.
_ _ _ _ _ _ _ _ _ _ _ _ _ _
Nekultsy Ivan dxvk github
Thanks a lot.
Please take a look other article in my blog ^^