PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : HttpWebRequests in .NET



Easysurfer
26.04.2010, 18:59
1. Einleitung:
Willkommen in meinem Tut über HttpWebRequests in .NET. Ich werde den Code jeweils in beide Sprachen “übersetzen”, das C# Coder, sowie VB.NET wissende beide was davon haben. Aber genug geredet, fangen wir an:


2. Warum HttpWebRequests?
Viele (meistens Anfänger) sehen in der Toolbox das WebBrowser Control und fangen an, mit diesem zu Arbeiten. Danach folgen Fragen wie “Wie klicke ich eine Radiobox an?????”, es folgen unsaubere Lösung und schlechter Code. Aber dieses ist nich der Hauptgrund, ich werde euch kurz ein paar Sachen aufzählen:


Das WebBrowser Control verwendet die IE6 Engine, das heist:



– Exploits können ausgeführt werden
– Seiten können zum Teil nicht richtig dargestellt werden
– Sehr langsamer Seitenaufbau



Das Laden von Bildern kostet ca. das 5 – 6 fache an Ladezeit
Multithreading nicht möglich
Keine Kontrolle über Abläufe was der Browser macht (auser die Document_Loaded Events)
Schwer Formulare auszufülllen

Das sind eigentlich die Hauptgründe, ich denke ich würde noch mehr finden http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif Dazu schauen wir uns kurz die Pro’s von HttpWebRequests an:


Wir senden direkt die Request, kein laden der Site und ausfüllen nötig
Schneller als das WebBrowser Control
Theoretisch ist es möglich, alles zu machen was der normale Browser auch kann (Ajax senden etc)
Multithreading (rulez <3 )
Genaue Kontrolle der Request (UserAgent, Cookies etc)

Der einzigste große Nachteil an HttpWebRequests ist eigentlich, das kein Javascript ausgeführt werden kann. Dieses kann man aber “simulieren” indem man den JS Code in C# umschreibt und da dann diverse Berechnungen etc durchführt.


3. WebClient und HttpWebRequest
Ich werde hier erst auf die WebClient Klasse eingehen, damit der Einstieg nicht all zu schwierig wird.


Der WebClient ist in der Lage jede beliebige Site herrunter zu laden (wenn auch ohne Cookies, wobei wenn man die Funktion überschreibt etc, sind da Sachen möglich http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif ). Des weitern kann super einfach Dateien heruntergeladen werden, sowie Dateien hochgeladen werden. Aber ein Beispiel sagtmehr wie tausend Worte:

System.Net.WebClient Client = new WebClient();
// Neue Inztanz
String GoogleSite =
Client.DownloadString("http://www.google.de");
// Wir laden die Google Mainpage
Client.DownloadFile("http://www.google.com/intl/images/logo.gif","googleLogo.gif");
// wir laden das Google logo runter und speichern es unter
//[ExecutePath]/googleLogo.gif

Dim Client As System.Net.WebClient = New WebClient()
' Neue Inztanz
Dim GoogleSite As String =
Client.DownloadString("http://www.google.de")
' Wir laden die Google Mainpage
Client.DownloadFile("http://www.google.com/intl/images/logo.gif","googleLogo.gif")
' wir laden das Google logo runter und speichern es unter
' [ExecutePath]/googleLogo.gif

Mit dem WebClient kann man schöne Sachen machen (Asyncron Datein runterladen, Proxy verwenden etc), aber wir wollen ja mehr ins Detail gehen. Also Weiter zu HttpWebRequest:
Ich werde erst auf die einfache Methode ohne POST eingehen (laden einer normalen Site), dann mit POST.


Der Aufbau einer HttpWebRequest sieht immer folgendermasen aus:
- Neue Inztanz
- Parameter Setzen (Cookies, UserAgent, Proxy etc)
- [POST String schreiben]
- Die Request abschicken und eine Response erhalten
- Mit den Cookies / Seiteninhalt von der Response weiterarbeiten
Ich werde im folgenden Beispiel genau diese Reihnfolge einhalten.


