Entwickler-Ecke

Programmierwerkzeuge - Einbinden einer Suchmaschine/Search Engine?


BlackMatrix - Sa 21.04.12 11:47
Titel: Einbinden einer Suchmaschine/Search Engine?
Hi.

Ich möchte gerne ein Suchmaschine in mein Programm einbinden, aber bisher habe ich noch keinerlei funktionierende Lösung gefunden.

Ich habe versucht über den WebRequests/WebClient Anfragen an http://www.google.de/search?q=suchbegriff zu senden, aber nachdem man einige Suchergebnisseiten "durchgeklickt" hat, wird man aufgefordert ein Captcha einzugeben.
Dann habe ich bereits versucht die Google Search API zu benutzen, aber wie ich rausgefunden habe, bietet diese auch einfach nur einen Webrequest an http://ajax.googleapis.com/ajax/services/search/web?v=1.0&rsz=large&q=suchbegriff
Die Suche scheint zwar zu funktionieren, aber ich glaube, die API hat Probleme damit Parameter wie inurl:, site: anzuwenden. Ich bekomme deutlich weniger Ergebnisse als wenn ich direkt über Google Suche.

Welche Suche es im Endeffekt ist, ist mir egal, sofern die Suchergebnisse akzeptabel sind. Hat das schon mal jemand umgesetzt?

Liebe Grüße


Oliver M. - Mo 23.04.12 17:37

Ich habe schon öfter Suchmaschinen in meine Programme eingebunden, und kann dir ein paar Tips geben:
Ich schicke dir per PN ein Beispiel für eine Youtube-Suche, die der Google-Suche ja sehr ähnelt, ich hoffe es hilft dir. Leider kann ich das Beispiel hier nicht öffentlich reinstellen, da der Code nur teilweise von mir ist.

MfG Oliver


Oliver M. - Sa 28.04.12 21:29

Ich weiß nicht was du willst! Das geht doch einwandfrei!!!


BlackMatrix - Mo 30.04.12 00:09

user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:
Ich weiß nicht was du willst! Das geht doch einwandfrei!!!


Dank dir. Die Suche funktioniert auch, will man aber z.B. alle Links mit den gefunden Textstellen rausparsen müsste man alle Seiten von 1-X durchlaufen.

Mein Code, der mich nach einer Weile ein Captcha eingeben lässt:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
        public string Search(string searchString)
        {
            int start = 0;
            WebClient wc = new WebClient();
            string html = string.Empty;
            do
            {
                html += wc.DownloadString(string.Format("http://www.google.de/search?q={0}&start={1}", searchString, start));
                start += 10;
                // Thread.Sleep(5000);
            } while (html.Contains("<b>Weiter</b>"));
            return html;
        }



Man kann auch optional noch Sleeps einbauen, das verändert aber nicht das Ergebnis, dass man irgendwann einen Timeout vom Google Server bekommt. Es wird zusätzlich zu den Cookies noch irgendwelcher Javascriptmist generiert, der den Aufruf von bestimmten Urls zur Folge hat. Ein korrekter Browseraufruf und Ablauf hat zur Folge, dass man keine Captchas eingeben muss, das bekomme ich aber nicht hin :/

MfG


Oliver M. - Di 01.05.12 09:28

Du willst ALLE Suchergebinsse auslesen? Das sind laut Google meist so ca. 1.340.000.000! LAss einfach den Benutzer ein Limit setzten, wieviele Ergebnisse er haben möchte (Siehe Anhang).
MfG Oliver


BlackMatrix - Di 01.05.12 13:52

user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:
Du willst ALLE Suchergebinsse auslesen? Das sind laut Google meist so ca. 1.340.000.000! LAss einfach den Benutzer ein Limit setzten, wieviele Ergebnisse er haben möchte (Siehe Anhang).
MfG Oliver


Hab mir mal den Regex geklaut :)

