Brugernavn:




Kodeord: Husk
Forside Forum Artikler Downloads Søg
 

Hvordan man laver en webcrawler

Forord

Før jeg begynder artiklen, ville det være godt hvis du havde en smule styr på PHP, OOP (dette vil jeg bruge i artiklen, så hvis du vil forstå den, vil du få brug for dette værktøj) og RegExp (Regular Expression).
Jeg vil i flere tilfælde referere til hjemmesider. Meningen er at du så skal gå ind og læse omkring det, på den måde kan du lære nye ting, eller blive bedre til ting du vidste i forvejen.

En Webcrawler er en "kravler". Den får angivet et link, som den skal gå ind og finde links/tekst whatever på.
Hurtig forklaring, gider ikke bruge den største sum tid på at skriver hvad en Webcrawler er. Læs evt. her hvis det er: http://en.wikipedia.org/wiki/WebCrawler

Jeg har ikke forstand på PHP, OOP eller RegExp?
PHP: http://www.phpartikler.dk
OOP: http://rowl.dk/showarticle.asp?id=140&succes=&page=0
RegExp: http://rowl.dk/showarticle.asp?id=91&succes=&page=0

Men hvis du føler at du har nogenlunde styr på ovenstående, kan du efter eget valg vælge at læse artiklen.
Men det er jo selvfølgelig dit eget valg, hehe.
Obs.: Det er en let udgave af en Webcrawler. Men når du er færdig med artiklen vil du være i stand til at fange links fra hjemmesider.

Jeg har valgt at lave en indholdsfortegnelse, så du har et overblik over hvad jeg gennemgår i artiklen.

1.0: Lidt teori omkring selve opbygningen af Webcrawleren.
- 1.1: Hvordan?
- 1.2: Hvad kan en sådan tingest gøre godt for?

2.0: Programmering af Webcrawleren.
- 2.1: Hvad skal jeg bruge?
- 2.2: Selve koden.
- 2.3: Forklaring af koden.
- 2.4: Jeg er fuldstændig lost.

3.0: Slutning
- 3.1: Tak til

1.0: Lidt teori omkring selve opbygningen af Webcrawleren
Du tænker sikkert, det er da umuligt. Ak nej, tværtimod det er skide nemt hehe.
Jeg vil heri afsnittet fortælle om hvordan jeg har valgt at opbygge den (der er andre måder ja).

- 1.1: Hvordan?
Ja ser du. Her er en lille illustration over hvordan den opbygges, jeg vil dernæst fortælle om billedet.
Illustration 1.0:

I den første boks i Illustration 1.0 står der ”Find links”, og med det mener jeg at du aktivt med RegExp skal ind i hjemmesidens kildekode, og søge efter links.
Resten siger forhåbentlig sig selv.

1.2: Hvad kan en sådan tingest gøre godt for?
Du kan bruge den til at finde links på en given adresse (www.rowl.dk f.eks.).
Men jeg lavede det, da jeg interessen pludselig kom.
Jeg valgte at udvikle en søge-maskine. Den er nu kommet online, men den bliver pillet ned snart.

2.0: Programmering af Webcrawleren.
Nu tænker du sikkert, nu bliver det spændene. Og ja hehe, det bliver spændene.
Jeg vil først forklare hvad du skal bruge, og dernæst koden + en forklaring linje for linje.

2.1: Hvad skal jeg bruge?
En php-editor. Notesblok er et godt bud på en god editor. Men hvis du vil have en lide bedre med syntaks-farvning og linjenummering vil jeg anbefale Notepad++.
Og du skal også bruge dit hoved, smart ikke?