Die Inztanz erstellen

HttpWebRequest Request =
(HttpWebRequest)WebRequest.Create("http://google.de");

Dim Request As HttpWebRequest =
DirectCast(WebRequest.Create("http://google.de"),HttpWebRequest)

Hier wird eine Request Variable von Typ HttpWebRequest erzeugt. Diese wird zu einer HttpWebRequest von Typ WebRequest gecastet, dieses müsst ihr einfach so hin nehmen. Es gibt noch andre Typen von Requests (FTPRequest) etc, daher ist WebRequest die Basisklasse von dem.

Parameter setzen

request.CookieContainer = Cookies;
// Siehe Unten
request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.5(.NET CLR 4.0.20506)";
// Wir benutzen "Firefox"
Request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
// solche Infos sendet der Browser normalerweise mit
Request.KeepAlive = true;
Request.Method = "GET";
// es wird GET verwendet (beim normalen Laden)
Request.Timeout = 10000;
// nach 10 Sek wird abgebrochen
Request.Referer = "http://google.de/";
// wir kommen (anscheinded) bereits von Google :D
Request.ContentType = "application/x-www-form-urlencoded";
// das ist eine normale HTTPRequest

Request.CookieContainer = Cookies;
Request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
Request.KeepAlive = True
Request.Method = "GET"
Request.Timeout = 10000
Request.UserAgent = "Mozilla/5.0(Windows; U; Windows NT 5.1; de; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.5 (.NET CLR 4.0.20506)"
Request.Referer = "http://google.de/"
Request.ContentType = "application/x-www-form-urlencoded"

Zu dem Cookie Container komme ich später, nehmt das einfach mal so hin ^^ Die restlichen Angaben könnten sich so oder so ähnlich in einem Header einer Http-Request befinden, wie sie Firefox abschicken würde. Sollte euch das weiter interessieren, rate ich Euch zu einer Dokumentation zum HTTP Protokol http://easy-verbal.netne.net/wp-includes/images/smilies/icon_razz.gif


Post string “schreiben”
Jetzt kommt der komplizierteste Teil des ganzen Tutorials. In der Thoerie schreibt man diesen POST String folgendermasen:


wir fordern einen Stream an um die Post daten zu schreiben
wir schreiben in den Stream unsere Daten
wir schliesen den Stream und setzten die ContentLength

Dann mal zum Source:

string Post = "username=XXX&amp;password=XXX2";
// das wird gesendet
byte[] byteArray = Encoding.UTF8.GetBytes(Post);
// Die Post daten werden in ein Byte Array umgewandelt
Stream DataStream = Request.GetRequestStream();
// der Steam wird angefordert ;)
DataStream.Write(byteArray, 0, byteArray.Length);
// wir schrieben in den Stream unsere Post daten
DataStream.Close(); // immer schön zumachen
Request.ContentLength = byteArray.Length;
// wir setzen die ContentLengh auf die Anzahl
// der Zeichen in dem PostString

Dim Post As String = "username=XXX&amp;password=XXX2"
' das wird gesendet
Dim byteArray As Byte() = Encoding.UTF8.GetBytes(Post)
' Die Post daten werden in ein Byte Array umgewandelt
Dim DataStream As Stream = Request.GetRequestStream()
' der Steam wird angefordert ;)
DataStream.Write(byteArray, 0, byteArray.Length)
' wir schrieben in den Stream unsere Post daten
DataStream.Close() ' immer schön zumachen
Request.ContentLength = byteArray.Length
' wir setzen die ContentLengh auf die Anzahl
' der Zeichen in dem PostString

Wichtig ist noch bei der POST Request, in der Request.Method “POST” zu verwenden http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif


Die Request abschicken und eine Response erhalten
Da wir nun unsere schöne HttpWebRequest “gebaut” haben, schicken wir sie doch mal ab. Das geht im Prenzip so, das wir einfach eine Antwort anfordern(eine HttpWebResponse). Dann mal los:

