728x90
반응형

웹 이벤트를 자동(batch)수행하기 위해 Selenium기반으로 C#으로 접근해 보았습니다.

 

기능하고자 한 것은

   1. 신문사의 특정 기사에 접근

   2. Tag를 찾아내서  그 하이퍼링크된 주소를  클릭

   3. 새창으로 열린 창으로 접근

   4. 특정 iframe을 찾기 및 iframe 선택

   5. Javascript 구문을 수행하기

   6. PageSource에 접근하여 내용 수정

   7. 페이지 코드를 파일로 저장

 

 

728x90

 

 

ChromdeDriver를 생성하여 그 인터페이스(Interface)를 사용합니다.

IWebDriver driver = new ChromeDriver(options)

       

 

크롬 웹브라우저를 열 URL을 지정합니다. 반환값은 처리한 URL입니다. 즉, 그대로 출력합니다.

 string strResult = driver.Url = "https://www.etnews.com/20230331000229";   // implicitly  wait until the load is complete.
 Console.WriteLine(strResult);

 

 

제대로 URL이 열렸는지는 Title 값을 활용하여 Heuristic하게 프로그래밍 했습니다.

 if (driver.Title.IndexOf("missing.html") == -1)

 

 

특정 태그('a')를 찾아 그 이름이 "Englisth"일 경우,  그 하이퍼링크 URL을 호출(click)합니다. 

IList<IWebElement> links = driver.FindElements(By.TagName("a"));
//Console.WriteLine(links[0].Text);
//links.First(element => element.Text == "English").Click();
foreach (var link in links)
{
    Console.WriteLine(link.Text);
    if (link.Text == "English")
    {
        Console.WriteLine(link.GetAttribute("href"));
        link.Click();
        break;
    }
}

 

 

'새창'으로 열렸기 때문에,  제어권을 '새창'으로 옮깁니다.(SwitchTo)

string originWindow = driver.CurrentWindowHandle;
Console.WriteLine(originWindow);
foreach (string window in driver.WindowHandles)
{
    //새창을 찾는다.
    if (originWindow != window)
    {
        Console.WriteLine(window);
        driver.SwitchTo().Window(window);
        break;
    }
}

 

 

특정 iFrame 요소를 찾습니다.

List<IWebElement> frames = new List<IWebElement>(driver.FindElements(By.TagName("iframe")));
Console.WriteLine("Number of Frames: " + frames.Count);
var bFoundResultPage = 0;
for (int i = 0; i < frames.Count; i++)
{
    Console.WriteLine("frame[" + i + "]: " + frames[i].GetAttribute("id").ToString());
    if (frames[i].GetAttribute("id").ToString() == "CSLiResulPage")
    {
        bFoundResultPage = 1;
    }
}

 

특정 iFrame을 사용합니다.

driver.SwitchTo().Frame("CSLiResultPage");

 

JavaScript를 수행하여, 속성을 바꾸어 봅니다.

IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
//js.ExecuteScript("window.open()");
js.ExecuteScript("document.getElementsByTagName(\"html\")[0].setAttribute(\"lang\",\"en\") ");

 

웹페이지소스코드의 내용을 수정해 봅니다.

string aaa = driver.PageSource.ToString();
string bbb = aaa.Replace("https://trans.etnews.com", "http://klaud.between.io");
//Console.WriteLine(bbb);

 

 

 

 

 

전체 소스코드는 아래와 같습니다.

( 메모리 최적화 delete ,   sleep 대신에 await 등 처리 대기 등은  더 최적화 되어야 합니다.^^)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium;

