본문 바로가기
이미지 매크로

C# .NET 매크로 프로그램 만들기. (웹 자동화 실행 및 중지)

by 업무자동화 2024. 6. 3.
반응형

유료 매크로 프로그램 다운로드

http://ngmsoftware.com/bbs/board.php?bo_table=product_review 

 

엔지엠소프트웨어

엔지엠 매크로는 복잡한 반복작업을 자동화할 수 있습니다. PC 게임, 모바일 게임을 최적으로 지원하며 모든 PC 프로그램 및 업무에 적용할 수 있습니다.

www.ngmsoftware.com

#매크로 #메크로 #매크로프로그램 #엔지엠소프트웨어 #엔지엠에디터 #엔지엠플레이어 #비활성매크로 #하드웨어매크로 #기계식매크로 #마우스광클릭 #키보드매크로 #이미지서치 #이미지매치 #블로그 #카페 #인스타그램 #유튜브 #소셜네트워크 #카카오톡 #텔레그램 #자동화

 

 

  • 엔지엠 커뮤니티 월 이용료: 4,500원, 1년 이용료: 55,000원 (전체 기능의 80프로)
  • 엔지엠 얼티밋 월 이용료: 6,500원, 1년 이용료: 77,000원 (전체 기능의 90프로)
  • 엔지엠 엔터프라이즈 월 이용료: 9,200원, 1년 이용료: 110,000원 (전체 기능 사용)

 

안녕하세요. 엔지엠소프트웨어입니다. 엔지엠 매크로에는 웹업무 자동화와 관련된 기능들을 제공합니다. 총 3종류인데요. Selenium 기반의 웹 API 액션들과 웹소켓 그리고, 크로미움이 있습니다. 총 3가지의 인터페이스를 사용해서 웹업무를 자동화 할 수 있습니다. 오늘은 가장 많이 사용하는 웹 API(Selenium)를 이용해서 브라우저를 실행하고, 사이트를 이동하는 방법에 대해 알아볼께요. 그리고, 연결을 끊고 리소스를 제거하는 액션도 만들어 볼께요.

 

우선, Connection과 Disconnection 액션을 각각 만들어 줍니다. 참고로, 엔지엠 매크로 6은 Single Macro 디자인 아키텍쳐라서 멀티 실행으로 처리하는 부분에 문제가 많았습니다. 그래서, 엔지엠 7 버전에서는 기본적으로 Multiple Macro 디자인 아키텍쳐를 사용했습니다. 처음 설계 단계부터 여러개의 인스턴스를 동시에 제어할 수 있도록 만들었기 때문에 다중 클라 작업에이 쉬워졌습니다.

 

아래와 같이 클래스 2개를 추가하세요.

 

 

웹 연결 액션에서 사용자에게 제공할 결과 데이터는 3개입니다. 추가적으로 더 필요할지도 모르겠지만, 일단은 3가지만 처리하는걸로 할께요.

[LocalizedCategory("Data")]
[LocalizedDisplayName("WindowTitle")]
[LocalizedDescription("WindowTitle")]
[Browsable(true)]
[DefaultValue(null)]
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
public string? Title { get; set; }

[LocalizedCategory("Data")]
[LocalizedDisplayName("CurrentWindowHandle")]
[LocalizedDescription("CurrentWindowHandle")]
[Browsable(true)]
[DefaultValue(null)]
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
public string? CurrentWindowHandle { get; set; }

[LocalizedCategory("Data")]
[LocalizedDisplayName("WindowHandles")]
[LocalizedDescription("WindowHandles")]
[Browsable(true)]
[DefaultValue(null)]
public string[]? WindowHandles { get; set; }

 

웹 업무 자동화에서 셀레니움으로 연결을 시도하면 몇가지 문제가 발생합니다. 웹 브라우저는 서버로부터 응답을 받았을 때 다음 프로세스로 넘어갑니다. 하지만, 우리가 처리하는 데이터는 웹 기준으로 onload 이벤트가 발생해야 합니다. 이 문제를 처리하기 위한 다양한 방법들이 존재하는데요. 이건 나중에 자세히 알아보기로 하고, 일단은 간단하게라도 구동되는지 먼저 체크 해볼께요.

 

기본 설정 옵션입니다.

[LocalizedCategory("Setting")]
[LocalizedDisplayName("WebBrowser")]
[LocalizedDescription("WebBrowser")]
[Browsable(true)]
[DefaultValue(typeof(Ai.Definition.WebBrowserType), "Chrome")]
public Ai.Definition.WebBrowserType WebBrowser { get; set; } = Ai.Definition.WebBrowserType.Chrome;

 