Dem Benutzer stehen nur eine Vielzahl von Suchbegriffen zur Verfügung. Diese Suchbegriffe sind so speziell, dass dabei niemals mehr als 30 Seiten abgesucht werden müssen. Das spielt aber keine Rolle, denn selbst wenn ich immer nur eine Seite absuche, aber dafür 30 verschiedene Suchbegriffe, irgendwann lässt mich Google nicht mehr zu deren Server verbinden. Egal wieviel Sleeps ich zwischen den Abfragen einbaue, irgendwann passiert das, weil ich keine Cookies, Javascript und vllt sogar auch Bilder runterlade. Dafür soll ja die API benutzt werden, die aber meiner Meinung nach noch mehr eingeschränkt ist, als die Requests selber zu machen.
Die einzige Möglichkeit, die ich im Moment noch sehe ist ein WebBrowser Control zu nehmen und damit die Requests zu machen, das regt mich aber jetzt schon auf :/


glotzer - Di 01.05.12 14:40

BlackMatrix hat folgendes geschrieben:
Dafür soll ja die API benutzt werden, die aber meiner Meinung nach noch mehr eingeschränkt ist, als die Requests selber zu machen.

vieleicht ist das ja der Sinn der ganzen Sache: die Abfragen einzuschränken?


Oliver M. - Di 01.05.12 15:21

Ich verstehe nicht ganz, zu welchem Zwech das ganze gut ist. Vielleicht könntest du ja sagen, warem du so viele Google-Suchen auf einmal machen möchtest. Das könnte helfen.
MfG Oliver


BlackMatrix - Di 01.05.12 17:20

Ich möchte meine Datenbank mit URLs füllen.

Um möglichst auf aktuellem Stand zu sein, versuche ich Google einzubeziehen.


FinnO - Di 01.05.12 18:09

Gut, daran wird Google wohl wenig interesse haben.


Oliver M. - Mi 02.05.12 19:04

Du möchtest also einfach irgend welche URLs in eine Datenbank füttern? Ich kann mir nicht zusammenreimen, warum. Jedenfalls wünsche ich dir viel Spaß :lol:


BlackMatrix - Di 15.05.12 17:25

Vielleicht kann mir jemand bei der Verwirklichung helfen.

Es geht nun um einen allgemeinen WebRequest/WebResponse Sache.

Wenn ich zuviele Anfragen an die Google Suche gesendet habe, dann muss ich ein Captcha eingeben. Wenn ich den Ablauf mit LiveHttpHeaders oder HttpFox mitschneide, dann werde ich von meiner Such-URL auf

http://www.google.com/sorry/?continue=http://www.google.de/search?q=searchString

weitergeleitet.

Wenn ich nun meine Suchanfrage mit einem WebRequest nachbauen will, dann bekomme ich eine WebException:

C#-Quelltext
1:
Der Remoteserver hat einen Fehler zurückgegeben: (503) Server nicht verfügbar.                    


Ich habe Cookies und Javascript im Browser abgeschalten, sende keinen Referer und trotzdem will die Weiterleitung beim WebRequest nicht funktionieren.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
                // Request
                var request = (HttpWebRequest)WebRequest.Create(uri);
                request.CookieContainer = _cookieContainer;
                request.UserAgent = UserAgent; // Firefox 12
                request.AutomaticDecompression = _automaticDecompression; // GZIP | DEFLATE
                request.KeepAlive = true;
                request.MaximumAutomaticRedirections = MaximumAutomaticRedirections; // 5
                request.AllowAutoRedirect = allowAutoRedirect; // true
                request.Headers.Set(HttpRequestHeader.AcceptLanguage, AcceptLanguage); // de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
                var response = (HttpWebResponse)request.GetResponse();
                Stream stream =  response.GetResponseStream();




Also ich rufe


C#-Quelltext
1:
http://www.google.de/search?q=searchString                    


auf, da werde ich im Browser auf:


C#-Quelltext
1:
http://www.google.de/sorry/?continue=http://www.google.de/search?q=searchString                    


weitergeleitet.

Das funktioniert nicht beim WebRequest, obwohl die Weiterleitung eingeschalten ist.


Oliver M. - Mi 16.05.12 19:17

Vielleicht hilft es, wenn du zwischen den Abfragen einen variablen Zeitraum wartest, also das einbaust:

C#-Quelltext
1:
Thread.Sleep(new Random().Next(103000));                    