namespace WebCrawler
{
    static class Program
    {
        static void Main(string[] args)
        {
            // ChomeDriver 인스턴스 생성                        
            ChromeOptions options = new ChromeOptions();
            options.AddArguments("--test-type");
            options.AddArguments("--ignore-certificate-errors");
                                    
            using ( IWebDriver driver = new ChromeDriver(options) )
            {
                // URL로 접속 
                string strResult = driver.Url = "https://www.etnews.com/20230331000229";   // implicitly  wait until the load is complete.
                Console.WriteLine(strResult);

                if (driver.Title.IndexOf("missing.html") == -1)
                {

                    // 대기 설정. (find로 객체를 찾을 때까지 검색이 되지 않으면 대기하는 시간 초단위)
                    driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(2);

                    Thread.Sleep(1000);

                    IList<IWebElement> links = driver.FindElements(By.TagName("a"));
                    foreach (var link in links)
                    {
                        Console.WriteLine(link.Text);
                        if (link.Text == "English")
                        {
                            Console.WriteLine(link.GetAttribute("href"));
                            link.Click();
                            break;
                        }
                    }


                    // 5초 기다린다.
                    Thread.Sleep(5000);

                    // 기존창 대신에 새창에서 열린다.
                    string originWindow = driver.CurrentWindowHandle;
                    Console.WriteLine(originWindow);
                    foreach (string window in driver.WindowHandles)
                    {
                        //새창을 찾는다.
                        if (originWindow != window)
                        {
                            Console.WriteLine(window);
                            driver.SwitchTo().Window(window);
                            break;
                        }
                    }

                    // iFrame 찾기
                    List<IWebElement> frames = new List<IWebElement>(driver.FindElements(By.TagName("iframe")));
                    Console.WriteLine("Number of Frames: " + frames.Count);
                    var bFoundResultPage = 0;
                    for (int i = 0; i < frames.Count; i++)
                    {
                        Console.WriteLine("frame[" + i + "]: " + frames[i].GetAttribute("id").ToString());
                        if (frames[i].GetAttribute("id").ToString() == "CSLiResulPage")
                        {
                            bFoundResultPage = 1;
                        }
                    }

                    if (bFoundResultPage == 1)
                    {
                        driver.SwitchTo().Frame("CSLiResultPage");
                        
                        IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
                        js.ExecuteScript("document.getElementsByTagName(\"html\")[0].setAttribute(\"lang\",\"en\") ");


                        string aaa = driver.PageSource.ToString();
                        string bbb = aaa.Replace("https://trans.etnews.com", "http://klaud.between.io");
                        //Console.WriteLine(bbb);


                        File.WriteAllText("C:\\UsersDownloads\\PageSource.html", bbb);
                        //File.WriteAllText("C:\\UsersDownloads\\PageSource.html", driver.PageSource);

                        // 5초 기다린다.
                        Thread.Sleep(1000);
                    }                    
                }
                driver.Quit();
            }
           
            // 아무 키나 누르면 종료
            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }

    }
}
728x90
반응형
728x90
반응형

음성인식엔진 개발자 출신으로서, 자연어처리/기계번역 분야에서  입력 글자 처리하는 루틴은 상당히 난해한 분야입니다.

 

프로그램을 보면,
MString 과 UString의 클래스가 있으면, 빈번히 변환한다.
 
사유 ::  소켓 통신할 때와,  프로젝트의 기반 세트가 다를 때, 빈번히 변환을 해 주어야 한다.
 
사유 :: 다국어 작업(번역)을 하다보면, 멀티바이트에서 언어가 깨지는 문제가 발생한다. 이 때 유니코드로 변환해서 적용을 해준다면, 깨지는 문제는 해결된다.
 
#문자세트(Character Set)의 종류와 특성
     . SBCS(Single Byte Character Set) :: 문자를 표현하는데 1Byte를 사용-ASCII
     . MBCS(Multi Byte Character Set) ::  한글은 2Byte, 영문은 1Byte -MultiByte(다중바이트), 다중 은 꼴랑 1개이냐? 2개이냐?  
     . WBCS(Wide Byte Character Set) ::  모든 문자를 2Byte 사용 - Unicode  ( 통일코드) ..  통일이 꼴랑 2로 했남?,  Uni가 1개? Wide가 넓게... 이름 참 희안하게 ....  ( 2^16 즉  65,536개....)  Uni는 1개의 뜻이 아니라  Unique의 뜻....(고유의 코드값)
 
 
# 멀티바이트 문자 집합은  특정문자 집합마다의 코드 페이지가 존재한다.
   예를 들어, 같은 코드 번호 일지라도 한글 코드페이지로 해석하면 한글이 나오지만,   일어코드 페이지로 해석하면 일어가 나온다. 
 
 
MULTI-BYTE ( ISO-2200 :: 가변바이트)
(ANSI, UTF-8)
:: UTF-8 ( 1~4바이트) :: 1,112,064자 표현 가능
WIDE-CHAR 자료형...
 유니코드
(Windows, Java에서는 UTF-16,
나머지 시스템에서는 UTF-8)
비고
string wstring CA2W("멀티바이트를 유니코드로 변환")
CW2A("유니코드를 멀티바이트로 변환")
CW2A("유니코드를 UTF8로 변환", CP_UTF8)
char *



strlen()
CString
WCHAR
wchar_t
L"유니코드"
lstrlenW()
TCHAR는 char인지, wchar인지 구별하지 않고 코딩
컴파일러에서 기본을 설절함에 따라, 일괄 변경된다...
LPCSTR LPCWSTR LP :: Long Pointer
C : Const

MultiByteToWideChar()   Windows OS에서만 가능
 
WideCharToMultiByte()
Windows OS에서만 가능
    CP_ACP  ::  시스템에서 사용하는 MBCS(멀티바이트) -> UTF-16(유니코드)
CP_UTF8->UTF-16(유니코드)
     
 
 
MFC에서
 
유니코드->멀티바이트
 