2.2: Selve koden.
  1. <?php

  2. ini_set("allow_url_fopen", 1);

  3. class __SmuugieCrawler54071233
  4. {
  5. public $fileOpener;
  6. const NameOnBot = "Smuugie"; // Dit navn på botten..

  7. public function __findlinks( $www ) {
  8.         
  9. if (!eregi("http://", $www ) )
  10. $wwwT = "http://".$www;
  11. else
  12. $wwwT = $www;
  13.             
  14. $this -> fileOpener = fopen( $wwwT, "r" );
  15.                 
  16. do {
  17. $open = fread($this -> fileOpener, 4096);
  18. $lines .= $open;
  19. } while(!feof($this -> fileOpener));
  20. fclose($this->fileOpener);
  21.                     
  22. for( $i = 0; $i < sizeof( $lines ); $i++) {
  23. preg_match_all("!a[s]*[^<>]+?href=["|"]([^<>]+?)["|"]>([^<>]+)</a>!i", $lines, $hrefs );
  24. preg_match_all("!(ftp|http)(://)([www.]?)([wæøå-.]+).([a-zA-Z]{2,5})([wæøå-%=.:#@/]+)?!i", $lines, $links );
  25. preg_match_all("![^http://]www.([wæøå-.]+).([a-zA-Z]{2,5})[wæøå-%=.:#@/]*!i", $lines, $wwwS);
  26. preg_match("!<title>([^<>]+)</title>!is", $lines, $matches2);                        
  27. }

  28.                     
  29. print "<span style="font-size:11pt;font-weight:bold;">" . self::NameOnBot . "</span> fanger links fra [" . $www . "]<br />";
  30. print "Fundet: " . (count($hrefs[1]) + count($links[1]) + count($wwwS[1])) . "<br /><br />";
  31.                     
  32. for($i = 0; $i < count($hrefs[1]); $i++ )
  33. print htmlspecialchars($hrefs[1][$i]) . "<br />";
  34.                         
  35. print "<hr style="background-color: #d5d5d5;" size="1">";
  36.                         
  37. for($x=0;$x<count($links[0]);$x++)
  38. print htmlspecialchars($links[0][$x]) . "<br />";
  39.     
  40. print "<hr style="background-color: #d5d5d5;" size="1">";
  41.                 
  42. for($w=0;$w<count($wwwS[0]);$w++)
  43. print htmlspecialchars($wwwS[0][$w]) . "<br />";
  44.                     
  45. print "<br>";
  46. print "<b>Titel:</b> " . $matches2[1] . "<br /><br />";
  47.                     
  48. /** Fang indhold af siden **/
  49. $content = file_get_contents($wwwT);
  50. preg_match( "!<body(.*?)>([^<>]+)</body>!is", $content, $description);
  51. print strip_tags($description[0][0]);
  52.         
  53. }

  54. }

  55. print "<html>";
  56. print "<head>";
  57. print "<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />";
  58. print "<title>Pulzer.dk</title>";
  59. print "<style type="text/css">
  60. body { font-family: Verdana; font-size: 8pt; }
  61. </style>";
  62. print "</head>";
  63. print "<body>";

  64. try {

  65. $Application = New __SmuugieCrawler54071233;
  66.     
  67. if ( !class_exists("__SmuugieCrawler54071233") )
  68. throw new Exception("Klassen eksisterer ikke, derfor melder vi fejl");
  69.         
  70.     
  71. $nytLink = "http://rowl.dk";
  72.     
  73. if ( !ereg( "http://", $nytLink ) )
  74. throw new Exception("Linket skal indeholde HTTP://");
  75.     
  76. $Application->__findlinks($nytLink);
  77.     
  78. } catch( Exception $error ) {

  79. print "Der skete en fejl: <i>" . $error->getMessage() . "</i>";
  80.     
  81. }

  82. print "</body></html>";

  83. flush();
  84. sleep(1);
  85. flush();
  86.     
  87. ?> 

2.3: Forklaring af koden.
Jeg vil her forklare koden, dog vil jeg ikke gå i detaljer med de simpleste ting.