지원하는 웹브라우저는 아래와 같이 3가지입니다. FireFox는 크로미움이 아니라서 공통적으로 처리하는데 문제가 있고, 몇몇 설정들은 아예 지원하지 않습니다. 그래서, 제외시킬지 고민중인데요. 엔지엠 6에서 제공하던 기능이라 약간의 제약이 있더라도 추가하는게 좋을거 같아요. 일단, 처리 로직은 그대로 두었습니다.

public enum WebBrowserType
{
    Chrome = 0,
    Edge = 1,
    FireFox = 2
}

 

크롬과 엣지의 옵션과 확장을 배열로 제공합니다. 그리고, 작업의 연속성을 유지하기 위해 이름을 설정하도록 해줍니다. 웹브라우저의 이름은 연결 정보를 내부에 저장하는 유니크한 키 값입니다. 웹브라우저에 연결된 드라이버를 통해서 마우스 클릭이나 키보드 텍스트 입력등등... 다양한 명령을 수행할 수 있습니다. 연결 정보가 사라지면 더이상 웹브라우저를 콘트롤할 수 없게 됩니다.

[LocalizedCategory("Setting")]
[LocalizedDisplayName("WebArguments")]
[LocalizedDescription("WebArguments")]
[Browsable(true)]
[DefaultValue(null)]
public string[]? Arguments { get; set; }

[LocalizedCategory("Setting")]
[LocalizedDisplayName("WebAdditionals")]
[LocalizedDescription("WebAdditionals")]
[Browsable(true)]
[DefaultValue(null)]
public List<Data.KeyValueItem> Additionals { get; set; } = new List<Data.KeyValueItem>();

[LocalizedCategory("Action")]
[LocalizedDisplayName("WebName")]
[LocalizedDescription("WebName")]
[Browsable(true)]
[DefaultValue(null)]
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
public string? WebName { get; set; }

 

홈페이지, 웹사이트에서 이동할 주소입니다.

[LocalizedCategory("Action")]
[LocalizedDisplayName("WebUrl")]
[LocalizedDescription("WebUrl")]
[Browsable(true)]
[DefaultValue(null)]
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
public string? Url { get; set; }

 

대기 시간을 설정합니다. UsePageLoaded는 지속되는 설정은 아닙니다. 연결 액션에서 페이지 이동시 완료 상태를 확인하기 위한 1회성 설정입니다. 나머지 Wait 옵션들은 페이지 응답과 요소 엘리먼트를 찾기 까지 대기 시간입니다. 이 둘의 설정은 암묵적인 지연 시간이므로 특수한 상황에서는 무시될수도 있습니다. 따라서, 이를 보완하기 위한 여러가지 로직을 추가로 구성해야 할수도 있습니다.

[LocalizedCategory("Action")]
[LocalizedDisplayName("UsePageLoaded")]
[LocalizedDescription("UsePageLoaded")]
[Browsable(true)]
[DefaultValue(false)]
public bool UsePageLoaded { get; set; }

[LocalizedCategory("Action")]
[LocalizedDisplayName("PageLoadCompleteWait")]
[LocalizedDescription("PageLoadCompleteWait")]
[Browsable(true)]
[DefaultValue(0)]
public int PageLoadCompleteWait { get; set; }

[LocalizedCategory("Action")]
[LocalizedDisplayName("ElementLoadCompleteWait")]
[LocalizedDescription("ElementLoadCompleteWait")]
[Browsable(true)]
[DefaultValue(0)]
public int ElementLoadCompleteWait { get; set; }

 

User Agent 정보를 설정하고 싶으면 아래 내용들을 추가해야 합니다. nuget에 RandomUA 페키지가 있으니 이걸 사용하면 쉽게 처리할 수 있습니다.

[LocalizedCategory("UserAgent")]
[LocalizedDisplayName("UserAgent")]
[LocalizedDescription("UserAgent")]
[Browsable(true)]
[DefaultValue(null)]
public string? UserAgent { get; set; }

[LocalizedCategory("UserAgent")]
[LocalizedDisplayName("UseRandomUserAgent")]
[LocalizedDescription("UseRandomUserAgent")]
[Browsable(true)]
[DefaultValue(false)]
public bool UseRandomUserAgent { get; set; }

[LocalizedCategory("UserAgent")]
[LocalizedDisplayName("RandomUserAgentOption")]
[LocalizedDescription("RandomUserAgentOption")]
[Browsable(true)]
[DefaultValue(typeof(UserAgentType), "All")]

 

아래 2개의 속성은 사용자 프로필을 사용해서 웹브라우저를 실행할 수 있도록 해줍니다. 이렇게하면 여러가지 문제가 될만한 것들을 우회할 수 있고, 테스트에도 용이합니다.