HttpWebResponse Response =
(HttpWebResponse)Request.GetResponse();
// Wir müssen wieder casten ^^
DataStream = Response.GetResponseStream();
// hier wird der "Empfangsstream" angefordert
StreamReader reader = new StreamReader(DataStream);
// Mit einem StreamReader wird aus dem Empfangsstream gelesen
string ServerResponse = reader.ReadToEnd();
// Es wird alles gelesen, was der Webserver zurückgegeben hat
// (den Quelltext quasi)
reader.Close();
DataStream.Close();
Response.Close();
// alles Closen ^^

Dim Response As HttpWebResponse =
DirectCast(Request.GetResponse(), HttpWebResponse)
' Wir müssen wieder casten ^^
DataStream = Response.GetResponseStream()
' hier wird der "Empfangsstream" angefordert
Dim reader As New StreamReader(DataStream)
' Mit einem StreamReader wird aus dem Empfangsstream gelesen
Dim ServerResponse As String = reader.ReadToEnd()
' Es wird alles gelesen, was der Webserver zurückgegeben hat
' (den Quelltext quasi)
reader.Close()
DataStream.Close()
Response.Close() ' alles Closen ^^

Natürlich bietet die HttpWebResponse noch viel mehr Inhalte als nur den Seitenquelltext, aber darauf werde ich erst bei dem praktischen Beispiel drauf eingehen (Cookies, Header etc)


Mit den Cookies / Seiteninhalt von der Response weiterarbeiten
Was ihr jetzt damit macht, ist euch überlassen. Ihr könnt prüfen ob etwas in der “Antwort” vorkam wie z.B. “Login erfolgreich!”, ihr könnt Proxylisten per RegEx auslesen etc. Ich hoffe ihr habt das soweit alles verstanden, auf jeden fall gehts jetzt weiter http://easy-verbal.netne.net/wp-includes/images/smilies/icon_razz.gif

4. Praktisches Beispiel an Rapidshare
In dem Beispiel werden wir uns einloggen, prüfen ob der Login erfolgreich war und ein paar Daten auslesen. (obwohl das eigentlich Sinnlos ist, Stichwort Rapidshare API). Ist ja nur zu Übungszwecken http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif


Doch wie sehn wir, was überhaupt von dem Browser an Post-Daten geschickt wurde? Es könnte ja usrname, username, uname etc heisen? Dazu gibt es ein FirefoxAdd-On namens HttpLiveHeader. Diese Add-On snifft (lauscht) alle noch so kleinen Requests mit, die von Firefox gesendet werden und stellt diese dar. In der Darstellung bekommt man genau so ein paar Header zurück, wie ich sie oben Vorgestellt habe. Das Tool sollte ansich selbsterklärend sein. (vor dem Login aufrufen, einloggen und “Mitschneiden deaktivieren”. Nun die gesendeten Daten anschaun und in das Tool eintragen).


Ich habe hier mal die Rapidshare Login Request mitgeschnitten:


https://ssl.rapidshare.com/cgi-bin/collectorszone.cgi – hier geht die Request hin (nachzulesen im HTML Code unter <form action=”XX.cgi”>)

Content-Length: 39 – 39 Zeichen werden per Post gesendet

username=meinusername&password=mein1337Password – das ist der Post String.

Achja, ich verwende im folgenden die Funktion SendPost(URL,POST), um das ganze abzukürzen. Die Funktion findet ihr in dem Projekt, es ist einfach nur alle Schritte wie oben aneinander gereiht.