Vi starter koden med at sætte allow_url_fopen til 1 (true) via ini_set().
Ini_set() er en funktion til at ændre variabler i din php.ini fil.
Dernæst opretter vi en klasse, som vi kalder __SmuugieCrawler54071233. Det er bare et navn jeg tilfældigt har valgt at kalde den. 54071233 er ikke tilfældige numre (05 – 04 – 2007 12:33).
De næste linjer er bare erklæring af variabler som jeg skal bruge i koden.
Public function __findlinks() er en funktion jeg opretter. Den skal tage imod 1 parameter ($www).
$www skal indholde et link som du har angivet (f.eks. www.google.dk).
Dernæst tjekke jeg med en if() om linket indeholder http://, hvis ikke det gør så putter jeg http:// foran.
Jeg har erklæret en variabel fra før ($fileOpener), den tager vi i brug nu. Vi bruger den til at åbne hjemmesiden med fopen() (derfor skulle allow_url_fopen sættes til true).
Så læser vi hjemmesiden linje for linje, og kommer indholdet af det i variablen $lines.
Og så lukker vi $this -> fileOpener med fclose().
Næst skal vi i gang med at finde linksene. Jeg har valgt at bruge preg_match_all (http://dk2.php.net/preg_match_all) og preg_match (http://dk2.php.net/preg_match).
Begge tager imod en RegExp og putter alle matchs ind i henholdsvis: $hrefs, $links og $matches2.
Ja, der findes andre alternativer såsom preg_replace_callback().

  • preg_match_all("!a[s]*[^<>]+?href=["|"]([^<>]+?)["|"]>([^<>]+)</a>!i", $lines, $hrefs ); 

Ser nok en smule tricky ud, men her er som følger:

  • !a [mellemrum]* [ingen < eller > tegn]+?href=[’ eller ”]([ingen < eller > tegn]+?)[’ eller ”]>([ingen < eller > tegn]+)</a>!i

Nu burde den være til at forstå.
Jeg vil herunder også forklare de tre næste RegExp.

  • preg_match_all("!(ftp|http)(://)([www.]?)([wæøå-.]+).([a-zA-Z]{2,5})([wæøå-%=.:#@/]+)?!i", $lines, $links ); 
Oversat:
  • !(ftp eller http)(://)([måske www.]?)([alle bogstaver inkl. æøå – og .]+).([bogstaver a-z]+{mellem 2 og 5 af dem}([måske: alle bogstaver, tegn som kan bruges i en querystring]+)?!i
_______________

  • preg_match_all("![^http://]www.([wæøå-.]+).([a-zA-Z]{2,5})[wæøå-%=?.:#@/]*!i", $lines, $wwwS); 
Oversat:
  • ![ikke http://]www.([bogstaver + æøå og – og .]+).([bogstaver fra a-z]{mellem 2 og 5 af dem}[alle muligt bogstaver som kan forekomme i en querystring]*!i
_______________

  • preg_match("!<title>([^<>]+)</title>!is", $lines, $matches2); 

Den her er let.
  • !<title ([ikke < eller > tegnet]+)</title>!is

Resten burde være til at forstå, og hvis ikke du forstår det kan du bare spørge.
Det sidste stykke kode består mest af for() løkker, hvilket du meget gerne skulle kunne.
Der er dog lige nogle ting jeg lige vil gå igennem for dig.
  1. $content = file_get_contents($wwwT);
  2. preg_match( "!<body(.*?)>([^<>]+)</body>!is", $content, $description);
  3. print strip_tags($description[0][0]); 
Jeg starter med at give $content værdien file_get_contents($wwwT) .
File_get_contents() er en funktion som tager kildekoden af en URL-adresse.
Jeg bruger så RegExp til at finde den tekst mellem <body> ( al teksten her ) og </body> tagsne.
Og så printer jeg det bare ud til brugeren som skal se det.
File_get_contents: http://dk2.php.net/file_get_contents
Strip_tags: http://dk2.php.net/strip_tags

Og her er en ting du måske ikke forstår:
  1. try {

  2. $Application = New __SmuugieCrawler54071233;
  3.     
  4. if ( !class_exists("__SmuugieCrawler54071233") )
  5. throw new Exception("Klassen eksisterer ikke, derfor melder vi fejl");
  6.         
  7.     
  8. $nytLink = "http://rowl.dk";
  9.     
  10. if ( !ereg( "http://", $nytLink ) )
  11. throw new Exception("Linket skal indeholde HTTP://");
  12.     
  13. $Application->__findlinks($nytLink);
  14.     
  15. } catch( Exception $error ) {

  16. print "Der skete en fejl: <i>" . $error->getMessage() . "</i>";
  17.     
  18. }
Det er et try-catch statement jeg har brugt.
Jeg kan prøve at give et eksempel på det (hvis ikke du forstod det fra før):
  1. hvis {
  2. // noget kode..
  3. // her kan komme en if eller noget, som man kan smid en Exception med.
  4. // f.eks:
  5. if ( !betingelse )
  6. {
  7. throw new Exception(”Fejl”);
  8. }
  9. } catch (Exception $e)
  10. {
  11. print $e -> getMessage();
  12. }
Dårligt eksempel, men jeg håber du fik noget ud af det.
Ellers kan du læse omkring try-catch her: http://dk2.php.net/manual/da/language.exceptions.php

2.4: Jeg er fuldstædig lost.
Hvis du er fuldstændig lost, og forstår slet intet af det jeg skriver, så vil jeg (for din skyld) henvise dig til http://phpartikler og læse en masse om PHP.

3.0: Slutning
Her til sidst, vil jeg bare sige tak for opmærksomheden. Jeg håber du har lært lidt om hvordan man kan opbygge en Webcrawler. Og det kan jo ende med at du skaber dit eget Google, who knows?
Jeg har gjort mit bedste. Og håber du har lært noget af det.

- 3.1: Tak til
Jeg vil gerne sige tak til Thomas (Dexo-fan), for ikke mindst at have hjulpet mig når jeg havde brug for det, men også have været en super ven som man har kunnet snakke med alt ham. Thomas my man, tak for alt.

Dernæst vil jeg også takke v0id, for at have hjulpet mig med så meget. C/C++ spørgsmålene er altid gået til ham stort set.
Han er også en super ven, som man også kan grine og hygge sig med.

Så er der jo Kim (Kimbert), knægten som alle kan lide hehe. Jeg kan i hvert fald lide ham, og derfor fortjener han også at komme med herunder tak til =)
Sidst redigeret 16:35 30/05/2007 af Rowl
Oprettet af:

PHP

Point modtaget: 0

Rate:
14:02 17/05/2007

Kommentarer

Giv din mening tilkende om denne artikel, eller læs andres.
Har du spørgsmål eller brug for hjælp til denne artikel henvises du til forummet.
Hvordan får du den til at smide det i Databasen ;)?
Oprettet af:
  Mail
14:20 17/05/2007
Nikolaj -> Har du overhovedet læst artiklen?
Oprettet af:
  Mail
14:22 17/05/2007
Fandt ud af det ;)
Sidst redigeret 14:59 - 17/05/2007
Oprettet af:
  Mail
14:55 17/05/2007
Rigtig fedt du lægger sådan en kode ud! Også meget lærerrig artikel :)

5/5 herfra! :D
Oprettet af:
  Mail
12:57 18/05/2007
Fed artikel holmes... Du gennemgår det hele, og forklarer det grundigt! :D
Oprettet af:
  Mail
11:47 19/05/2007
Tak for responsen alle sammen :D:D
Oprettet af:
  Mail
13:14 19/05/2007
Rigtig god har artikel 5/5
Oprettet af:
  Mail
14:13 19/05/2007
Faktisk en god artikel.. Keep up the good work..
Oprettet af:
  Mail
22:50 20/05/2007
Tak alle sammen =)
Oprettet af:
  Mail
12:25 21/05/2007
Du skal være oprettet og logget ind for at kommentere en artikel
Copyright © Rowl.dk v/ Michael Raagaard | 2005-12 | Alle rettigheder forbeholdes