[LocalizedCategory("UserProfile")]
[LocalizedDisplayName("UserProfileDirectory")]
[LocalizedDescription("UserProfileDirectory")]
[Browsable(true)]
[DefaultValue(null)]
[Editor(typeof(TypeEditor.FolderSelectorEditor), typeof(UITypeEditor))]
public string? UserProfileDirectory { get; set; }

[LocalizedCategory("UserProfile")]
[LocalizedDisplayName("UserProfile")]
[LocalizedDescription("UserProfile")]
[Browsable(true)]
[DefaultValue(null)]
public string? UserProfile { get; set; }

 

웹 이름을 입력하지 않으면 액션이 실행되지 않도록 예외 처리를 해줍니다.

if (!Ai.Common.Helper.NullCheckAndWriteLine(player.Manager.Client, nameof(WebName), WebName))
    return id;

 

User Agent를 설정하는 방법은 아래와 같은데요. 패키지를 사용해서 처리하면 간단합니다. 또는 직접 랜덤 목록을 만들어서 텍스트 읽기로 처리해도 됩니다.

if (UseRandomUserAgent)
{
    switch (RandomUserAgentOption)
    {
        case UserAgentType.All:
            userAgent = new Random().Next(0, 2) == 0 ? MobileRandomUserAgent.RandomUserAgent : RandomUserAgent.RandomUa.RandomUserAgent;
            break;
        case UserAgentType.PC:
            userAgent = RandomUserAgent.RandomUa.RandomUserAgent;
            break;
        case UserAgentType.Mobile:
            userAgent = MobileRandomUserAgent.RandomUserAgent;
            break;
    }
}

 

문제를 피하기 위해서는 remote-debugging-port를 설정해서 사용하는게 좋습니다. 이 부분은 테스트를 통해서 알아볼께요.

OpenQA.Selenium.IWebDriver? driver = null;

switch (WebBrowser)
{
    case Definition.WebBrowserType.Chrome:
        var gService = ChromeDriverService.CreateDefaultService();
        gService.HideCommandPromptWindow = true;

        var gOption = new OpenQA.Selenium.Chrome.ChromeOptions();

        if (Arguments != null && Arguments.Length > 0)
        {
            foreach (var argument in Arguments)
            {
                if (argument.Contains("remote-debugging-port"))
                {
                    string[] kv = argument.Split('=');
                    gOption.DebuggerAddress = $"127.0.0.1:{kv[1]}";
                }
                else
                    gOption.AddArgument($"{argument}");
            }
        }

 

마지막으로 드라이버에 주소를 입력하면 웹브라우저가 실행되고, 사이트로 이동합니다. 이 후 처리 부분은 랜더링 후 처리되는 지연 설정과 실행 후 사용자에게 보여줄 결과 데이터 정보들입니다. 웹브라우저에 연결된 페이지가 여러개일수도 있기 때문에 목록을 보여주고, 현재 컨트롤하는 브라우저의 핸들 정보도 표시하도록 했습니다.

driver.Url = Url;

if (PageLoadCompleteWait > 0)
    driver.Manage().Timeouts().PageLoad = TimeSpan.FromMilliseconds(PageLoadCompleteWait);

if (ElementLoadCompleteWait > 0)
    driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(ElementLoadCompleteWait);

CurrentWindowHandle = driver.CurrentWindowHandle;
WindowHandles = driver.WindowHandles.ToArray();

if (UsePageLoaded)
    while (string.IsNullOrEmpty(driver.Title))

Title = driver.Title;

if (player.Manager.WebDrivers.ContainsKey(WebName))
    player.Manager.Output.WriteLine($"[{WebName}] {player.Manager.Client.ResxMessage.GetString("ExistsWebConnection")}", log4net.Core.Level.Warn);
else
    player.Manager.WebDrivers.Add(WebName, driver);

 

아래 동영상처럼 간단하게 테스트를 해볼께요.

https://youtu.be/Ql1N21MSEto

 

 

 

[ 각종 자동화 매크로 및 RPA 프로그램 제작 해드립니다. ]

[ 초보자도 쉽게 따라할 수 있는 기초 학습 강좌 보기 ]

 

원본 글 보기

http://ngmsoftware.com/bbs/board.php?bo_table=tip_and_tech 

 

엔지엠소프트웨어

엔지엠 매크로는 복잡한 반복작업을 자동화할 수 있습니다. PC 게임, 모바일 게임을 최적으로 지원하며 모든 PC 프로그램 및 업무에 적용할 수 있습니다.

www.ngmsoftware.com

 

반응형

댓글