NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 팁 앤 테크
  • 매뉴얼

    팁과 테크니컬 노하우를 확인하세요.

    팁 앤 테크

    팁과 테크니컬 노하우를 확인하세요.

    본 사이트의 컨텐츠는 저작권법의 보호를 받으므로 무단 복사, 게재, 배포 등을 금합니다.

    커스텀 2. 네이버 실시간 검색어 크롤링하기. (AgilityPack을 이용한 크롤링 모듈 만들기)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. [ 이전글 ]에서 개발 환경을 갖추었죠? 오늘은 AgilityPack을 이용해서 네이버 실검 키워드들을 수집하는 모듈을 만들도록 하겠습니다. Visual Studio 2019를 관리자 권한으로 실행한 후 CustomNGM 솔루션을 열어주세요~

    1poGuGl.png

     

     

    아래 그림과같이 솔루션 탐색기의 Tools 폴더에서 우클릭 후 새 프로젝트를 추가하세요.

    SiaBHDv.png

     

     

    템플릿 검색 아래에서 C#, Windows, 라이브러리를 선택하세요. 검색된 템플릿 목록에서 중간쯤 클래스 라이브러리(.NET Framework)를 선택하고 다음을 누르세요.

    AHH8aNH.png

     

     

    프로젝트 이름은 ①CustomToolCrawlingModule로 정합니다. 엔지엠 인터페이스를 사용하려면 이름 명명 규칙을 따라야합니다. 모듈의 이름은 CustomTool 또는 CustomFunction으로 시작해야 합니다. 그리고, 마지막은 Module로 끝나야 합니다. 아래 1번과 같이 이름을 입력하시면 됩니다. 이는 좀 더 효율적인 관리를 위한 네이밍룰이며, 호스트 입장에서 좀 더 쉽게 리소스를 처리할 수 있게됩니다. 사전적 의미는 다르지만, 스캐폴딩(Scaffolding) 기법중에 하나로 상호작용을 쉽게할 수 있습니다. ②위치는 물리적인 폴더 Tools를 선택하세요. ③만들기를 클릭하면 클래스 라이브러리 프로젝트가 만들어집니다.

    ZH3dsg9.png

     

     

    여러분들은 CustomToolCrawlingModule 프로젝트 하나만 존재할거예요^^; 프로젝트 앞에 ▷를 클릭하여 펼치세요. 그리고 Class1.cs를 선택하고 이름 바꾸기를 누르세요.

    FhTKF0u.png

     

     

    CrawlingModel.cs로 이름을 변경하세요. 클래스의 이름도 네이밍룰에 맞게 입력해야 합니다. 클래스는 마지막에 Model로 끝나야 합니다.

    M567THd.png

     

     

    C#으로 웹크롤러를 구현할수도 있습니다. 하지만... 웹 리퀘스트(Web request), 웹 리스폰스(Web response) 및 XML, Node 탐색기등등을 만드는데는 많은 노력과 시간이 소요됩니다. 이런것들은 이미 구현된 모듈이 있거나 솔루션들이 존재할겁니다. 파이썬에서 사용하는 BeautifulSoup과 같은것들이죠. 자바는 jsoup을 이용하면 쉽게 구현이 가능합니다. C#은 AgilityPack을 이용합니다^^; 아래 그림과 같이 Visual Studio 2019의 상단에 도구 > NuGet 패키지 관리자 > 솔루션용 NuGet 패키지 관리자를 클릭하세요.

    ※ BeautifulSoup, jsoup, AgilityPack은 Html 파싱 모듈 또는 프레임워크입니다.

    l0w7HBQ.png

     

     

    찾아보기에서 ①agility를 입력하세요. ②HtmlAgilityPack을 선택한 후 ③설치할 프로젝트에 체크하세요. 여러분들은 프로젝트가 2개만 보일겁니다. 저는 이미 설치되어 있어서 ④설치가 비활성되어 있는데요. 여러분들은 활성화되어 있고 클릭할 수 있는 상태일겁니다. 설치를 클릭하여 프로젝트에 모듈을 추가하세요.

    gcV5y4b.png

     

     

    아래 그림처럼 프로젝트의 참조를 펼쳐보면 HtmlAgilityPack 모듈이 추가된것을 알 수 있습니다.

    ReBl6Ju.png

     

     

    NGM과 인터페이스하기 위한 모듈 NGM, NGM.Models, NGM.Models.Interface를 추가해야합니다. 아래 그림과 같이 참조에서 우클릭 후 참조 추가를 클릭하세요. 참조 추가라는건 간단하게 말해서 도움을 받을 친구를 주소록에 저장한다고 생각하시면 됩니다. 시스템 또는 프로그램이 독립적으로 혼자 모든일을 처리할수도 있습니다만... 대부분은 다른 친구(모듈, 프레임워크, 라이브러리)들의 도움을 받아서 처리합니다. 좀 더 깊이 들어가면 재사용성과 관련이 있지만 자세히 알아보지는 않겠습니다. 프로그래밍 강의가 아니라서요^^;

    xFZMKEE.png

     

     

    하단에 찾아보기를 클릭하세요. 참고로, COM(Component Object Model)은 마이크로소프트가 개발한 소프트웨어 구성 요소들의 응용 프로그램 이진 인터페이스입니다. 일반적으로 OLE나 ActiveX, COM+, DCOM등을 통칭해서 콤이라고 부릅니다. 닷넷 프레임워크의 등장으로 마이크로소프트에서 콤을 서서히 줄여나갈것으로 예상했습니다. 하지만, 예상과는 다르게 아직도 광범위하게 사용되는 기술이며 패키징된 프로그램들과 인터페이스를 위해 필수로 알아야 하는 기술이기도 합니다. 일반적으로는 잘 몰라도 개발하는데 크게 문제가 되지 않아요!

    anMtZhb.png

     

     

    내문서 > NGM5 > ToolExtension 폴더에 아래 3개 파일을 모두 선택하고 추가하세요.

    wsg9E6Q.png

     

     

    Visual Studio 2019의 솔루션 탐색기에서 CrawlingModel.cs를 더블클릭하세요. 코딩할 수 있는 소스가 표시됩니다. 아래 코드를 참고해서 직접 수정해보세요.

    using HtmlAgilityPack;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace CustomToolCrawlingModule
    {
        // Serializable 특성 추가
        // 이 특성은 클래스를 직렬화할 수 있다는 것을 나타냅니다.
        [Serializable]
        // public은 접근 한정자(접근 제한자)로 공개된 클래스로 표시합니다.
        // NGM.Models.Interface.BaseCustomToolModel은 추상 클래스입니다. 이 클래스를 상속받으면 NGM 에디터의 도구 상자 액션으로 인식합니다.
        public class CrawlingModel : NGM.Models.Interface.BaseCustomToolModel
        {

     

     

    간단하게 설명을 달아두었습니다. Serializable(시리얼라이저블) 특성(Attribute)은 클래스를 직렬화할 수 있도록 해줍니다. 직렬화는 컴퓨터 과학의 데이터 스토리지(일반적으로 메모리를 말함)에서 오브젝트의 구조나 상태를 파일로 저장해줍니다. 이 파일을 다른 컴퓨터 환경에서 메모리로 동일하게 복구할 수 있는 메커니즘을 제공합니다. 복구하는 행위는 Deserialization(디시리얼라이제이션)이라고 부릅니다. 엔지엠 에디터에서 만든 스크립트를 저장하는 행위가 시리얼라이제이션이며, 이 스크립트를 다른 컴퓨터에 복사한 후 플레이어에서 불러오면 디시리얼라이제션으로 메모리에 로딩할 수 있습니다. 그래서 동일한 동작을 보장할 수 있게됩니다.

    VrGEJ7c.jpg

     

     

    두번째로 클래스 앞에 public 접근 한정자(접근 제한자)를 추가했습니다. OOP(Object Oriented Programming: 객체 지향 프로그래밍)에서 나온 개념으로 C++에서 정보 은닉에 사용됩니다. 오래전 프로그래밍 언어들은 프로그램이 수십줄에서 수백줄밖에 안되었습니다. 컴퓨터 성능의 한계도 있었지만, 현재와 같은 복잡한 기능이 필요하지 않았기 때문이기도 했습니다. 현재는 수십만에서 수백만줄 이상의 거대한 프로그램을 사용하고 있습니다. 몇줄만으로 코딩이 가능하다고 하는것들도 이미 만들어진 프레임워크나 모듈 또는 라이브러리를 가져다 사용하는것입니다. 아무튼, 코딩량이 많아지고 여러명의 개발자가 협업하거나 개발자도 소비자처럼 프레임워크나 모듈을 구매합니다. 이 때 사용자가 굳이 알 필요가 없는 정보는 사용자로부터 숨겨야 한다는 개념입니다. 자동차를 구매했으면 핸들 조작이나 가속과 정지, 좌우 방향 지시등 및 비상등정도만 알면 될겁니다. 그러면 도로에서 달리는데 문제가 없죠. 개발자도 동일합니다. 다른 개발자 또는 회사의 제품을 구매한 후 내가 원하는 기능만 보여지는게 프로그램을 사용하는데 더 쉽기 때문입니다.

    dEVLdfH.png

     

     

    C#은 접근 한정자가 언어들중에서 가장 많습니다. 아마도 C++과 Java 다음에 나온탓에 둘의 접근 제어 지시자를 모두 가져온거 같습니다. 아무튼, 자꾸 프로그래밍 강의처럼 되어가는데... 개발자가 아니라면 굳이 몰라도 되는 내용들입니다. 대부분은 구글에서 필요한 코드를 검색해서 Ctrl+CV(복붙)하면 원하는 프로그램을 금방 만들 수 있기 때문입니다. 개발자의 가장 큰 덕목중 하나가 원하는 코드를 얼마나 잘 찾아서 짜집기를 아름답게 하느냐이기도 하니까요^^ 무(無)에서 유(有)를 창조하는 개발자는 없습니다.

     

    아래 코드를 참고해서 추상 클래스에 정의된 DisplayCategory, DisplayName 속성을 재정의하여 구현해줍니다. 이 부분도 설명해야 할 내용이 참 많습니다. 추상화는 일반화 프로그래밍 기법중에 하나로 OOP에서 핵심이 되는 기술입니다. 추상화라는건 쉽게 말해서 아이언맨, 슈퍼맨, 울버린, 아쿠아맨등등을 히어로(영웅)로 표현하는겁니다. 그렇다면, 영웅을 만듭니다. 영웅은 인류를 구하고 펄럭이는 망토를 두르고 있죠? 하지만, 일부 영웅들은 망토가 없습니다. 이런 경우 상속받아서 재정의할 수 있는겁니다.

    using HtmlAgilityPack;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace CustomToolCrawlingModule
    {
        // Serializable 특성 추가
        // 이 특성은 클래스를 직렬화할 수 있다는 것을 나타냅니다.
        [Serializable]
        // public은 접근 한정자(접근 제한자)로 공개된 클래스로 표시합니다.
        // NGM.Models.Interface.BaseCustomToolModel은 추상 클래스입니다. 이 클래스를 상속받으면 NGM 에디터의 도구 상자 액션으로 인식합니다.
        public class CrawlingModel : NGM.Models.Interface.BaseCustomToolModel
        {
            // 추상 클래스에 정의된 프로퍼티(속성)을 구현합니다.
            // 이 속성은 엔지엠 에디터 도구상자의 카테고리입니다.
            // get만 구현되어 있으므로 읽기 전용입니다.
            /// <summary>
            /// 도구 상자에 표시할 카테고리 이름입니다.
            /// </summary>
            public override string DisplayCategory
            {
                get
                {
                    return "NGMsoftware";
                }
            }
    
            /// <summary>
            /// 도구 상자에 표시할 액션 이름입니다.
            /// </summary>
            public override string DisplayName
            {
                get
                {
                    return "크롤링";
                }
            }

     

     

    범용성을 생각하면 아래와 같은 속성들은 사용자에게 선택할 수 있도록 해주는게 좋을듯 보입니다. WebSiteAddress 속성을 예로 들어서 설명해야겠네요. 누군가는 네이버에서 크롤링하고 싶을수도 있고, 누군가는 다음에서 또는 구글에서 크롤링할 정보가 있을수 있습니다. 만약, 나혼자 사용하는 프로그램이라면 이 속성은 필요가 없습니다. 내가 사용하는 사이트의 주소를 이미 알고 있기 때문입니다. 하지만 범용적인 프로그램을 만들게되면 사용자로부터 입력받은 값을 메모리에 저장해야 합니다. 입력과 저장된 값을 가져올때 속성(Property)을 사용하게 됩니다.

            [Category("Action")]
            [DisplayName("사이트 주소")]
            [Description("크롤링할 사이트의 전체 주소를 가져오거나 설정합니다.")]
            [DefaultValue(null)]
            [Browsable(true)]
            public string WebSiteAddress { get; set; }
    
            [Category("Action")]
            [DisplayName("노드 XPath 1")]
            [Description("노드의 XPath 값을 가져오거나 설정합니다.")]
            [DefaultValue(null)]
            [Browsable(true)]
            public string NodeXPath1 { get; set; }
    
            [Category("Action")]
            [DisplayName("노드 XPath 2")]
            [Description("노드의 XPath 값을 가져오거나 설정합니다.")]
            [DefaultValue(null)]
            [Browsable(true)]
            public string NodeXPath2 { get; set; }
    
            [Category("Action")]
            [DisplayName("줄바꿈")]
            [Description("탐색하는 노드별로 줄바꿈을 실행할지 여부를 가져오거나 설정합니다.")]
            [DefaultValue(false)]
            [Browsable(true)]
            public bool LineBreak { get; set; }
    
            [Category("Action")]
            [DisplayName("파일 저장")]
            [Description("저장할 파일위치와 이름을 가져오거나 설정합니다.")]
            [Browsable(true)]
            [DefaultValue(null)]
            public string TextFile { get; set; }

     

     

    추상 클래스에 정의된 Execute입니다. 이 메소드는 엔지엠 에디터에서 스크립트를 실행하고, 이 액션이 실행될 때 수행하게 될 로직입니다. 사실 가장 중요한 부분이죠.

            // 액션이 실행될 때 호출되는 메소드입니다.
            public override void Execute()
            {
                // 어질리티팩의 HtmlWeb 인스턴스를 만듭니다.
                var site = new HtmlWeb();
                // 웹에서 Html을 가져옵니다.
                var html = site.Load(WebSiteAddress);
    
                // 노드를 탐색합니다.
                foreach (HtmlNode node1 in html.DocumentNode.SelectNodes(@NodeXPath1))
                {
                    // 구조적으로 네이버의 실검은 2단계의 노드를 탐색해야 가져올 수 있더라구요^^;
                    // 만약, 다른 사이트의 구조를 파악해봤더니 구조적으로 3단계를 처리해야 한다면 NodeXPath3 속성을 추가하고,
                    // 이 코드를 수정해야 합니다.
                    using (StreamWriter outputFile = new StreamWriter(TextFile)) // Text 파일로 저장하기 위해 스트림을 사용합니다.
                    {
                        // 네이버 실검의 keyword 노드를 탐색하는 부분입니다.
                        foreach (HtmlNode node2 in html.DocumentNode.SelectNodes(@"//span[@class='" + NodeXPath2 + "']"))
                        {
                            // 줄바꿈 처리 여부에 따라 텍스트 문서에 기록하게 됩니다.
                            if (LineBreak)
                                outputFile.WriteLine(node2.InnerText);
                            else
                                outputFile.Write(node2.InnerText);
                        }
                    }
                }
            }

     

     

    프로그램 개발과 테스트에 1시간이 걸렸다면... 강좌를 작성하는데는 10시간이 걸리는군요-_-; 아래는 전체 코드입니다.

    using HtmlAgilityPack;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing.Design;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace CustomToolCrawlingModule
    {
        // Serializable 특성 추가
        // 이 특성은 클래스를 직렬화할 수 있다는 것을 나타냅니다.
        [Serializable]
        // public은 접근 한정자(접근 제한자)로 공개된 클래스로 표시합니다.
        // NGM.Models.Interface.BaseCustomToolModel은 추상 클래스입니다. 이 클래스를 상속받으면 NGM 에디터의 도구 상자 액션으로 인식합니다.
        public class CrawlingModel : NGM.Models.Interface.BaseCustomToolModel
        {
            // 추상 클래스에 정의된 프로퍼티(속성)을 구현합니다.
            // 이 속성은 엔지엠 에디터 도구상자의 카테고리입니다.
            // get만 구현되어 있으므로 읽기 전용입니다.
            /// <summary>
            /// 도구 상자에 표시할 카테고리 이름입니다.
            /// </summary>
            public override string DisplayCategory
            {
                get
                {
                    return "NGMsoftware";
                }
            }
    
            /// <summary>
            /// 도구 상자에 표시할 액션 이름입니다.
            /// </summary>
            public override string DisplayName
            {
                get
                {
                    return "크롤링";
                }
            }
    
            [Category("Action")]
            [DisplayName("사이트 주소")]
            [Description("크롤링할 사이트의 전체 주소를 가져오거나 설정합니다.")]
            [DefaultValue(null)]
            [Browsable(true)]
            public string WebSiteAddress { get; set; }
    
            [Category("Action")]
            [DisplayName("노드 XPath 1")]
            [Description("노드의 XPath 값을 가져오거나 설정합니다.")]
            [DefaultValue(null)]
            [Browsable(true)]
            public string NodeXPath1 { get; set; }
    
            [Category("Action")]
            [DisplayName("노드 XPath 2")]
            [Description("노드의 XPath 값을 가져오거나 설정합니다.")]
            [DefaultValue(null)]
            [Browsable(true)]
            public string NodeXPath2 { get; set; }
    
            [Category("Action")]
            [DisplayName("줄바꿈")]
            [Description("탐색하는 노드별로 줄바꿈을 실행할지 여부를 가져오거나 설정합니다.")]
            [DefaultValue(false)]
            [Browsable(true)]
            public bool LineBreak { get; set; }
    
            [Category("Action")]
            [DisplayName("파일 저장")]
            [Description("저장할 파일위치와 이름을 가져오거나 설정합니다.")]
            [Browsable(true)]
            [DefaultValue(null)]
            public string TextFile { get; set; }
    
            // 액션이 실행될 때 호출되는 메소드입니다.
            public override void Execute()
            {
                // 어질리티팩의 HtmlWeb 인스턴스를 만듭니다.
                var site = new HtmlWeb();
                // 웹에서 Html을 가져옵니다.
                var html = site.Load(WebSiteAddress);
    
                // 노드를 탐색합니다.
                foreach (HtmlNode node1 in html.DocumentNode.SelectNodes(@NodeXPath1))
                {
                    // 구조적으로 네이버의 실검은 2단계의 노드를 탐색해야 가져올 수 있더라구요^^;
                    // 만약, 다른 사이트의 구조를 파악해봤더니 구조적으로 3단계를 처리해야 한다면 NodeXPath3 속성을 추가하고,
                    // 이 코드를 수정해야 합니다.
                    using (StreamWriter outputFile = new StreamWriter(TextFile)) // Text 파일로 저장하기 위해 스트림을 사용합니다.
                    {
                        // 네이버 실검의 keyword 노드를 탐색하는 부분입니다.
                        foreach (HtmlNode node2 in html.DocumentNode.SelectNodes(@"//span[@class='" + NodeXPath2 + "']"))
                        {
                            // 줄바꿈 처리 여부에 따라 텍스트 문서에 기록하게 됩니다.
                            if (LineBreak)
                                outputFile.WriteLine(node2.InnerText);
                            else
                                outputFile.Write(node2.InnerText);
                        }
                    }
                }
            }
        }
    }

     

     

    이렇게해서 네이버 실시간 검색어 순위를 크롤링하는 모듈을 만들어봤습니다. 다음에는 런처에 모듈을 탑제해서 테스트해보고, 결과를 확인하도록 할께요. 아마 이 강좌를 따라해보신 분들은 직접 어떤 사이트든 원하는 정보를 가져와서 가공하고 처리할 수 있을겁니다. 다음 마지막 강좌도 기대해주세요~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.