char * ConvertUnicodeToMultiByte( CString strUnicode)
{
         int nLen = WideCharToMultiByte( CP_ACP, 0, strUnicode, -1, NULL, 0, NULL, NULL);   # 변환 대상에 대한 크기, 길이정보를 구한다. 변환 후의 크기....  widechar가 2바이트짜리, 3바이트짜리가 있으니....계산해서.. multibyte의 크기를 출력...
        
        char* pMultiByte = new char(nLen);
        memset( pMultiByte, 0x00, nLen * sizeof(char) );
 
        WideChartoMultiByte( CP_ACP, 0, strUnicode, -1, pMultiByte, nLen, NULL, NULL);            // {유니코드}->{멀티바이트}.[ASCII  또는 UTF-8],     CP_ACP(아스키),  CP_UTF8
 
       retrun pMultiByte;
}
 
wchar_t strUnicode[256]={0,};
char      strMultibyte[256]={0,};
wcscpy(strUnicode, 256, L"유니코드");
int  len = WideCharToMultiByte( CP_ACP, 0, strUnicode, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ASCP, 0, strUnicode, -1, strMultibyte, len, NULL, NULL);
 
 
유니코드->UTF-8
wchar_t strUni[256]=L"유니코드";
char      strUtf8[256]={0, };
int nLen = WideCharToMultiByte( CP_UTF8, 0, strUni, lstrlenW(strUni), NULL, 0, NULL, NULL);
WideCharToMultiByte( CP_UTF8, 0, strUni, lstrlenW(strUni), strUtf8, nLen, NULL, NULL);
 
 
 
 
멀티바이트->유니코드
 
CString ConvertMultibyteToUnicode(char *pMultibyte)
{
     int nLen = strlen(pMultibyte);
    
    WCHAR * *pWideChar = new WCHAR(nLen);
    memset(pWideChar, 0x00, (nLen)*sizeof(WCHAR));
 
    MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pMultiByte, -1, pWideChar, nLen);
 
   CString strUnicode;
   strUnicode.format(_T("%s"), pWideChar);      // byte을 aligne해서 넣는다??
 
    delete [] pWideChar;
 
   return strUnicode;
}
 
wchar_t strUnicode[256]={0,};
char      strMultibyte[256]={0,};
strcpy_s( strMultibyte, 235, "멀티바이트");
int nLen = MultiByteToWideChar( CP_ACP, 0, strMultibyte, strlen(strMultibyte), NULL, NULL);
MultiByteToWideChar(CP_ACP, 0, strMultibyte, strlen(strMultibyte), strUnicode, nLen);
 
 
UTF-8 -> 유니코드
 
wchar_t strUnicode[256]={0,};
char      strUTF8[256]={0,};
strcpy_s( strUTF8, 256, "utf-8글자..");
int nLen = MultiByteToWideChar( CP_UTF8, 0, strUTF8, strlen(strUTF8), NULL, NULL);
MultiByteToWideChar( CP_UTF8, 0, strUTF8, strlen(strUTF8), strUnidcode, nLen);
 
 
 
 
 
#pragma once
#include <Windows.h>
#include <atlbase.h>
#include <iostream>
 
void func()
{
     USES_CONVERSION;  //매크로 선언
     
     LPCSTR        mChar;
     LPCWSTR     wChar = L"test";
 
    mChar = W2A( wChar );     //유니코드 문자열을 멀티바이트문자열로 변환
    wChar = A2W( mChar, CP_UTF8 );     //멀티바이트문자열을 유니코드문자열로 변환
 
}
 
 
 
 
 
인코딩(Encoding) - ASCII, ANSI, Multi-Byte, Unicode
 
아스키(ASCII)코드( 표)
    :: 128개문자
ANSI
    :: 영어만을 고려하여 만들어진 ASCII에서 다른 언어를 지원해야 할 필요가 생겨서...
    :: 아스키의 확장판 : 앞의 7bit(ASCII와 동일) + 1 bit(CodePage) = 총 8bit로 사용
             :::: CodePage = CP949, EUC-KR
    
 
 
한글처리
  :: EUK-KR ( Extended Unix Code-Korea)
         :::: 한글 지원을 위해 유닉스 계열에서 나온 '완성형' 코드 조합,  ANSI를 한국에서 확장한 것으로 외국에서는 지원이 안 될 가능성이 높다.
   :: CP949(Code Page 949)
         :::: 한글 지원을 위해 윈도우즈 계열에서 나온 확장 완성형 코드 
 
 
UTF-8
   1. 유니코드를 위한 가변길이 문자 인코딩(멀티바이트)방식...
   2. 처음 128글자는 ASCII코드값으로 동일
   3. 2bytes를 사용하여, 중동지역 언어 또는 많은 유럽 언어를 표현...
   4. 3byte를 사용하여 동아시아어권(한국,중국,일본..)
 
