WebBrowser e pagine di login: metodologie di "fill in" e submit dei f...

mercoledì 16 dicembre 2009 - 14.31

pinoba Profilo | Newbie

Ciao,
sono nuovo e mi sono iscritto per risolvere proprio un problema analogo, e sono finito anche io dentro questi menaggi.

Vi introduco il problema:
dato di avere un form con campi userID, password, un campo chiamiamolo di dominio e un tasto Loggami!
riempire il form nelle due input (caselle di testo html) e premere Loggami da codice.

Ho studiato il problema dopo aver visto che tanti tentativi non sono serviti.
SUlla rete ci sono uan valanga di medori differenti per compilare i due campi, tra cui:

1) usare HtmlDocument e accedere ai campi interni (i vari tag) tramite ID e poi lanciare un SetAttibute del campo specifico che si vuole aggiornare.
2) lanciare, una volta ottenuto il fuoco sulla pagina dei SendKey in modo da fare in modo che la schermata riceva dei segnali come se si fosse in manuale con un utente davanti allo schermo
3) incorporare mshtml e usare i metodi dell'interfaccia 2(la faccio breve qui, ma in sostanza si parla di usare HTMLDocument invece di HtmlDocument in modo da accedere al wrapper non gestito) in modo da avere a disposizione metodi non comuni a tutti i controlli, come l'evento click(), ecc...
4) altri usi e abusi fino alla reflection.... che evito di menzionare perchè tanto funzionano più o meno tutti e i primi sono molto più semplici.

Poi, una volta riempiti i campi, si deve lanciare il submit, e anche qui altre alternative:

A) ancora reflection, se trovo il link della pagina in cui l'ho visto ve lo allego
B) SendKeys con una sequenza appropriata per simulare un utenza umana del form,
C) lanciare InvokeMember sul HtmlElemt che raprpesenta il tasto (ovvero la input di tipo "submit" sempre per farla breve).

Ovvaimente il terzo è quello che viene in mente a tutti visto che a tutti funziona.

Io non ci sono ancora riuscito.... non conosco l'Html e quindi pensavo di farla franca semplicemente copiando e incollando una versione adattata dei codici precotti che si trovano in giro ma nulla.
Da qui ho fatto un po' di teora e mi sono accorto che i form hanno più di un tipo, ci sono i SET e i POST.

Fine della premessa, inizio delle domande...

Ma siamo sicuri che l'invokeMember funzioni sempre?
Inoltre, il metodo SetAttribute permette di modificare l'html presente nel controllo webbrowser, non il relativo input element sul web vero e proprio (lato server), quindi un'istruzione del genere come prima cosa non ha creato la compilazione a video nel webBrowser del campo associato e visualizzabile (ad esempio una casella di testo).
Tutto questo per dire che in realtà non succede poi molto dopo l'invocazione di SetAttribute (che peraltro funziona, ovvero richiedendo di restituire il paramentro appena settato, in effetti il codice restituisce il nuovo valore) a meno che poi tutti questi campi modificati (che si suppone appartengano ad un form di cui poi si farà la submission) non vengano poi lanciati in un processo lato server che li processa al click del submit (normalmente un input tag di tipo submit come dicevo prima).
Ora, il mio problema è proprio qui, ci sono dei form che hanno una sumission di tipo SET e una di tipo POST.
Posto che non conosco molto pdi più di HTML di quanto non abbia affrontato finora per riempire un form in C#, mi pare di aver capito che il metodo SET passa tutto in chiaro all’interno della stringa di testo della nuova pagina da navigare (parametri separati da una &) e il modo POST invece genera qualche script all’interno della pagina e poi chissà che altra diavoleria. Sarebbe bello che qualcuno me lo spiegasse in dettaglio soprattutto per capire dove andare a prendere il metodo che viene lanciato quando al action del form è action ="#", quindi un rimando all'inizio del documento).

Ora, ma un form che sia di tipo POST e che come action abbia qualcosa del tipo action=”#” dove ce l’ha il codice di esecuzione della submit?!??!?

Come faccio a capire quale metodo chiama e se effettivamente il bottone che fa il sumbit fa effettivamente il submit?
Faccio un esempio e riporto qui un paio di righe web per referenza

<form method="post" name="loginForm" id="loginForm" action="#">
<input name="yyy_id" value="pippo" type="hidden">
<input name="v" value="2" type="hidden">
<input name="is_utf8" value="0" type="hidden">
<div id="input_xxx">
<select name="name2" id="idname2" class="input_2" tabindex="1">
<option selected="selected" value="valueoption1" onclick="setField('pippo'); setPasswordlostUrl('urlettino_diverso');"> Text_of_Option_1 </option>
<option value=" valueoption2" onclick="setField(‘pluto’); setPasswordlostUrl(altro_urlettino_diverso);"> Text_of_Option_2 </option>
</select>
</div>
<div id="input_background">
<input name="login" id="inputform" alt="Nome Utente" value=" " maxlength="20" tabindex="2" onclick="play('enterTextfield', 80); if(this.value == 'Nome Utente') this.value = '';"
onblur="if(this.value == '') this.value= 'Nome Utente';" onkeydown="play('typing', 80)" type="text">
</div>
<div id="password_background">
<input name="pass" id="passwort" alt="Password" maxlength="32" tabindex="3" onclick="play('enterTextfield', 80);" onkeydown="play('typing', 80)" type="password">
</div>
<input name="submitInput" id="login_button" onmouseover="play('bigHover', 80);" onclick="play('bigClick', 80);" tabindex="4" value="Login" type="submit">
</form>


