2017-02-06 7 views
3

GeckoFx을 사용하여 특정 웹 사이트에 로그인합니다. 이 웹 사이트는 로그인이 실패한 경우 (또는 ReCaptcha와 같은 추가 인증이 필요한 경우) 새 정보로 페이지를 편집합니다. 불행히도, 페이지가 업데이트 될 때 이벤트에 액세스해야합니다. 나는 display: none 속성이 변경된 경우 주로C#에서 GeckoFx의 MutationObserver 사용?

  • uri 여전히 각 로그인 시도 및 문제의 특정 요소에 대한 후속 체크인시 동일한 경우 계속 검사 (보고 다양한 방법을 시도했습니다. (이 결과 무한 루프로 보이는 것처럼 GeckoFx은 페이지를 비 차단 방식으로 업데이트하여 프로그램이 무한 루프가되도록합니다.
  • 로그인 요청 사이에 약 5 초 동안 잠자기 상태이고 전술 한 uri 검사를 사용하여 잠자기합니다. 빨대를 쥐고 ​​있었다) 브라우저가 5 초 동결 되어도 여전히 페이지를 업데이트하지 못했습니다.
  • DocumentCompleted 이벤트와 비슷한 페이지가 업데이트 될 때 특정 이벤트에 대해 GeckoFx 코드베이스를 검색합니다 (그러한 행운은 없습니다).

내가 읽은 가장 일반적인 접근 방식은 가장 적합합니다 (MutationObserver). 인터넷을 통한 모든 대답에는 필요한 작업을 수행하기 위해 Javascript을 주입하는 것이 포함 된 것으로 보입니다. 내 모든 프로그래밍 배경이 웹 개발에 전혀 영향을 미치지 않았 음을 알고, 나는 내가 아는 것에 충실하려고 노력하고있다.

여기 내 접근 방식은 지금까지 불행히도 그리 많지 않습니다. 코멘트에 위의 코드에 명시된 바와 같이

public class GeckoTestWebLogin 
{ 
    private readonly string _user; 
    private readonly string _pass; 
    public GeckoWebBrowser Gweb; 
    public Uri LoginUri { get; } = new Uri("https://website.com/login/"); 

    public bool LoginCompleted { get; private set; } = false; 
    public bool Loaded { get; private set; } = false; 

    public GeckoTestWebLogin(string user, string pass) 
    { 
     _user = user; 
     _pass = pass; 
     Xpcom.EnableProfileMonitoring = false; 
     Xpcom.Initialize("Firefox"); 

     //this code is for testing purposes, it will be removed upon project completion 
     CookieManager.RemoveAll(); 

     Gweb = new GeckoWebBrowser(); 
     Gweb.DocumentCompleted += DocLoaded; 

     //right about here is where I get lost, where can I set a callback method for the observer to report back to? Is this even how it works? 
     MutationObserver mutationObserver = new MutationObserver(Gweb.Window.DomWindow, (nsISupports)Gweb.Document.DomObject); 
    } 

    private void TestObservedEvent(string parms, object[] objs) 
    { 
     MessageBox.Show("The page was changed @ " + DateTime.Now); 
    } 

    public void DocLoaded(object obj, GeckoDocumentCompletedEventArgs e) 
    { 
     Loaded = true; 
     if (Gweb.Url != LoginUri) return; 
     AttemptLogin(); 
    } 

    private void AttemptLogin() 
    { 
     GeckoElementCollection elements = Gweb.Document.GetElementsByTagName("input"); 
     foreach (GeckoHtmlElement element in elements) 
     { 
      switch (element.Id) 
      { 
       case "username": 
        element.SetAttribute("value", _user); 
        break; 
       case "password": 
        element.SetAttribute("value", _pass); 
        break; 
       case "importantchangedinfo": 
        GeckoHtmlElement authcodeModal = 
         (GeckoHtmlElement) 
          Gweb.Document.GetElementsByClassName("login_modal").First(); 
        if (authcodeModal.Attributes["style"].NodeValue != "display: none") 
        { 
         InputForm form = new InputForm { InputDescription = "Captcha Required!" }; 
         form.ShowDialog(); 
         elements.FirstOrDefault(x => x.Id == "captchabox")?.SetAttribute("value", form.Input); 
        } 
        break; 
      } 
     } 
     elements.FirstOrDefault(x => x.Id == "Login")?.Click(); 
    } 

    public void Login() 
    { 
     //this will cause the DocLoaded event to fire after completion 
     Gweb.Navigate(LoginUri.ToString()); 
    } 
} 

는, 나는 완전히 내가 나를 설정할 수 있습니다 것 MutationObserver에 대한 GeckoFx의 소스에서 아무것도 찾을 수 없습니다

MutationObserver mutationObserver = new MutationObserver(Gweb.Window.DomWindow, (nsISupports)Gweb.Document.DomObject); 

에서 손실입니다 콜백/이벤트/whathaveyou. 나의 접근 방식은 일을하는 올바른 방법인가 아니면 Javascript을 페이지에 삽입하는 것 이외의 다른 옵션으로 남지 않았습니까?

많은 의견 부탁드립니다.

(GeckoTestWebLogin 현황)

public void DocLoaded(object obj, GeckoDocumentCompletedEventArgs e) 
    { 
     Loaded = true; 
     if (Gweb.Url != LoginUri) return; 

     MutationEventListener mutationListener = new MutationEventListener(); 
     mutationListener.OnDomMutation += TestObservedEvent; 
     nsIDOMEventTarget target = Xpcom.QueryInterface<nsIDOMEventTarget>(/*Lost here*/); 
     using (nsAString modified = new nsAString("DOMSubtreeModified")) 
      target.AddEventListener(modified, mutationListener, true, false, 0); 

     AttemptLogin(); 
    } 

MutationEventListener.cs :

public delegate void OnDomMutation(/*DomMutationArgs args*/); 

public class MutationEventListener : nsIDOMEventListener 
{ 
    public event OnDomMutation OnDomMutation; 

    public void HandleEvent(nsIDOMEvent domEvent) 
    { 
     OnDomMutation?.Invoke(/*new DomMutationArgs(domEvent, this)*/); 
    } 
} 

답변

2

내가 Geckofx의 webidl compiler는 생각하지 않는다 여기

톰의 대답에 옵션 2에서 내 시도 현재 콜백 생성자를 생성 할만큼 충분히 고급입니다.

옵션 1 - 개선 변이원 소스.

MutationObserver 소스를 수동으로 수정하여 필요한 생성자 콜백을 추가 할 수 있습니다. 그런 다음 Geckofx를 다시 컴파일하십시오. (나는 이것이 얼마나 어려운지를 보지 못했다)

옵션 2 - 구식 뮤 테이션 이벤트를 사용한다.

public class DOMSubtreeModifiedEventListener : nsIDOMEventListener 
{ 
    ... // Implement HandleEvent 
} 

다음과 같은 (아마도 DocumentCompleted 이벤트 처리기에서) :

_domSubtreeModifiedEventListener = new DOMSubtreeModifiedEventListener(this); 

    var target = Xpcom.QueryInterface<nsIDOMEventTarget>(body); 
    using (nsAString subtreeModified = new nsAString("DOMSubtreeModified")) 
     target.AddEventListener(subtreeModified, _domSubtreeModifiedEventListener, true, false, 0); 

옵션 3 - 사용 유휴 + 확인하십시오.

winforms Application.idle 이벤트 처리기를 추가하고 문서를 검사하여 준비가되었는지 확인하십시오.

옵션 4 - 자바 스크립트 콜백을 삽입하십시오.

(이미 언급했듯이) -이 예제는 크기 조정이 완료 될 때까지 대기 중입니다.

기본적으로 주입 : "<body onresize=fireResizedEventAfterDelay()>" 값 : C#에서 다음

string fireResizedEventAfterDelayScript = "<script>\n" + 
      "var resizeListner;" + 
      "var msDelay = 20;" + 
      "function fireResizedEventAfterDelay() {" + 
      "clearTimeout(resizeListner);" + 
      "resizeListner = setTimeout(function() { document.dispatchEvent (new MessageEvent('resized')); }, msDelay);" + 
      "}\n" + 
      "</script>\n"; 

:

browser.AddMessageEventListener("resized", (s) => runafterImDone()) 
+0

안녕하세요, 옵션 2를 시도했습니다, 그러나, 유일한 적절한 참조 내가 찾을 수있는 다음과 같은 뭔가를 주입 'var target = Xpcom.QueryInterface (X);에 대해'WindowRoot'는'Window.cs'에서'WindowRoot'였습니다. 그러나'GeckoWindow.cs'가'Window.cs'를 확장하는 동안 앞에서 언급 한'WindowRoot' 속성을 드러내지 않는 것처럼 보일 것입니다. 내가 잘못된 방향으로가는거야? 내 원래의 질문에 내 시도의 관련 부분을 포함 시켰습니다. –

+1

var body = browser.Document? .Body? .DOMHtmlElement; – Tom

+0

아, 지금 어리 석다. .. Tom에 감사한다! –