1. Der Login
Wir erhalten den Seitenquelltext wenn wir folgendes aufrufen:
String Login =
SendPost("https://ssl.rapidshare.com/
cgi-bin/collectorszone.cgi",
"username=meinusername&amp;password=mein1337password)

2. Der Check
Nun prüfen wir einfach ob in der Antwort das Wort “Logout” vorkommt (ist logischerweise nur da wenn man eingeloggt ist http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif )

If (Login.Contains("Logout")) //...

3. Das Auslesen der Premium Punkte
Ich schaue wo die Premiumpunkte im Quelltext stehen und schneide das “davor” und “danach” dann aus:

String Punkte = SplitOut("
Premium RapidPoints:
" _
+ "<strong><span>", "</span>", Login)

So, das wars auch schon http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif


5. Abschluss
Wenn ihr mein Beispielprogramm öffnen werdet, werdet ihr eine Variable namens “Cookies” finden. Dies ist ein Cookie Container der automatisch alle neuen Cookies die er empfängt (Cookies = Response.CookieContainer) erträgt, sowie diese weiter verwendet (Request.CookieContainer = Cookies). Also könnt ihr so auch Browsergamebots schreiben etc (das macht übrigens hammer Spass http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif )


Wenn Fragen oder Feedback gibt, meldet euch. Das Tutorial ist jetzt doch länger ausgefallen wie als ich eigentlich schreiben wollte ^^ Sorry http://easy-verbal.netne.net/wp-includes/images/smilies/icon_biggrin.gif Ich hoffe Ihr habt wenigstens ein bisschen was davon mitgenommen und könnt in Zukunft auf den WebBrowser als Control verzichten! xD


Greez easy


Download des Beispielprojekts:
Klick Mich (http://easy-verbal.netne.net/stuff/Rapidshare%20Checker%20Tutorial.rar)

(http://easy-verbal.netne.net/stuff/Rapidshare%20Checker%20Tutorial.rar)

DaPolo
27.04.2010, 09:24
schönes Tut, hatte Gestern erst ein ähnliches gesehen, welches jedoch nicht so gut kommentiert war ;) Danke!

NoNameMT
27.04.2010, 09:45
Wow, das Tutorial ist wirklich sehr umfassend geschrieben und gut erklärt und dokumentiert ;) kann man wirklich gut verstehen und ist für "Anfänger" gut zu gebrauchen :)

Gruß NoName

krypt0n
27.04.2010, 10:31
Unter C, C++, PHP, Python etc. kann ich übrigens libcurl empfehlen. Das Ding ist verdammt mächtig und unterstützt neben HTTP gleich noch viele andere Protokolle. Der einzige Nachteil ist, dass es etwas Übung braucht um das ganze wirklich mächtig anzuwenden.

sumrbr33z
02.06.2010, 14:07
Ich komm dank deines Tuts realtiv gut damit klar.
Doch hab ich eine Frage:
woher weiß ich was ich dem POST mitschicken soll?

alexj
05.06.2010, 14:31
Ich komm dank deines Tuts realtiv gut damit klar.
Doch hab ich eine Frage:
woher weiß ich was ich dem POST mitschicken soll?

Firefox Addon > Live HTTP Headers

Devil589
04.12.2010, 23:25
Sorry das ich so einen recht alten Thread noch mal ausgrabe aber mir stellt sich immer noch die Frage wie man an den PostString kommt.
Denn ich habe es mal versucht bei einer Suche und zwar bei dasoertliche.de und da finde ich leider nicht den PostString, sprich die Sachen die der übergibt.
Über eine Antwort würde ich mich freuen.

Vielen Dank.
See Ya!

100
04.12.2010, 23:40
Das "Formular" auf dasoertliche.de verschickt die Daten nicht mit der POST-Methode, sondern mit der so genannten GET Methode. Der Unterschied liegt darin, dass bei der Datenübergabe mit GET alle Parameter mit ihren Werten in der URL übergeben werden (index.php?param1=var1&param2=var2). Das hier ist zum Beispiel der GET-String von dasoertliche:


..dasoertliche.de/Controller?topKw=0&form_name=search_nat&context=0&choose=true&page=0&zvo_ok=0&ci=Wo&rci=yes&action=43&kw=Wen+oder+wasZur Erzeugung aller Parameter gibts da ne große Javascript Funktion.

Ansonsten eignet sich das FF Addon "Tamper Data" hervorragend, um solche Informationen herauszubekommen.