Se lancio con l’invokeMember il metodo onClick, tutto quelli che succede è il play sonoro o c’è qualcosa di più? Chi me lo sa spiegare in termini semplici?
E soprattutto, come fa il submit sul sito a conoscere i valori delle variabili di cui ho modificato il valore se risiedono solo sul lato client? Immagino che al momento del submit la pagina passi i campi che possiede, cioè delle celle vuote o comunque non ancora modificate.

Qualcuno mi sa dare una dritta sul principio di funzionamento di queste cose?

G1000
Ale


RISOLTO:
Mi rispondo da solo..

Sono risucito a fare un login in una schermata con metodo POST di submission senza toccare la parte javascript e senza interessarmi dei metodi php scritti all'interno della pagina.
Posto qui alcune considerazioni per tutti quegli utenti che non conoscono HTML e ci si addentrano solo per risolvere il loro problema.
Non serve cercare all'interno di un tag delle propietà tipo onclick, oppure onblur per essere sicuri che quel particolare tag possa gestire un particolare evento.
Per esempio una tag INPUT che cha solo proprietà value="login", type="submit", onclick='fai_operazione1()', onblur='fai_operazione2()' ecc. è anche in grado di rispondere all'evento click.
Quindi basta invocare tramite InvokeMember("click") il metodo associato e il bottone sulla pagina web inserita dentro il bwebrowser si skiaccia ed esegue tutto il codice lato server che era supposto dover fare.
Per chiunque volesse capire meglio come riempire una shcermata di questo tipo, riporto qui il metodo per entrare in Ogame.it



public void DoLogin()
{
Program.originOfNavigation = OriginOfDocumentCompleted.login;
Program.browserHandler.Navigate("http://www.ogame.it");
}

public void DoLogin2()
{
HtmlDocument htmlPageLogin = Program.browserHandler.Document;

//NOTE: Settaggio combo per l'universo
HtmlElement selectUniverseCombo = htmlPageLogin.GetElementById("uni_select_box");
if (selectUniverseCombo.TagName == "SELECT")
{
//TODO
foreach (HtmlElement option in selectUniverseCombo.Children)
{
if (option.GetAttribute("value") == "uni13.ogame.it")
{
option.SetAttribute("selected", "true");
break;
}
}
}
else
{
throw new Exception("DoLogin2: UNI SELECT BOX not present!");
}

//NOTE: Settaggio username
HtmlElement userName = htmlPageLogin.GetElementById("login");
if (userName.TagName == "INPUT")
{
userName.SetAttribute("value", Program.settings.Username);
}
else
{
throw new Exception("DoLogin2: USERNAME box not present!");
}

HtmlElement passwordField = htmlPageLogin.GetElementById("passwort");
if (userName.TagName == "INPUT")
{
passwordField.SetAttribute("value", Program.settings.Password); // VERIFY: il tag non ha campo value: e invece funziona! Assurdo!
}
else
{
throw new Exception("DoLogin2: PASSWORD box not present!");
}

HtmlElement submitButton = htmlPageLogin.GetElementById("login_button");
if (userName.TagName == "INPUT")
{
object obj = submitButton.DomElement;
System.Reflection.MethodInfo mi = obj.GetType().GetMethod("click"); //NOTE: parsing type@runtime, wrap in Invokemember() asap
mi.Invoke(obj, new object[0]);
}
else
{
throw new Exception("DoLogin2: SUBMIT BUTTON not present!");
}
}

Per capire esattamente cosa sto facendo basta guardare l'html delal pagina relativa al sito di Ogame italia.

Moreover,
il metodo è diviso in due parti in quanto resta sempre necessario intercettare l'evento DocumentCompleted(), che serve per assicurare al processore di parsing che tutto l'html sia già stato caricato nel webBrowser (altrimenti si finisce sicuramente in un NullArgumentException).
In sostanza DoLogin() lancia una navigazione, che a sua volta genera un evento documentCompleted e il metodo di genstione del documnetCompleted contiene un'utiltiy per capire chi lo ha generato (lo faccio con un enum globale) e lancia il Dologin2().
DoLogin2 usa la reflection ma ciò non è strettamente necessario, è solo difficile da capire, lento e molto prolisso. Molto probabilmente funziona anche con un InvokeMember o un RaiseEvent(), ma lascio ai posteri il responso.

Altre note a margine:
- il webBrowser non è in sola lettura, o solo lato client come dir si voglia, cambiando una prorietà value di una input box si cambia anche la pagina e quando si fa un submit, il sistema invia tutte le informazioni come essec sono un istante prima del click sul bottone.
- POST e SET come metodi di submit non influenzano minimamente la cosa, in quanto in ogni caso il metodo riportato sopra ripete fedelmente quello che farebbe un utente umano davanti alla pagina in IE e l'utente non si interessa dell'implementazione. Teorema noto a tutti.
- ovviamente quanto detto qui sopra non vale se invece di eseguire l'evento click del bottone di submission si esegue invece una chiamata diretta alla pagina successiva (supposto che uno la conosca), in questo caso si inviano le informazioni originali e non modificate e il login fallisce.

Sperro che questo aiuti chi vorrà fare un login a qualsiasi altro sito.

Ciao!


Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2023
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5