[C#] 네이버 실시간 검색 순위 CS프로그램 - 2

개발 노트/C#  2013.08.05 09:00



이번 포스팅은 저번 포스팅에 이어서 서버 프로그램을 작성해보도록 하겠습니다.

이 서버의 역할을 Naver로 부터 Xml를 받으면 Client로 배포 전문을 다시 만드는 역할입니다.

왜 굳히 이렇게 번거롭게 작업을 하냐고 하면.. Naver 가 데이터베이스라는 가정하에 커넥션을 최대한 줄이려는 목적이 있습니다. 즉 여기 키 발급 하는데를 보시면 아시겠지만 하루 클릭 25000번으로 제약이 되어있습니다.

이 프로그램은 배포가 아니라 단순 공부 프로그램이라 뭐 상관은 없겠지만 배포라고 했을 경우 25000이란 수치는 결코 높은 수치가 아닙니다. 만약 제 프로그램이 대박이 터져서 사람들이 다들 다운로드 받아서 사용한다는 가정하에 25000이면 1시간도 안되서 막혀버릴 것이기 때문입니다.


그럼 Server에서 Naver로 부터 Xml 파싱 부품을 작성해 보도록 하겠습니다.




위 코드를 보면 Class 안에 두개의 클래스가 있습니다 원래는 클래스가 아니고 Struct로 작성을 해야 옳은 용법이나 Class로 써도 큰 차이가 없기 때문에 저는 그냥 클래스로 사용했습니다.


XmlPathStruct 클래스는 먼저 네이버에 접속을 위한 쿼리를 작성하는 클래스 입니다.

두번째 DataStruct 클래스는 네이버로부터 Xml를 받으면 메모리에 Struct로 정의해서 로드하기 위한 클래스 입니다. 보면 네개의 맴버변수가 있네요. 랭크, 라벨,랭크 변경단위,변경크기 가 있습니다.



맴버변수 구성은 Url 만드는 클래스 네이버로 부터 Xml을 로드하기 위한 XmlDocument, 메모리에 보존하기 위한 Memorystream, 데이터 형식으로 가공하기 위한 List<DataStruct> 로 구성되었습니다.


생성자 일때 Url 를 만들고, XmlDocument와 DataSet를 로드 시킵니다.



위 코드는 외부에서 GetXmlData를 호출하게 되면 Xml 형식대로 값을 추출해서 DataSet 값에 넣는 부분입니다.



위 코드는 Xml 분석하는 While 문이 보이네요... 세번째는 XmlPath를 작성하는 함수이고 두번째는 XmlPath를 해독하는 쿼리 입니다.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Collections;
using System.IO;

namespace RealSearchServer
{
    class NaverXmlReader 
    {
        private class XmlPathStruct
        {
            public XmlPathStruct(String sKeyCode)
            {
                m_Url = "http://openapi.naver.com/search";
                m_Key = "key=" + sKeyCode;
                m_Query = "query=nexearch";
                m_Target = "target=rank";
            }
            public String GetXmlPath
            {
                get
                {
                    return m_Url + "?" + m_Key + "&" + m_Query + "&" + m_Target;
                }
            }
            private String m_Url;
            private String m_Key;
            private String m_Query;
            private String m_Target;
        }
        public class DataStruct
        {
            public enum UpnDown
            {
                UP,
                NoChange,
                Down
            }
            private int m_Rank;
            private String m_Label;
            private UpnDown m_RankChange;
            private int m_ChangeSize;

            public int Rank
            {
                get { return m_Rank; }
                set { m_Rank = value; }
            }
            public String Label
            {
                get { return m_Label; }
                set { m_Label = value; }
            }
            public UpnDown RankChange
            {
                get { return m_RankChange; }
                set { m_RankChange = value; }
            }
            public int ChangeSize
            {
                get { return m_ChangeSize; }
                set { m_ChangeSize = value; }
            }
            
        }
        private XmlDocument m_XmlData;
        private MemoryStream m_XmlStream;
        private XmlPathStruct m_XmlUrlPath;
        private List DataSet;

        public DataStruct GetData(int nIndex)
        {
            if (nIndex < DataSet.Count)
                return DataSet[nIndex];
            else
                return null;
        }
        public int Count
        {
            get
            {
                return DataSet.Count;
            }
        }

        public NaverXmlReader()
        {
            m_XmlStream = null;
            DataSet = new List();
            m_XmlUrlPath = new XmlPathStruct("");
            m_XmlData = new XmlDocument();
        }
        public void GetXmlData()
        {
            if (m_XmlStream != null)
            {
                m_XmlStream.Close();
                m_XmlStream.Dispose();
                m_XmlStream = null;
            }
            m_XmlData.Load(new XmlTextReader(m_XmlUrlPath.GetXmlPath));
            m_XmlStream = new MemoryStream(Encoding.UTF8.GetBytes(m_XmlData.InnerXml));
            
            DataSet.Clear();
            String sBuffer;
            String sBuffer2;
            for (int i = 1; i <= 10; i++)
            {
                DataStruct pBuffer = new DataStruct();
                pBuffer.Rank = i;
                for (int j = 0; j < 3; j++)
                {
                    char cBuffer = ' ';
                    switch (j)
                    {
                        case 0: cBuffer = 'K'; break;
                        case 1: cBuffer = 'S'; break;
                        case 2: cBuffer = 'V'; break;
                    }
                    sBuffer = GetXPath(i, cBuffer);
                    sBuffer2 = GetPathData(sBuffer);
                    switch (j)
                    {
                        case 0:
                            pBuffer.Label = sBuffer2;
                            break;
                        case 1:
                            switch (sBuffer2)
                            {
                                case "+":
                                    pBuffer.RankChange = DataStruct.UpnDown.UP;
                                    break;
                                case "-":
                                    pBuffer.RankChange = DataStruct.UpnDown.Down;
                                    break;
                                default:
                                    pBuffer.RankChange = DataStruct.UpnDown.NoChange;
                                    break;
                            }
                            break;
                        case 2:
                            if (sBuffer2 != "")
                                pBuffer.ChangeSize = Convert.ToInt32(sBuffer2);
                            else
                                pBuffer.ChangeSize = 0;
                            break;
                    }
                }
                DataSet.Add(pBuffer);
            }
        }
        private String GetPathData(String sXPath)
        {
            int offset = 0;
            String sElementName = XPathElement(sXPath,ref offset);
            bool bCheck = false;
            m_XmlStream.Seek(0, SeekOrigin.Begin);
            XmlTextReader pXmlBuffer = new XmlTextReader(m_XmlStream);
            while (pXmlBuffer.Read())
            {
                switch (pXmlBuffer.NodeType)
                {
                    case XmlNodeType.Element:
                        if (!bCheck && pXmlBuffer.Name == sElementName)
                        {
                            sElementName = XPathElement(sXPath, ref offset);
                            if (sElementName == "text()")
                            {
                                bCheck = true;
                            }
                        }
                        break;
                    case XmlNodeType.Text:
                        if (bCheck)
                        {
                            return pXmlBuffer.Value;
                        }
                        break;
                }
            }
            return "";
        }
        private String XPathElement(String sXPath,ref int offset)
        {
            int nPos = sXPath.IndexOf("/", offset)+1;
            int nEpos = sXPath.IndexOf("/", nPos) ;
            offset = nEpos;
            if (nEpos > 0)
            {
                return sXPath.Substring(nPos, nEpos - nPos);
            }
            else
            {
                return sXPath.Substring(nPos, sXPath.Length - nPos);
            }
        }
        protected String GetXPath(int nIndex, char cNode)
        {
            return String.Format("/result/item/R{0}/{1}/text()", nIndex, cNode);
        }
    }
}



참고 소스입니다.


NaverXmlReader.cs





댓글 1개가 달렸습니다.
댓글쓰기

  1. 2014.01.26 21:57 |  수정/삭제  댓글쓰기

    비밀댓글입니다