UTF-16
   1.  한글의 경우, UTF-8로 저정할 경우, 3바이트를 필요로 하므로,  UTF-16으로 저장하면 용량의 이점이 있음.
   2.  Endian 처리를 고려함에 따른 복잡성 증대나 ANSI와의 호환이 안되는 단점이 있음...
 
 
 
gcc 에서 characters
 
 
서버 프로그램에서 socker을 통해 전달받은 메시지 프로토콜은, 기본 인코딩은 유니코드임...(UString)...UTF-16 즉,, 2바이트 사용... 
   예시  
       //int n = ustrPassWord.Find( LPCWSTR(":MOD"));
       int n = ustrPassWord.Find( LPCWSTR("\x00\x3A\x00\x4D\x00\x4F\x00\x44\x00"));
 
   :: 유니코드에서 ->   멀티바이트로 변환
         ustrAccountName.FromMBC( CP_UTF8,   LPCSTR( g_theDoc.m_aryAuthAccountName.GetAt(i)) );    // MultiByte를  유니코드로 변환..)
 
 
   :: 멀티바이트에서 -> 유니코드로 변환
         mstrDebug.FromUnicode( CP_KOREAN,  LPCWSTR(ustrUserID));
 
 
클라이언트에서 서버로 보낼 때 인코딩은?  
   ::   프로젝트 속성에서  _UNICODE가 선언되어 있음..
   ::   CString이 기본 자료형임..
   ::   MString으로 변환하여, 일반적인 char* 또는 숫자 기반을 처리함...
   ::  "~~~ :ENC"를 보내고 있음...

 

728x90
반응형
728x90
반응형

https://www.sololearn.com/compiler-playground/c5Dt36lP1AHN/

 

https://www.sololearn.com/compiler-playground/c5Dt36lP1AHN/

 

www.sololearn.com

를 참조하였습니다.
 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;


namespace ExampleApplication
{
    public class Person
    {
        public int PersonID { get; set; }
        public string Name{ get; set; }
        public bool Registered{ get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine ("Hello World");
                       
            var RegisteredUsers = new List<Person>();
            RegisteredUsers.Add( new Person () {  PersonID=1, Name="Bryon Hetrik", Registered = true  });
            RegisteredUsers.Add( new Person () {  PersonID=2, Name="Nicole Wilcox", Registered = true  });
            RegisteredUsers.Add( new Person () {  PersonID=3, Name="Adrian Martinson", Registered = false  });
            RegisteredUsers.Add( new Person () {  PersonID=4, Name="Nora Osborn", Registered = false  });
           

            var serializer = new JavaScriptSerializer();
            var serializedResult = serializer.Serialize(RegisteredUsers);            
            Console.WriteLine( serializedResult );

            var deserializedResult = serializer.Deserialize<List<Person>>( serializedResult );
            //var deserializedResult = serializer.Deserialize< List <object>>( serializedResult );

            Console.WriteLine(deserializedResult.Count );            
            

foreach ( var item in deserializedResult ){
                Console.WriteLine($"{item.PersonID}");
                Console.WriteLine($"{item.Name}");            
            }
           
            Console.WriteLine("Done!");

            var cities = new Dictionary<string, object>() {
                {"UK", "London, Manchester, Birmingham"},
                {"USA", "Chicago, New York, Washington"},
                {"India", "Mumbai, New Delhi, Pune"},
                {"Available", false }
            };

            foreach( var city in cities ){
                Console.WriteLine(" Key : {0}, Value: {1}", city.Key, city.Value );
            }

            //use ContainsKey() to check for an unknown key
            if( cities.ContainsKey("India")) {
                Console.WriteLine( cities["India"]);
            }

            //use TryGetValue() to get a value of unknown key            
            if( cities.TryGetValue("Available", out object result )){
                Console.WriteLine( (bool) result);

            }


            //var Profiles = serializer.Deserialize<List<object>>( profilesResponse );
            //Console.WriteLine( Profiles.Count );






         
            Console.WriteLine("!!!!DONE");
        }
    }
}

 

 

출력 결과 

 

 

Hello World
[{"PersonID":1,"Name":"Bryon Hetrik","Registered":true},{"PersonID":2,"Name":"Nicole Wilcox","Registered":true},{"PersonID":3,"Name":"Adrian Martinson","Registered":false},{"PersonID":4,"Name":"Nora Osborn","Registered":false}]
4
1
Bryon Hetrik
2
Nicole Wilcox
3
Adrian Martinson
4
Nora Osborn
Done!
Key : UK, Value: London, Manchester, Birmingham
Key : USA, Value: Chicago, New York, Washington
Key : India, Value: Mumbai, New Delhi, Pune
Key : Available, Value: False
Mumbai, New Delhi, Pune
False
!!!!DONE

 

728x90
반응형

+ Recent posts