Portal > Foren > PHP > PHP-Programmierung > PHP-Crawler optimieren
Antwort
 
Themen-Optionen
Alt 14.03.2008, 09:03 Nach oben    #1
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard PHP-Crawler optimieren

Hallo sehr geehrte DG Gemeinde,

vor langem hatte ich hier meine Probleme mit dem Crawler schon beschrieben, und jetzt hab ich einen Perfomance problem.

Habe mit meinem Script 1.300 Links gecrawlt. Beim ersten versuch klappte nichts, ich musste den max_execution_time auf 6666 Sekunden setzen, damit ich eine Sicherheit habe, dass es vollständig crawlt. Danach lief das Script 36 Minuten. Das dauerte mir zu lange *g.

Mein nächster Versuch über CLI brachte schon bessere Ergebnisse. Dort brauchte es 19 Minuten für 1.300 Links..

Da das Script später täglich mehr als 1 Millionen Links crawlen soll, ist es schon etwas nervig wenn es so lange braucht.

Ich gehe in meinem Crawler-Script so vor:
  • Ich lade den Inhalt der jeweiligen Kategorie zunächst in eine Variable
  • danach Crawle ich alle Links der Seitenlinks
  • Dann laufe ich in einer for-Schleife Links durch und Crawle den 2. Depth aus und Crawle diese erneut und extrahiere mir die nötigen Links in einer foreach-Schleife
  • und dann werden Links in die Datenbank eingefügt
und nun hier der Code:

PHP-Code:
<?php
mysql_connect
("localhost""root""");
mysql_select_db("crawler");

$link0 "link.com";
$wget0 file_get_contents($link0);
$patt0 preg_match_all('°start=([^"]+)\">letzte°S'$wget0$erg0);

#if(isset($_GET["start"])) $start = intval($_GET["start"]); else $start = 1; $end=$start + 43;

#if($start < $erg0[1][1]) {
    
