DA(Data Architecture) 도구/네이버 국어,영어사전 검색 도구

네이버 국어사전, 영어사전 검색 도구 동작 방식과 소스코드 설명

ProDA 2021. 6. 26.

이 글은 새로운 블로그로 옮겼습니다. 5초후 자동으로 이동합니다.

▶ 새로운 블로그 주소: https://prodskill.com/

▶ 새로운 글 주소: https://prodskill.com/naver-korean-english-dictionary-search-tool-operation-sourcecode/

네이버 국어사전과 영어사전을 반복하여 검색할 수 있는 매크로 도구의 동작방식과 소스코드에 대해 설명한다.

이전 글에서 이어지는 내용이다.

2021.06.23 - [엑셀 & VBA/Tools] - 네이버 국어사전, 영어사전 검색 도구 사용 방법

 

네이버 국어사전, 영어사전 검색 도구 사용 방법

목차 1. 도구 개요 1.1. 필요성 네이버 국어사전과 영어사전을 검색하고 그 검색결과를 수작업으로 엑셀에 복사&붙여넣기를 반복해 본일이 있는가? 검색할 단어(또는 용어)가 몇 개 되지 않는다면

prodtool.tistory.com


 

목차

     

    1. 동작방식과 주의사항

    사용자가 웹브라우저를 이용하여 검색어를 네이버 서비스에 검색을 요청(Request)하고, 네이버 서버는 요청에 대한 처리결과를 응답(Response)한다.

    (Web 동작 방식에 대한 자세한 내용은 아래 구글 검색결과의 글을 읽어보기 바란다.)
    https://www.google.co.kr/search?q=web+동작+방식

     

    web 동작 방식 - Google 검색

    2016. 3. 17. · 웹 프로그래밍을 한다는 것은 웹 애플리케이션을 구현한다는 것을 의미한다. 웹 애플리케이션 동작 원리 클라이언트(사용자, 웹 브라우저)가 서버에. 웹 애플리케이션 서버 (WAS, Web A

    www.google.co.kr

     

    네이버 사전 서비스의 검색 요청(Request)과 응답(Response)에 대해 자세히 살펴보자.

     

    1.1. 네이버 사전 검색 요청과 응답

    웹 브라우저를 통해 서버와 주고 받는 내용을 확인하는 방법은 여러 가지가 있는데, 여기에서는 Fiddler Web Debugger로 설명하겠다.

    아래는 네이버 국어사전에서 "가입" 이라는 단어를 검색했을때 요청과 응답내용을 Fiddler에서 확인한 결과이다.

    Fiddler로 살펴본 네이버 사전 검색 요청과 응답
    Fiddler로 살펴본 네이버 사전 검색 요청과 응답

     

    1. URL, Content-Type: 아래 내용을 확인할 수 있다.
      • Protocol: HTTPS
      • Host: ko.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된 문자열이다.
    2. 요청(Request) Header
      • User-Agent, Cookie 등의 내용을 확인할 수 있다.
    3. 응답(Response) 내용
      • Content-Type: application/json;charset=UTF-8
        • Response 내용이 json 형식이고, character-set은 UTF-8로 encoding되어 있음을 알 수 있다.
      • Content-Length: 50814
        • Response 내용이 50,814 Byte, 약 50KB 임을 알 수 있다.
      • Content-Body: {"searchResultMap":{"searchResultListMap":{"WORD":{"query":"가입", ...
        • JSON string이고, "JSON" 탭에서 확인하면 다음과 같이 계층적 구조를 가지고 있다.
          네이버 국어사전 HTTP Response JSON 구조
          네이버 국어사전 HTTP Response JSON 구조

     

    1.2. 응답결과 형식 변경 (HTML --> JSON)

    이 도구는 네이버 Open API를 사용하지 않고 Web Request, Response 방식을 이용한다.

    정확하지는 않으나, 2018년 12월을 전후로 응답결과의 형식이 변경되었다. 그 이전에는 HTML 형식이었는데, 이 시기에 우연히 Fiddler로 확인해 보니 JSON 형식으로 응답이 변경되었음을 알게 되었다.

    이 도구의 첫 버전은 응답이 HTML 형식일 때 만들어졌다. HTML에서 필요한 항목을 추출하였는데, 네이버가 HTML의 구조를 변경할 때마다 제대로 동작하지 않아 변경된 HTML구조에 맞춰서 매번 소스코드를 변경해 줘야 했었다. 응답결과 형식이 JSON으로 변경된 이후로는 소스코드 변경없이 잘 동작하고 있다.

     

    1.3. 사용상 주의사항

    네이버가 사전 검색결과를 JSON 형식으로 제공한다고 공식적으로 알렸는지 확인할 수 없다. JSON의 구조에 대한 문서도 공개되어 있지 않은 것으로 보인다.
    (만약, 공개된 뉴스나 자료가 있다면 댓글로 알려주기 바란다.)

    이런 이유로 어느 날 갑자기 동작하지 않을 수 있으니 주의하기 바란다.

     

     

    2. 구현

    2.1. 전체 흐름 요약

    검색할 단어를 URL Encoding하고 GetDataFromURL 함수를 실행하여 가져온 JSON 검색결과를 parsing하여 필요한 항목을 추출한다.

    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")

    주요 함수에 대해 살펴보자.

     

    2.2. URL Encoding하기 (URLEncodeUTF8 소스코드)

    검색요청할 URL을 URLEncoding한 문자열로 반환한다. ADODB.Stream 클래스를 사용하였다.

    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

    ADODB 라이브러리를 사용하기 위해서 "Microsoft ActiveX Data Object 6.1 Library"를 참조 추가해야 한다. 엑셀 화면에서 Alt + F11 키를 누르고 VBA Editor로 전환하여 추가해 주면 된다.

    엑셀 VBA 라이브러리 참조 추가
    엑셀 VBA 라이브러리 참조 추가

     

    2.3. Request & Get Response (GetDataFromURL 함수 소스코드)

    "WinHttp.WinHttpRequest" 클래스를 이용하여 Request header, option 정보를 설정하고, 검색 URL을 방문하여 결과를 얻어온다. CreateObject로 개체를 생성하는 late binding 방식이라 라이브러리 참조 추가할 필요는 없다.

    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(검색결과) JSON 문자열

    Response(검색결과) JSON 문자열은 상당히 많은 정보를 포함하고 있다. 들여쓰기와 행구분이 없어 보기가 어려운데, 보기 좋게 정리하면 아래와 같다. (일부만 발췌함)

    {
      "searchResultMap": {
        "searchResultListMap": {
          "WORD": {
            "query": "가입",
            "queryRevert": "",
            "items": [
              {
                "rank": "1",
                "gdid": "8800000f_4002c436c93d4bb38d3e58632fe00af0",
                "matchType": "exact:entry",
                "entryId": "4002c436c93d4bb38d3e58632fe00af0",
                "serviceCode": "1",
                "languageCode": "KOKO",
                "expDictTypeForm": "단어",
                "dictTypeForm": "2",
                "sourceDictnameKO": "표준국어대사전",
                "sourceDictnameOri": "Standard Korean Dict.",
                "sourceDictnameLink": "https://stdict.korean.go.kr/main/main.do",
                ...
                "expEntry": "<strong>가입</strong>",
                ...
                "destinationLink": "#/entry/koko/4002c436c93d4bb38d3e58632fe00af0",
                ...
                "meansCollector": [
                  {
                    "partOfSpeech": "명사",
                    "partOfSpeech2": "noun",
                    "means": [
                      {
                        "order": "1",
                        "value": "조직이나 단체 따위에 들어가거나, 서비스를 제공하는 상품 따위를 신청함.",
                        ...
                        "exampleOri": "<strong>가입</strong> 신청서.",
                        ...
                      },
                      {
                        "order": "2",
                        "value": "새로 더 집어넣음.",
                        ...
                        "exampleOri": "원고 중간에 수정된 내용의 <strong>가입</strong>이 발견되었다.",
                        ...
                      },
                      {
                        "order": "3",
                        "value": "조약문의 인증 절차 없이, 그 조약에 드는 행위. 의사 표시만으로 당사자가 될 수 있게 하여 법 공동체...",
                        ...
                        "languageGroup": "법률",
                        ...
                        "exampleTrans": null,
                        ...
                      }
                    ]
                  }
                ],
                "similarWordList": [],
                "antonymWordList": [
                  {
                    "antonymWordName": "탈퇴",
                    "antonymWordLink": "#/entry/koko/14e89175152b46569c2a2b6360e835ad"
                  }
                ],
                "expAliasEntryAlwaysList": [],
                "expAliasGeneralAlwaysList": [
                  {
                    "originLanguageValue": "加入"
                  }
                ],
                ...
              },
              {
                "rank": "2",
                "gdid": "881857e6_e12c4e3432cf458c929bd49c929fd80b",
                "matchType": "exact:entry",
                "entryId": "e12c4e3432cf458c929bd49c929fd80b",
                "serviceCode": "1",
                "languageCode": "KOKO",
                "expDictTypeForm": "단어",
                "dictTypeForm": "2",
                "sourceDictnameKO": "우리말샘",
                "sourceDictnameOri": "Urimalsaem",
                "sourceDictnameLink": "https://opendict.korean.go.kr/main",
                ...
                "expEntry": "<strong>가입</strong>",
                ...
                "destinationLink": "#/entry/koko/e12c4e3432cf458c929bd49c929fd80b",
                ...
                "meansCollector": [
                  {
                    "partOfSpeech": "명사",
                    "partOfSpeech2": "noun",
                    "means": [
                      {
                        "order": "",
                        "value": "어떤 개체군에 새로운 개체가 더해지는 것. 단, 일정한 발육 단계에 도달한 개체만 해당된다.",
                        ...
                      }
                    ]
                  }
                ],
                "similarWordList": [],
                "antonymWordList": [],
                ...
              },
            ],
            "total": 96,
            "sectionType": "WORD",
            "revert": "",
            "orKEquery": null
          }
        }
      }
    }

     

     

    2.5. JSON parser

    문자열 함수(MID, INSTR 등)를 사용하여 JSON 문자열에서 원하는 항목을 추출해 낼 수는 있으나, 탐색이 복잡하고 코드가 매우 지저분해 진다.

    Python으로 구현하면 간단히 json module을 import하고, json 클래스를 사용하면 된다. VBA는 공개된 라이브러리가 많지 않은데, 다행히 github에 공개된 JSON parser가 있어서 잘 사용하였다.

    https://github.com/VBA-tools/VBA-JSON

     

    VBA-tools/VBA-JSON

    JSON conversion and parsing for VBA. Contribute to VBA-tools/VBA-JSON development by creating an account on GitHub.

    github.com

     

    이 JSON parser의 소스코드는 1,123 행이나 되어 블로그에 올려놓지는 않는다. 필요한 분들은 위 URL에서 소스코드를 확인하기 바란다. JSON parser를 사용하는 간단한 예시는 다음과 같다.(위 github에 공개된 코드)

    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. 검색 버튼 클릭 이벤트 소스코드

    "사전검색" 시트에서 "네이버 사전 검색" 버튼을 클릭했을 때 실행되는 코드이다. 다음 내용이 구현되어 있다.

    • 옵션 설정이 잘 되어 있는지 확인한다.
    • 검색어에 대해 사전 검색을 반복 실행하여 결과를 시트에 표시한다.
      • 표시되는 결과는 matchType, searchEntry, meaning, link, 유의어, 반의어이다.
    • 실행중 "검색 중지" 버튼이 눌렸다면 반복을 멈춘다.
    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. 사전 검색 (DoDicSearch 소스코드)

    검색어 한개에 대해 검색요청을 보내고 결과를 받은 다음 필요한 항목을 추출하여 반환하는 함수이다.

    • JSON 문자열을 Dictionary로 parsing: 49행
    • matchType, searchEntry, meaning, link, 유의어, 반의어 항목 추출: 53 ~ 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

     


    이상으로 이 도구의 동작방식, 주의사항, 소스코드에 대해 살펴보았다. 도구를 사용해 보신 분들의 후기나, 궁금한 점, 필요한 기능 등 의견은 댓글로 남겨주기 바란다. 

    댓글

    💲 추천 글