Das braucht zwar ein wenig länger, aber vielleicht trickst du so Google aus. Sonst halt Verbindug über einen Proxy leiten.


platzwart - Mi 16.05.12 20:49

Oder sich einfach an die Spielregeln von Google halten und nicht einfach so fremde Leistungen abgreifen...


Oliver M. - Mi 16.05.12 21:05

Das ist natürlich das Besste, Einfachste und Sinnvollste.


BlackMatrix - Mi 16.05.12 21:10

user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:
Vielleicht hilft es, wenn du zwischen den Abfragen einen variablen Zeitraum wartest, also das einbaust:

C#-Quelltext
1:
Thread.Sleep(new Random().Next(103000));                    

Das braucht zwar ein wenig länger, aber vielleicht trickst du so Google aus. Sonst halt Verbindug über einen Proxy leiten.


Schon ausprobiert. Das hatte ich mir auch gedacht, aber das bringt nichts. Das ist ein Parameter der vib Google wahrscheinlich am wenigsten kontroliert wird. Google schaut eher, ob Javascript und Cookies funktionieren.

Ansonsten, sobald eben dieser Captchamechanismus von Google eingeleitet wurde, kann ich mit meinem HttpWebRequest einfach nicht mehr diese URL aufrufen ttp://www.google.de/search?q=searchString, obwohl es im Firefox ohne Cookies und Javascript (das ja genau dem HttpWebRequest im .Net Framework) entspricht, nicht funkioniert.

Also entweder man benutzt wirklich das WebBrowser Control ohne Anzeige, dann hat man aber das Problem, dass wenn man doch mal ein Captcha eingeben muss, es nur schwer geht dieses Captcha im verstecken Browser zum Benutzer weiterzuleiten. Ich habe gelesen, das geht nur über die Zwischenablage.

user profile iconplatzwart hat folgendes geschrieben Zum zitierten Posting springen:
Oder sich einfach an die Spielregeln von Google halten und nicht einfach so fremde Leistungen abgreifen...


Das ist insofern nur schwer machbar, weil mir die API, welche von Google angeboten wird, nicht die selben Ergebnisse wie die Suche im WebBrowser liefert. Bei der neuen Google API funktionieren Suchparameter wie "inurl:" nicht. Dafür gibt es auch schon einige Threads im Netz:

http://stackoverflow.com/questions/8900707/why-google-ajax-search-api-return-no-results-when-inurl-points-to-specific-pa

Daher wäre eine funktionierende, nicht restriktierte Lösung schon etwas feines.


Oliver M. - Mi 16.05.12 21:13

Wie gesagt: Wenn du einen Proxy benutz, hat Google keine Chance gegen dich mehr.


UGrohne - Do 17.05.12 10:53

user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:
Wie gesagt: Wenn du einen Proxy benutz, hat Google keine Chance gegen dich mehr.

Warum das denn? Ist doch im Endeffekt auch nur ein anderer Rechner. Das Verhalten dürfte dasselbe bleiben.


BlackMatrix - Fr 18.05.12 16:27

user profile iconUGrohne hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:
Wie gesagt: Wenn du einen Proxy benutz, hat Google keine Chance gegen dich mehr.

Warum das denn? Ist doch im Endeffekt auch nur ein anderer Rechner. Das Verhalten dürfte dasselbe bleiben.


Ich denke er meint damit, dass jede Suchseite oder nur eine handvoll Suchseiten mit einem Proxy abgefragt werden, sodass Google noch nicht von einem Bot ausgeht. Das ist wohl die einzig funktionierende Möglichkeit, verkompliziert das Ganze aber auch, da Google selber auch wieder gegen Proxys vorgeht und man bei einer bestimmten IP direkt zur Captchaeingabe weitergeleitet wird.

Die Captchaeingabe an und für sich stellt ja kein Problem dar, die kann mein Benutzer gerne eingeben, aber mir ist bisher noch nicht gelungen überhaupt weitergeleitet zu werden um das Captcha herunterzuladen.


Oliver M. - Sa 19.05.12 11:34