for($i=$start$i<=$erg0[1][1]; $i++) {
        
$link1 "link.com/?cat=4&start=$i";
        
$wget1 file_get_contents($link1);
        
$patt1 preg_match_all('°<P CLASS=\"TITLE\"><A HREF=\"\/\?id=([^"]+)\">°S'$wget1$erg1);
        foreach(
$erg1[1] as $links) {
            
$link1 "link.com/?id=$links";
            
$wget1 file_get_contents($link1);
            
$patt1 preg_match_all('°<TH ALIGN=\"LEFT\"> <H1><A HREF=\"([^"]+)\"><B>([^"]+)<\/B><\/A>°S'$wget1$erg1);
            
#echo $erg1[2][0]."<br />";
            
$patt3 preg_match_all('°<H1>Download ([^"]+)<\/H1>°isS'$wget1$erg3);
            
preg_match_all('°\(([^"]+),°'$erg3[1][0], $p);
            
$sql "INSERT INTO link1 (`site`, `cate`, `linkname`, `link`, `dtyp`)
                        VALUES
                    ('link', 'gam', '$link1', '"
.$erg1[2][0]."', '".$p[1][0]."')";
            
mysql_query($sql);
        }
    }
    
#header("Refresh: 0; url=crawler.php?start=$end");
#}
?>

Ein kleiner Hinweis, da da Script vorher über nen Browser lief, ist da noch meine "Refresh-Script" drin
__________________
Meine Free SMS Seite

Geändert von Eyüp (14.03.2008 um 09:14 Uhr). Grund: Refresh-Script auskommentiert
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.03.2008, 09:09 Nach oben    #2
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

Ach, mir fällt noch ein, ich wollte noch den php-core neukompilieren und nur die nötigen pakete installieren. Bloss als Laie ist man da aufgeschmissen. Gibts da irgendwelche Tutorien?
__________________
Meine Free SMS Seite
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.03.2008, 09:17 Nach oben    #3
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

So, hab jetzt ein wenig gegooglt und das hier rausgefunden:

http://de.php.net/manual/de/ref.curl.php#59877
cURL kann bis zu 50% schneller sein als file_get_contents.

Ich werd heute versuchen, meinen Code in cURL umzuschreiben...
__________________
Meine Free SMS Seite
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.03.2008, 09:25 Nach oben    #4
Benjamin Steininger
 
Benutzerbild von robo47
 
Registriert seit: 02.06.2005
Ort: weiher im tiefsten Odenwald
Beiträge: 1.180
Standard

Lass das Script lokal mit einem Debugger (beispielsweise xdebug) laufen, aktiviere den Profiler und schau dir die Verteilung der Rechenzeit an. Dann siehst du erstmal wo du optimieren kannst und was am meisten Rechenzeit braucht, wenn es beispielsweise das file_get_contents ist, ist dafür eben auch mit die Antwortzeit + Geschwindigkeit des Servers gegenüber verantwortlich und die DL-Geschwindigkeit.

Übrigends würde ich die Ergebnisse escapen (mysql_(real_)escape_string bevor du den Kram in die Datenbank einfügst.
robo47 ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.03.2008, 09:31 Nach oben    #5
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

Danke Benjamin, dann muss ich mir zunächst anschauen, wie das mit dem XDebug und dem Profiler geht *g

Laut der php.net Kommentaren ist ja cURL trotzdem schneller als file_get_contents, oder etwa nicht?

Escaping ist immer drin *g nur würde man es hier nicht mehr richtig lesen können...
__________________
Meine Free SMS Seite
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.03.2008, 19:51 Nach oben    #6
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

So, hab das in cURL umgeschrieben. Die Geschwindigkeit ist gleich geblieben.

Jetzt werde ich nach Anleitung von der Nutzung von XDebug & Profiler suchen und dies anwenden

Wenn ihr noch Tipps habt, her damit

Evtl, kann man die RegEx durch was anderem ergänzen oder die foreach Schleife ersetzen? kA Warte auf eure tipps.
__________________
Meine Free SMS Seite
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.03.2008, 20:41 Nach oben    #7
Benjamin Steininger
 
Benutzerbild von robo47
 
Registriert seit: 02.06.2005
Ort: weiher im tiefsten Odenwald
Beiträge: 1.180
Standard

Zitat:
Zitat von Eyüp Beitrag anzeigen
So, hab das in cURL umgeschrieben. Die Geschwindigkeit ist gleich geblieben.

Jetzt werde ich nach Anleitung von der Nutzung von XDebug & Profiler suchen und dies anwenden

Wenn ihr noch Tipps habt, her damit

Evtl, kann man die RegEx durch was anderem ergänzen oder die foreach Schleife ersetzen? kA Warte auf eure tipps.
Es bringt nix jetzt Tips zu geben und rumzuraten, wenn man nicht weis, was an dem ganzen die langsamsten teile sind und wo man noch etwas beschleunigen kann, du kannst anstatt xdebug natürlich auch dir selbst nen Benchmark basteln mit microtime und so und dann halt das teil mehrfach durchlaufen lassen und schauen welche teile am längsten brauchen, aber mit nem debugger ist das wesentlich komfortabler.

Ich würde mir lokal nen Xampp installieren, dazu xdebug dann die config von php anpassen, dass der profiler von xdebug mitläuft und dir irgendwo seine profiles speichert von den scriptdurchläufen und dann kannst du dir die mit:

http://sourceforge.net/projects/wincachegrind/ (unter windows)

anschauen.

Das sieht dann so in der Art aus:


Klick für größere Ansicht


und das kannst du dann auswerten nachdem du siehst welche funktionen am meisten aufgerufen werden, wie lange sie brauchen etc und kannst damit die langsamen Teile identifizieren.

Vielleicht sind ja auch einfach die Server die du abfragst so langsam, dass sie entweder verdammt lange bruachen um die Anfrage zu beantworten oder dass sie ihre daten maximal mit XX kb/s schicken ... heißt den Teil bekommst du überhaupt nicht schneller, da hilft es dann irgendwann nur noch das script so zu bauen, dass problemlos mehrere Instanzen synchron laufen können und die sich die Arbeit teilen (da müsste dann allerdings das Design der ganzen Applikation nochmal überdacht werden.)

Es wäre ja beispielsweise auch möglich, aber da musst du eben mal rumtesten ob das über den gesamten zeitverbrauhc überhaupt relevant ist, die inserts zu "sammeln"

sprich du brauchst ja eigentlich den INSERT ( INSERT INTO table (spalte1, spalte2, spalte 3) VALUES ) nur einmal und dann in der form erweitert:

( wert1, wert2, wert3),
.....
( wertX.1, wertX.2, wertX.3);

sprich am ende ein großes Query abschicken, damit hast du halt nen viel größeren Speicherverbrauch, aber eben nicht andauernd einen insert, der overhead der querys wird dadurch kleiner.
robo47 ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.03.2008, 08:00 Nach oben    #8
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

Danke Benjamien,

derzeit läuft jetzt der Crawler nochmal die Links etc. durch

Hier vorab der Code mit cURL:

PHP-Code:
<?php
mysql_connect
("localhost""root""");
mysql_select_db("crawler");

$ch curl_init("http://'$--link--$/?cat=4");
curl_setopt($chCURLOPT_HEADER0);curl_setopt($chCURLOPT_RETURNTRANSFER1);curl_exec($ch);
$wget0 curl_multi_getcontent($ch);

$patt0 preg_match_all('°start=([^"]+)\">letzte°S'$wget0$erg0);

for(
$i=1$i<=$erg0[1][1]; $i++) {

    
$ch1 curl_init("http://'$--link--$/?cat=4&start=$i");
    
curl_setopt($ch1CURLOPT_HEADER0);curl_setopt($ch1CURLOPT_RETURNTRANSFER1);curl_exec($ch1);
    
$wget1 curl_multi_getcontent($ch1);
    
$patt1 preg_match_all('°<P CLASS=\"TITLE\"><A HREF=\"\/\?id=([^"]+)\">°S'$wget1$erg1);

    foreach(
$erg1[1] as $links) {
    
$l "http://'$--link--$/?id=$links";
    
$ch2 curl_init($l);
    
curl_setopt($ch2CURLOPT_HEADER0);curl_setopt($ch2CURLOPT_RETURNTRANSFER1);curl_exec($ch2);
    
$wget1 curl_multi_getcontent($ch2);
        
$patt1 preg_match_all('°<TH ALIGN=\"LEFT\"> <H1><A HREF=\"([^"]+)\"><B>([^"]+)<\/B><\/A>°S'$wget1$erg1);

        
$patt3 preg_match_all('°<H1>Download ([^"]+)<\/H1>°isS'$wget1$erg3);
        
preg_match_all('°\(([^"]+),°'$erg3[1][0], $p);

        
$sql "INSERT INTO link1 (`site`, `cate`, `linkname`, `link`, `dtyp`)
                        VALUES
                    ('$--link--$', 'gam', '$l', '"
.$erg1[2][0]."', '".$p[1][0]."')";
            
mysql_query($sql);
    }
}
?>
cURL XDebug Profil


Zum Redesign des Scriptes, dazu hätt ich ein paar fragen..

So, laut WinCacheGrind verbraucht curl_exec die meiste Zeit.. und das ist Serverseitig
da kann man wohl wenig machen *g danach kommt preg_match und mysql_query..


Zum Redesign des Scriptes, wie meinst du das genau, dass es synchron ablaufen soll..

ich will ja täglcih mehrere tausend links crawlen
__________________
Meine Free SMS Seite

Geändert von Eyüp (15.03.2008 um 08:16 Uhr).
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.03.2008, 09:26 Nach oben    #9
Benjamin Steininger
 
Benutzerbild von robo47
 
Registriert seit: 02.06.2005
Ort: weiher im tiefsten Odenwald
Beiträge: 1.180
Standard

1) Versuch die von mir angesprochene Änderung betreffs dem INSERT zu machen und beispielsweise immer 100 Inserts zusammen zu machen (das einzelne Query darf aber nicht zu groß werden)

2) Überleg dir wie mehrere Instanzen synchron laufen könnten, sprich mehrere Startpunkte oder ein System was sich seine Startpunkte selbst sucht oder sowas

3) mal noch schauen ob vielleicht Snoopy noch nen tick schneller ist als Curl ( http://snoopy.sourceforge.net/ )

Oder trenne die Scripte, eins das sich nur ums downloaden kümmert, den code in einem verzeichnis speichert und ein weiteres Script, dass sich nur um das Parsen der Dateien kümmert, alles dinge die du ausprobieren kannst.
robo47 ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.03.2008, 09:42 Nach oben    #10
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

zu 1) Nun, da die INSERTs eh klein sind, würd sich das evtl. nicht lohnen... aber ich werds auf jedenfall probieren. vllt. bringts ja doch was
zu 2) Nunja, soviele Startpunkte gibts ja nicht. Ich werd jetzt das System ein wenig erweitern, weil das hier war spezifisch nur für einen Bereich und nur für eine Seite..

