NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (유튜브, 인스타그램, 네이버, 쿠팡등등... 자바스크립트 검색 방법)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 오늘은 웹 API에서 자바스크립트 실행 액션을 만들어 보도록 하겠습니다. 그리고, 웹 API에 추가한 여러가지 기능들을 조합해서 유튜브 검색을 만들어 볼께요. 이 테스트에서는 유튜브 검색만 진행했지만 인스타그램이나 네이버 스마트스토어, 쿠팡등등... 검색 기능을 가지고 있는 모든 사이트에서 상품을 검색해서 클릭할 수 있습니다. 물론, 몇가지 추가적인 설정들이 더 필요하지만 이 부분은 홍보나 마케팅 회사를 하시는 분들이 더 잘 알고 계실거예요.^^;

     

    유튜브에 검색어를 입력하려면 마우스 클릭 액션과 텍스트 쓰기 액션이 필요합니다. 그래서, 외부로부터 받아온 엘리먼트를 이용해서 처리할건데요. 아래와 같이 외부로부터 가져온 엘리먼트에 명령을 수행할 수 있도록 속성을 만들어줍니다. 외부로부터 온 엘리먼트가 아니더라도 자바스크립트로 가져온 엘리먼트들을 선택할때도 사용할 수 있습니다.

    [NonSerialized]
    private IWebElement? _currentElement = null;
    
    [NonSerialized]
    private List<IWebElement>? _elements = null;
    
    /// <summary>
    /// 현재 선택되어 있는 엘리먼트입니다.
    /// </summary>
    [LocalizedCategory("Data")]
    [LocalizedDisplayName("WebCurrentElement")]
    [LocalizedDescription("WebCurrentElement")]
    [Browsable(true)]
    [DefaultValue(null)]
    public IWebElement? CurrentElement
    {
        get { return _currentElement; }
        set { _currentElement = value; }
    }
    
    /// <summary>
    /// 웹드라이브에서 가져온 엘리먼트의 전체 목록입니다.
    /// </summary>
    [LocalizedCategory("Data")]
    [LocalizedDisplayName("WebElements")]
    [LocalizedDescription("WebElements")]
    [Browsable(true)]
    [DefaultValue(null)]
    [XmlIgnore]
    public List<IWebElement>? Elements

     

    자바스크립트를 실행하고 결과를 저장할 속성입니다.

    /// <summary>
    /// 자바스크립트를 실행하고 결과를 반환합니다.
    /// </summary>
    [LocalizedCategory("Data")]
    [LocalizedDisplayName("Result")]
    [LocalizedDescription("Result")]
    [Browsable(true)]
    [DefaultValue(null)]
    [EditorAttribute(typeof(MultilineStringEditor), typeof(UITypeEditor))]
    public string? Result { get; set; }

     

    자바스크립트가 실행된 후 만들어진 결과 값이 꼭 문자나 숫자는 아닐겁니다. 특정 요소(Element: 엘리먼트)가 될수도 있습니다. 그리고, 여러개의 엘리먼트를 선택할수도 있습니다. 그래서, 여러개의 엘리먼트중에서 하나만 선택할 수 있는 인덱스 속성도 추가 했습니다.

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

     

    배열의 경우는 특정 구분자를 이용해서 하나의 문자열로 합쳐줍니다. 귀찮아서 구분자를 일반적으로 사용하는 콤마(Comma)로 하드코딩 하려고 했지만~ 나중에 분명이 수정 요구가 나올거라서 속성으로 만들었습니다. 자유도가 높으면 어려워지고 자유도가 낮으면 쉬워지지만, 사용자에게 선택권을 주는쪽으로 개발하는게 좋을듯 합니다. 아무래도 개발 도구다보니 자유롭게 사용할 수 있도록 해주는게 더 유리하다고 판단하기 때문입니다.

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

     

    자유롭게 자바스크립트를 코딩할 수 있는 공간도 하나 만들어줄께요.

    /// <summary>
    /// 실행할 자바스크립트를 가져오거나 설정합니다.
    /// </summary>
    [LocalizedCategory("Action")]
    [LocalizedDisplayName("ExecuteJavaScript")]
    [LocalizedDescription("ExecuteJavaScript")]
    [Browsable(true)]
    [DefaultValue(null)]
    [EditorAttribute(typeof(MultilineStringEditor), typeof(UITypeEditor))]
    public string? JavaScriptCode { get; set; }

     

    이 액션을 사용하려면 어느정도 자바스크립트를 다룰줄 알아야 합니다. 자바스크립트도 엄연히 프로그래밍 언어의 한 종류(?)이기 때문에 개발과 검증이 필요합니다. 그래서, 전문적인 도구(Visual Studio Code)를 사용해서 먼저 테스트 해보고, JavaScriptCode 속성에 입력해서 동작 시켜보는게 좋습니다. 안그러면 수차례 반복하면서 테스트를 해야 할겁니다. 물론, 웹에서 간단하게 자바스크립트를 테스트 해볼 수 있는 사이트도 많으니 이런걸 이용해도 됩니다.

     

    사실, 자바스크립트 코드만 잘 사용해도 대부분의 기능 개발이 가능합니다. 나중에 추가할 기능이긴 하지만 웹소켓 액션들은 대부분 자바스크립트로 브라우저와 통신해야 합니다. 그리고, 소켓을 통해 직접 통신하기 때문에 웹 API와 같은 셀레니움을 우회할 수 있습니다. 그렇기 때문에 아무래도 개발이 더 복잡하고 어렵습니다. 하지만 늘 그렇듯이~ 우리는 목표를 가지면 꼭 해내고야 마는 능력자들이기 때문에 크게 문제되지는 않을겁니다.

     

    이제 이 코드를 실행할 수 있는 핵심 내용인데요. 좀 더 아름다운(?) 코드를 작성하고 싶었지만, 능력이 안되므로 조건을 분기해서 의식의 흐름대로 작성했습니다.

    public override string? Execute(IPlayer player)
    {
        CurrentElement = null;
        Elements = null;
        Result = null;
    
        var id = base.Execute(player);
    
        string? executeJS = Ai.Common.Helper.GetMatches(player, GetType().GetProperty(nameof(JavaScriptCode)), JavaScriptCode);
    
        var driver = player.Manager.WebDrivers[WebName];
    
        IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
        object result = js.ExecuteScript(executeJS);
    
        if (result != null)
        {
            Result = result.ToString();
    
            if (result.GetType().Name == "ReadOnlyCollection`1")
            {
                List<string> results = new List<string>();
    
                foreach (var item in (IEnumerable)result)
                {
                    if (item is IWebElement)
                    {
                        if (Elements == null)
                            Elements = new List<IWebElement>();
    
                        Elements.Add((IWebElement)item);
                    }
                    else
                        results.Add(item.ToString());
                }
    
                if (Elements != null && Elements.Count > 0)
                {
                    Result = Elements[ElementIndex].ToString();
                    CurrentElement = Elements[ElementIndex];
                }
                else
                    Result = string.Join(Separator, results);
            }
            else if (result is IWebElement)
            {
                Result = result.ToString();
                CurrentElement = (IWebElement)result;
            }
        }
    
        return id;
    }

     

    완성된 액션을 테스트 해볼까요? 테스트는 아래 동영상을 참고 해주세요.

     

     

    이 글이 도움이 되셨다면~ 커피 한잔이라도 후원 부탁드립니다^^

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

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

    댓글목록

    등록된 댓글이 없습니다.