So sehr ich mich auch bemühe, ich bekomme keine Chaptcha Abfrage, obwohl ich alle Scuhergebnisse von Google abrufe. Wieviele muss man denn abrufen, bis man nach einem Chapta gefragt wird? Und woran erkennt man, das ein Captcha abgefragt wird? Ich bekomme zwar bei manschen Querys (z. B. „und“) irgend wann einen 403, aber bis dahin wurden mir schon einige Zeit immer die gleichen Ergebnisse angezeigt. :?


BlackMatrix - Sa 19.05.12 20:27


C#-Quelltext
1:
2:
3:
            WebClient wc = new WebClient();
            for (int start = 0; start < 1000; start+=10)
                wc.DownloadString("http://www.google.de/search?q=inurl:sharp&start=" + start);


Sollte dir einen 503 Error bringen.


Oliver M. - So 20.05.12 20:19

Ich erhalte einen 503 nur wenn ich inurl: angebe, aber inzwischen werden alle Suchanfragen mit inurl: die von meinem Programm kommen blockiert. Mal sehen ob die Sperre morgen weg ist. Kannst du nicht einfach auf inurl: Verzichten?
Jedenfalls habe ich jetzt herausgefunden, wo man den http://www.google.de/sorry/ auslesen kann, aber wenn man http://www.google.de/sorry/ abfragt, erhält man seltamer Weise auche einen 503:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
catch (WebException ex)
{
  if (ex.Response.ResponseUri.AbsolutePath == "/sorry/")
  {
    HttpWebRequest request = HttpWebRequest.CreateHttp(ex.Response.ResponseUri);
    string response = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
  }
}


BlackMatrix - Mo 21.05.12 10:26

user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:
Ich erhalte einen 503 nur wenn ich inurl: angebe, aber inzwischen werden alle Suchanfragen mit inurl: die von meinem Programm kommen blockiert. Mal sehen ob die Sperre morgen weg ist. Kannst du nicht einfach auf inurl: Verzichten?


War bei mir genauso, ich habe mir dann ne neue IP versorgt, damit ich davon wieder wegkam. Sollte aber heute wieder weg sein.

user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:
Kannst du nicht einfach auf inurl: Verzichten?


Dieser Parameter sorgt eigentlich nur dafür, dass die Suchanfrage schneller als eine Botanfrage erkannt wird. Das ist vielleicht auch der Grund warum überhaupt kein inurl Parameter bei der Search API von Google funktioniert.

user profile iconOliver M. hat folgendes geschrieben Zum zitierten Posting springen:

Jedenfalls habe ich jetzt herausgefunden, wo man den http://www.google.de/sorry/ auslesen kann, aber wenn man http://www.google.de/sorry/ abfragt, erhält man seltamer Weise auche einen 503:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
catch (WebException ex)
{
  if (ex.Response.ResponseUri.AbsolutePath == "/sorry/")
  {
    HttpWebRequest request = HttpWebRequest.CreateHttp(ex.Response.ResponseUri);
    string response = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
  }
}


Ich habe HttpFox fürn Firefox eingesetzt, das schneidet mir die WebRequests mit und laut HttpFox darf es gar nicht zu einer 503 Exception kommen, sondern zu einer Weiterleitung (im Header) zu http://www.google.de/sorry/. Irgendein Parameter muss da noch irgendwie gesetzt werden, sodass es zu einer Weiterleitung und nicht zu einer Exception kommt.

Wie schon einmal geschrieben brauch ich keine Vollautomatisierung, also die Eingabe der Captchas wäre kein Problem, nur muss ich dieses erstmal herunterladen um es an den Benutzer weitergeben zu können.

Bei Gelegenheit werde ich mal noch LiveHttpHeaders oder Wireshark anwerfen um herauszufinden, was da nun noch zwischen BrowserRequest und C#-WebRequest unterschiedlich ist. Viel Hoffnung habe ich dabei aber nicht.


BlackMatrix - Mo 21.05.12 15:45

Live HTTP headers:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
http://www.google.de/search?q=sharp&start=10

GET /search?q=sharp&start=10 HTTP/1.1
Host: www.google.de
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate

HTTP/1.1 302 Found
Via: 1.1 INET
Connection: Keep-Alive
Content-Length: 287
Date: Mon, 21 May 2012 13:40:13 GMT
Location: http://www.google.com/sorry/?continue=http://www.google.de/search%3Fq%3Dsharp%26start%3D10
Content-Type: text/html; charset=UTF-8
Server: GFE/2.0
Cache-Control: private


Wikipedia schreibt dazu:

Zitat:
302 Found
Die angeforderte Ressource steht vorübergehend unter der im „Location“-Header-Feld angegebenen Adresse bereit.[3] Die alte Adresse bleibt gültig. Wird in HTTP/1.1 je nach Anwendungsfall durch die Statuscodes 303 bzw. 307 ersetzt. 302-Weiterleitung ist aufgrund eines Suchmaschinen-Fehlers, dem URL-Hijacking, in Kritik geraten. Webmaster sollten von der Verwendung eines solchen Redirects absehen, wenn sie auf fremde Inhalte weiterleiten.


Oliver M. - Di 22.05.12 17:54

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe HttpFox fürn Firefox eingesetzt, das schneidet mir die WebRequests mit und laut HttpFox darf es gar nicht zu einer 503 Exception kommen, sondern zu einer Weiterleitung (im Header) zu http://www.google.de/sorry/. Irgendein Parameter muss da noch irgendwie gesetzt werden, sodass es zu einer Weiterleitung und nicht zu einer Exception kommt.

Ich habe mir den Fehler noch mal genauer angeschaut und habe gesehen, dass die Weiterleitung einwandfrei funktioniert. Die 503 erhält man beim aufrufen des Soory-Urls:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
HttpWebRequest request = HttpWebRequest.Create(url);
try 
{ request.GetResponse(); }
catch (WebException ex)
{
  Console.WriteLine(ex.Response.ResponseUri.ToString()) // http://www.google.de/sorry/...
}

Allerdings kann man mittels ex.Response die Seite mit dem Chapta auslesen :zwinker::

C#-Quelltext
1:
string response = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();                    

Und somit auch das Chapta-Bild:

C#-Quelltext
1:
2:
3:
4:
5:
string response = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();

string imageUrl = new Regex("<img src=\"(?<url>.+?)\" border=\"1\" alt=\"Bilder aktivieren\">").Match(response).Groups["url"].Value;
Stream imageStream = HttpWebRequest.Create("http://www.google.de" + imageUrl).GetResponse().GetResponseStream();
Image chapta = new Bitmap(imageStream);

Jetzt müssen die entschlüsselten Chaptas nur noch an Google gesendet werden, aber ich denke das dürfte nicht schwer sein.


BlackMatrix - Di 22.05.12 19:32

Stimmt, auf die Idee bin ich noch gar nicht gekommen in der Exception dann den Response noch auszulesen :)

Getestet wird erst morgen, aber ich danke dir schon einmal :)

Edit:

Ja, das klappt, man muss also den Response in der WebException auslesen. Das hatte mich irretiert, denn mit diversen Tools wurde das nicht als WebException mitgeschnitten sondern als Weiterleitung.

Man brauch zum Absenden des Captchas auf jeden Fall einen CookieContainer, ohne funktionierts nicht. Und man muss an folgenden Url einen Request machen, damit man weitergeleitet wird:


Quelltext
1:
http://www.google.de/sorry/Captcha?continue=http://www.google.de/search?searchString&id="+id+"&captcha="+captcha+"&submit=Senden                    


Wobei "id" im Response rauszulesen ist und captcha die Zeichenfolge vom Captcha ist.

Edit2:

Danke für dein Projekt.

Was ich noch festgestellt habe, dass der Regex nicht ganz stimmt, da du ja die Url aus dem grünen Text von Google parst. Das Problem dabei ist, dass es sein kann, dass die grüne Url manchmal nur einen Teil der kompletten URL darstellt. Das ist dann der Fall, wenn die Url sehr lang ist, dann wird von Google mit ... gekürzt. Die richtige Url befindet sich nach "<a href="...

Liebe Grüße und danke für deine Mithilfe :)


Oliver M. - Mo 28.05.12 17:27

Gern geschehen!