Devil589
05.12.2010, 09:22
Super danke für die Antwort.
Aber kann man bei meinem Fall (dasoertliche) dann auch die Sachen so machen wie hier beschrieben?
Denn egal was ich versuche bei string Post rein zu schreiben, bekomme ich immer einen Fehler.
Der Fehler taucht bei folgender Stelle mit folgendem Fehler auf: Stream DataStream = Request.GetRequestStream(); FEHLER: "Inhaltsteil mit diesem Verbtyp kann nicht gesendet werden"
Ich würde mich über Hilfe freuen.
Und könnte mir vielleicht einer sagen was genau bei dem Post string rein muss bezogen auf meinen Fall mit dasoertliche.de

Vielen Dank schon mal.
See Ya!

100
05.12.2010, 13:12
Ich habe doch schon gesagt dass dasoertliche.de nicht mit POST, sondern mit GET arbeitet. Der Seite ist es scheiß egal was du per POST sendest, denn sie will die Parameter+Inhalte über die URL bekommen. Wenn du wissen willst wie sich das zusammensetzt, dann schaust du dir so wie ich die URL oben an und wenn du genau wissen willst wie welche Parameter sich zusammensetzen, dann schaust du dir den Javascript-Teil an.

Devil589
05.12.2010, 13:18
Also ich habe die ganze Zeit GET genutzt nur damit ging es ja nicht.
Dann habe ich es mal auf POST geändert und siehe da es klappt nun. ;)
Trotzdem danke.

See Ya!

100
05.12.2010, 13:21
Dann hast du irgendwas gemacht wovon du nicht weißt was du tust, denn die Seite nimmt immernoch nur GET Parameter an, da kannst du so viel "posten" wie du willst.

Devil589
05.12.2010, 14:47
Also ich habe den String "Post" so gemacht:

string Post = "Controller?topKw=0&form_name=search_nat&context=0& choose=true&page=0&zvo_ok=0&ci=ORT&rci=yes&action=43&kw=NAME";

Für ORT und NAME habe ich natürlich Namen eingesetzt.
Und beim WebRequest.Create habe ich auch "http://dasoertliche.de" eingesetzt.
Und wie bereits gesagt Request.Method = "POST".
Und komischerweise klappt es mit POST aber mit GET nicht.
Und ich habe mir dann den Sourcecode anzeigen lassen und in dem Sourcecode der Seite tauchen dann auch die Suchergebnisse auf mit dem Namen und Ort den ich in dem Poststring mit gegeben habe.
Aber ich versteh halt nicht wieso es nicht mit GET geht. (komisch)

See Ya!

100
05.12.2010, 14:58
Du musst bei GET die Variablen in der URL anhängen, und nicht mit irgendeinem String mitsenden. Ich glaube mit dem GET im Script ist was anderes gemeint :P

Devil589
05.12.2010, 15:32
Also wenn ich dich jetzt richtig verstanden habe müsste ich also dann nur sowas hier machen?

string Post = "ci=ORT&kw=NAME";

Weil das sind ja die beiden Felder die ausgefüllt werden bei der Suche.
Also das sind die Namen der Textboxen.
Und bei Request.Method dann natürlich GET.

Vielen Dank schon mal.
See Ya!

100
05.12.2010, 16:03
Nein man das gehört an die URL dran ganz einfach :D
An der Stelle wo du die URL einträgst die aufgerufen werden soll musst du das einfach dranhängen. Aber wenn es anders funktioniert so wie du sagst ist das ja auch erstmal in Ordnung. Für mich sind GET Parameter aber ausschließlich die, die man an die URL dranhängt, und das sind definitiv nicht die regulären POST Parameter.

Atropos
05.12.2010, 16:47
Super Tutorial

@GET-Frage:


WebClient web = new WebClient();
string data = "feld1=kkk&feld2=jjj";
string response = web.DownloadString("http://deineurl.com/index.php?" + data);

Hab das jetzt am Handy aus dem Kopf geschrieben also bei Fehlern nicht schlagen ;).

//edit:
Die Streamvariante ist zwar schöner, braucht aber mehr Platz ;).