zu 3) Ich werds jetzt probieren

Es geht wie es schient nicht schneller.

Hab jetzt eine andere Seite ausprobiert, und da war der Crawler doppelt so schnell fertig.

statt 0,7 Seiten pro Sekunde hat er 1,7 Seiten pro Sekunde gecrawlt.
__________________
Meine Free SMS Seite
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.03.2008, 17:20 Nach oben    #11
Neuer Benutzer
 
Registriert seit: 15.03.2008
Beiträge: 2
Standard

Hallo,
mir stellt sich gleich von Anfang an die Frage, wieso du den Crawler überhaupt in PHP schreibst, und nicht etwa in C, C++ oder meinetwegen auch Java?
codethief ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.03.2008, 18:14 Nach oben    #12
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

Nun, ganz einfach Mein schreibt Programme/ Scripte in der Sprache, die man auch kann *g. Irgendwie logisch?

Ich werde demnächst C++ lernen und den Code dann in C++ neu schreiben mit mehr Features .

Zu blöd das PHP kein Multithreading untersützt...
__________________
Meine Free SMS Seite
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 16.03.2008, 01:12 Nach oben    #13
Neuer Benutzer
 
Registriert seit: 15.03.2008
Beiträge: 2
Standard

Ja, so dachte ich früher auch. Ich hab mir damals sogar eine CronJob-Simulation und einen IRC-Bot in PHP geschrieben. Heute lasse ich die Finger von solchen Aktionen und insbesondere von PHP selbst.
Darf ich fragen, für was du den Crawler schreibst?
codethief ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 16.03.2008, 08:39 Nach oben    #14
Erfahrener Benutzer
 
Registriert seit: 04.03.2007
Ort: Viernheim
Beiträge: 131
Standard

Für eine Suchmaschine *g
Nähere Infos nur über PN
__________________
Meine Free SMS Seite
Eyüp ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Antwort

Lesezeichen


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
PHP 5.2 Kompilierung schlägt fehl Byrel Tools, Server, Betriebssysteme 0 03.11.2006 21:09
[Rezension] PHP 5 Kochbuch Artemis Literatur 2 07.09.2006 19:15
PHP 5.1.5, PHP 4.4.4 und PHP 5.2.0 RC2 veröffentlicht Ben Nachrichten 2 01.09.2006 16:05
PHP 5.1 ist drausen robo47 Nachrichten 5 28.11.2005 20:30
Neue PHP "release candidates": PHP 4.4.2 RC 1 und PHP 5.1 RC 6 Ben Nachrichten 1 21.11.2005 20:48


Alle Zeitangaben in WEZ +2. Es ist jetzt 16:11 Uhr.


Powered by vBulletin® Version 3.7.3 (Deutsch)
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44