Diferență între revizuiri ale paginii „Design doc Crawler”

De la dexonline wiki
Sari la navigare Sari la căutare
(Pagină nouă: == Sumar == Construirea unui crawler și a unui index pentru site-uri românești (cu texte corecte din p.d.v. gramatical): * Găsirea de cuvinte pe care DEX nu le conține pentr...)
 
 
(Nu s-au afișat 6 versiuni intermediare efectuate de același utilizator)
Linia 7: Linia 7:
* O statistică a folosirii diacriticelor
* O statistică a folosirii diacriticelor


Vezi și [[Crawler TODO]]


== Proiectarea in ansamblu ==
== Proiectarea in ansamblu ==
Linia 48: Linia 49:


Astfel cand facem back-off si revenim putem avea unde s-a oprit.
Astfel cand facem back-off si revenim putem avea unde s-a oprit.


== Proiectarea in detaliu ==
== Proiectarea in detaliu ==
Linia 61: Linia 61:
Baza de date
Baza de date


    CrawledPage(id, timestamp, url, httpStatus, rawPagePath, parsedTextPath)
CrawledPage(id, timestamp, url, httpStatus, rawPagePath, parsedTextPath)
 
 
 
    Link(id, url, canonicalUrl, domain, urlHash, crawledPageId)


Link(id, url, canonicalUrl, domain, urlHash, crawledPageId)


httpStatus - HTTP status code


    httpStatus - HTTP status code
Verificam daca linkul a fost expandat prin a vedea dacă a intrat în tabelul CrawledPage


    Verificam daca linkul a fost expandat prin a vedea dacă a intrat în tabelul CrawledPage
crawledPageId - același cu id de la CrawledPage, pagina în care am gasit link-ul


    crawledPageId - același cu id de la CrawledPage, pagina în care am gasit link-ul
urlHash - comparăm ca să nu inserăm același link din nou(md5(canonicalUrl)).
 
    urlHash - comparăm ca să nu inserăm același link din nou(md5(canonicalUrl)).


Totuși o să avem o problemă la linkuri relative vs linkuri absolute. Putem să eliminăm partea de Domain atunci cănd procesăm linkul, dar în final trebuie să compunem linkul absolut. Trebuie ignorate linkurile care n-au extensii relevante (imagini, etc).
Totuși o să avem o problemă la linkuri relative vs linkuri absolute. Putem să eliminăm partea de Domain atunci cănd procesăm linkul, dar în final trebuie să compunem linkul absolut. Trebuie ignorate linkurile care n-au extensii relevante (imagini, etc).
    Nu am găsit încă o bibliotecă pentru asta asemănător cu realpath. Dacă e, facem noi un mecanism, compunem link-ul și apoi îl testăm încercând să accesăm pagina respectivă și vedem ce întoarce.


Nu am găsit încă o bibliotecă pentru asta asemănător cu realpath. Dacă e, facem noi un mecanism, compunem link-ul și apoi îl testăm încercând să accesăm pagina respectivă și vedem ce întoarce.


=== Parsare HTML ===
=== Parsare HTML ===


- o bibliotecă pentru parsat pagini html, am folosit simple_html_dom (e mică dar își face treaba)
* o bibliotecă pentru parsat pagini html, am folosit simple_html_dom (e mică dar își face treaba)
- as merge si pe o biblioteca care face strip html tags, acum depinde ce gasim si cum se comporta cu broken html
* as merge si pe o biblioteca care face strip html tags, acum depinde ce gasim si cum se comporta cu broken html
- dacă nu găsim nimic, putem trânti un regexp chior -- găsim <div>-ul în care stă conținutul care ne interesează și facem un regexp doar pentru acela. Asta va insemna ca o sa folosim regexp-uri diferite per site
* dacă nu găsim nimic, putem trânti un regexp chior -- găsim <div>-ul în care stă conținutul care ne interesează și facem un regexp doar pentru acela. Asta va insemna ca o sa folosim regexp-uri diferite per site


=== Indexer ===
=== Indexer ===


Indexer - php
Indexer - php
baza de date - paris
baza de date - paris


Tabele
Tabele
Linia 99: Linia 92:
Cuvant
Cuvant


id cuvantCuDiacritice cuvantFaraDiacritice  idLexem=null (null daca nu are definitie)
id cuvantCuDiacritice cuvantFaraDiacritice  idLexem=null (null daca nu are definitie)




Freq
Freq


id caleFisier idCuvant freq(de aparitie sau de cate ori apare?)
id caleFisier idCuvant freq(de aparitie sau de cate ori apare?)




UseCase
UseCase


id idCuvant  text (propozitii)
id idCuvant  text (propozitii)






Mecanism diacritice
Mecanism diacritice




Linia 145: Linia 136:
Old Post
Old Post


    - să găsesc cuvinte pe care DEX nu le știe, e destul de challenging cum aș face asta rapid, dacă cuvintele sunt ordonate alfabetic, atunci e mai simplu puțin, depinde și dacă ai copii de tabele ordonate invers sau nu (așa am putea folosi LIMIT 1 pentru a opri query-ul).
* să găsesc cuvinte pe care DEX nu le știe, e destul de challenging cum aș face asta rapid, dacă cuvintele sunt ordonate alfabetic, atunci e mai simplu puțin, depinde și dacă ai copii de tabele ordonate invers sau nu (așa am putea folosi LIMIT 1 pentru a opri query-ul).
 
 
    Cred că asta se poate face în timpul indexării. Pentru căutarea full text pe dexonline, de exemplu, indexez un cuvânt găsit cu toate lexemele de care ar putea aparține. Astfel, „copii” poate proveni din „copie” sau din „copil”. Cele care nu aparțin de niciun lexem sunt cele pe care le dorim (ai să râzi, dar și baza de definiții a dexonline conține câteva cuvinte necunoscute).
 
    Mai trebuie tratate câteva cazuri speciale:


    - Forme contrase (am uitat exact cum se numesc), de exemplu „gândindu-” din „gândindu-se”.
    - Forme compuse, care adesea nu apar ca atare în dicționar: nemai+verb (doar la participiu sau la gerunziu -- nemaipomenit, nemaicrezând), prefixe ca re-, ne-, anti- etc.
    - Nume proprii


- daca avem o biblioteca toleranta la broken html, am putea face un parser general cu mai multe blocuri try-catch, (eventual logam tot ce se intampla aici), astfel evitam scrierea unei expresii regulate pentru fiecare site in parte.
Cred că asta se poate face în timpul indexării. Pentru căutarea full text pe dexonline, de exemplu, indexez un cuvânt găsit cu toate lexemele de care ar putea aparține. Astfel, „copii” poate proveni din „copie” sau din „copil”. Cele care nu aparțin de niciun lexem sunt cele pe care le dorim (ai să râzi, dar și baza de definiții a dexonline conține câteva cuvinte necunoscute).


Mai trebuie tratate câteva cazuri speciale:


- la partea de store-tuples n-aș pune definiția în DB, mai degrabă un url local de fișier.
* Forme contrase (am uitat exact cum se numesc), de exemplu „gândindu-” din „gândindu-se”.
* Forme compuse, care adesea nu apar ca atare în dicționar: nemai+verb (doar la participiu sau la gerunziu -- nemaipomenit, nemaicrezând), prefixe ca re-, ne-, anti- etc.
* Nume proprii
* daca avem o biblioteca toleranta la broken html, am putea face un parser general cu mai multe blocuri try-catch, (eventual logam tot ce se intampla aici), astfel evitam scrierea unei expresii regulate pentru fiecare site in parte.
* la partea de store-tuples n-aș pune definiția în DB, mai degrabă un url local de fișier.


index, timestamp, URL, raw_page_path, parsed_text_path
index, timestamp, URL, raw_page_path, parsed_text_path
Linia 166: Linia 154:
=== Inserarea de diacritice ===
=== Inserarea de diacritice ===


- o tabelă de cuvinte care contin diacritice (cu toate formele), eventual un associative array în memorie folosind memcached sau altceva, cu cheia *cuvantul fara diacritice* si valoarea *cuvantul cu diacritice*
* o tabelă de cuvinte care contin diacritice (cu toate formele), eventual un associative array în memorie folosind memcached sau altceva, cu cheia *cuvantul fara diacritice* si valoarea *cuvantul cu diacritice*
- pentru fiecare cuvânt parsat, verificăm dacă se poate scrie cu diacritice și îl înlocuim cu varianta respectivă.
* pentru fiecare cuvânt parsat, verificăm dacă se poate scrie cu diacritice și îl înlocuim cu varianta respectivă.


=== prelucrare tarball ===
=== prelucrare tarball ===


- daca link-urile sunt relative, ar merge crawler-ul si local, dar eu zic ca n-are rost sa functioneze la fel ca pentru parsare online, deoarece ar insemna salvarea din nou a paginii raw. In plus e mai rapid sa parcurgem toate fisierele si directoarele dintr-un director radacina. De aceea propun să avem un crawler local care doar extrage text si inserează în DB în tabelul CrawledPage.
* daca link-urile sunt relative, ar merge crawler-ul si local, dar eu zic ca n-are rost sa functioneze la fel ca pentru parsare online, deoarece ar insemna salvarea din nou a paginii raw. In plus e mai rapid sa parcurgem toate fisierele si directoarele dintr-un director radacina. De aceea propun să avem un crawler local care doar extrage text si inserează în DB în tabelul CrawledPage.
 


=== checkpoint & resume ===
=== checkpoint & resume ===


Ca sa nu parcurgem de mai multe ori acelasi link, ideea e sa facem hash pe linkuri si sa comparam hash-urile.
Ca sa nu parcurgem de mai multe ori acelasi link, ideea e sa facem hash pe linkuri si sa comparam hash-urile.


* adaugare la panoul de monitorizare
* functiuni la panoul de monitorizare cu posibilitatea de a reporni crawler-ul sau indexer-ul pe o anumita pagina/fisier text


+ adaugare la panoul de monitorizare
=== fisier de configurare===
+ functiuni la panoul de monitorizare cu posibilitatea de a reporni crawler-ul sau indexer-ul pe o anumita pagina/fisier text
 
===fisier de configurare===


2 variante
2 variante
Linia 196: Linia 181:
define("_KEY1_", "VAL1");
define("_KEY1_", "VAL1");
define("_KEY2_", "VAL2");
define("_KEY2_", "VAL2");


== Documentația Crawlerului ==
== Documentația Crawlerului ==
Linia 212: Linia 194:
=== Setările de bază ===
=== Setările de bază ===


1) în /DEX/wwwwbase/Crawler trebuie: .htaccess, AbstractCrawler.php, AppLog.php, Crawler.php, MemoryManagement.php, simple_html_dom.php, WhiteList.txt, directoarele ParsedText și RawPage
1) în /DEX/www/Crawler trebuie: .htaccess, AbstractCrawler.php, AppLog.php, Crawler.php, MemoryManagement.php, simple_html_dom.php, WhiteList.txt, directoarele ParsedText și RawPage


2) în /DEX/: la dex.conf trebuie adăugat fișierul /DEX/wwwbase/Crawler/crawler_dex.conf (commentarii în fișier)
2) în /DEX/: la dex.conf trebuie adăugat fișierul /DEX/www/Crawler/crawler_dex.conf (commentarii în fișier)


3) /DEX/phplib/models/CrawledPage.php și Link.php trebuie puse în același director pe server
3) /DEX/lib/models/CrawledPage.php și Link.php trebuie puse în același director pe server


4) Trebuie să puneți un fișier conținând user_agent-ul crawler-ului undeva într-un director care nu este public (am observat că unele site-uri nu cer user_agent (ex: romlit)).
4) Trebuie să puneți un fișier conținând user_agent-ul crawler-ului undeva într-un director care nu este public (am observat că unele site-uri nu cer user_agent (ex: romlit)).
Linia 224: Linia 206:
Și apoi să-i dați calea absolută în dex.conf :: user_agent_location
Și apoi să-i dați calea absolută în dex.conf :: user_agent_location


5) Editați fișierul /DEX/wwwwbase/Crawler/WhiteList.txt, instrucțiuni de utilizare în fișier
5) Editați fișierul /DEX/www/Crawler/WhiteList.txt, instrucțiuni de utilizare în fișier


=== Rulare crawler ===
=== Rulare crawler ===


în directorul /DEX/wwwwbase/Crawler/ rulați comanda
în directorul /DEX/www/Crawler/ rulați comanda


php Crawler.php
php Crawler.php
Linia 234: Linia 216:
va porni crawlerul, acesta va lua primul domeniu din WhiteList.txt și va căuta linkuri nedescoperite în baza de date.
va porni crawlerul, acesta va lua primul domeniu din WhiteList.txt și va căuta linkuri nedescoperite în baza de date.


Crawler-ul dispune de un fișier de log: /DEX/wwwwbase/Crawler/crawler_log, iar ]n dex.conf puteți seta
Crawler-ul dispune de un fișier de log: /DEX/www/Crawler/crawler_log, iar ]n dex.conf puteți seta
log2screen și log2file.
log2screen și log2file.


Linia 241: Linia 223:
URL-ul relativ va fi /Crawler/index.php, nu /Crawler/
URL-ul relativ va fi /Crawler/index.php, nu /Crawler/


1) Necesitatea fișierului /DEX/wwwwbase/Crawler/index.php
1) Necesitatea fișierului /DEX/www/Crawler/index.php


2) În directorul /DEX/phplib/ trebuie adăugat fișierul SmartyWrap.php ce conține metoda
2) În directorul /DEX/lib/ trebuie adăugat fișierul Smart.php ce conține metoda
 
<syntaxhighlight lang="php">
   static function smartyDisplay($skin) {
   static function smartyDisplay($skin) {
      
      
     self::$theSmarty->display($skin);
     self::$theSmarty->display($skin);
   }
   }
</syntaxhighlight>


3) În directorul /DEX/wwwbase/ajax trebuie adăugat fișierul fetchCrawlerStatus.php din același director de pe SVN
3) În directorul /DEX/www/ajax trebuie adăugat fișierul fetchCrawlerStatus.php din același director de pe SVN


4) În directorul /DEX/wwwbase/styles trebuie adăugat fișierul crawler.css din același director de pe SVN
4) În directorul /DEX/www/styles trebuie adăugat fișierul crawler.css din același director de pe SVN


5) În directorul /DEX/templates/crawler trebuie adăugat fișierul crawler.ihtml din același director de pe SVN. Dacă am uitat ceva și programul nu merge, încercați să verificați scripturile încluse din crawler.ihtml.
5) În directorul /DEX/templates/crawler trebuie adăugat fișierul crawler.ihtml din același director de pe SVN. Dacă am uitat ceva și programul nu merge, încercați să verificați scripturile încluse din crawler.ihtml.


6) În directorul /DEX/wwwbase/Crawler/ trebuie adăugat fișierul .htaccess din același director de pe SVN.
6) În directorul /DEX/www/Crawler/ trebuie adăugat fișierul .htaccess din același director de pe SVN.
 
(Autor: Alin Ungureanu)
 
[[Categorie:Design docs]]
[[Categorie:Design docs]]

Versiunea curentă din 4 februarie 2019 15:15

Sumar

Construirea unui crawler și a unui index pentru site-uri românești (cu texte corecte din p.d.v. gramatical):

  • Găsirea de cuvinte pe care DEX nu le conține pentru a le adauga (cu definiții)
  • Când un utilizator caută definiții vrei să îi oferi și exemple în care s-ar folosi cuvântul respectiv.
  • O statistică a folosirii diacriticelor

Vezi și Crawler TODO

Proiectarea in ansamblu

Crawlerul indentifică si salveaza paginile raw, extrage text-ul relevant si il salveaza ca fisier, depune in DB o linie in tabelul CrawledPage(id, timestamp, url, httpStatus, rawPagePath, parsedPageText), apoi din parsarea paginii respective vor rezulta link-uri, acestea vor fi adaugate in tabelul Link(descriere la Crawler mai jos). Dupa un timp de asteptare, crawler-ul poate incepe accesarea unei noi pagini. Astfel se cere o singura data pagina de la site, crawler-ul este separat de indexer, putand fi apelate independent.

Indexer-ul se uita in baza de date in CrawledPage si selecteaza urmatoarea linie cu textul neindexat(verifica eventual in tabela index daca exista), apoi dupa indexare o marcheaza.

Codul acesta zice ca se face exec in background

<?php
function execInBackground($cmd) {

    exec($cmd . " > /dev/null &");
}
?>

L-am testat, putem deci rula mai multe instante de indexer, in cazul in care indexarea ar merge mai greu decat parsarea + T wait.

Trebuie avută in vedere o verificare a fisierelor text, dacă au fost indexate. Pentru asta as propune un log + program php de monitorizare, in eventualitatea unui crash al sistemului.


Folosim log-uri peste tot si un panou (eventual meniu care alege fisierul log) care arata o statistica a activitatii.

Ex 1) timestamp | URL saved raw page parsed text 2) . . . 42) timestamp | URL saved raw page parsed text

Adaugam linii pe masura ce indeplinim activitati, astfel la un crash stim unde s-a oprit, in loc de saved raw page sau parsed text putem pune 0/1, T/F, etc

Astfel cand facem back-off si revenim putem avea unde s-a oprit.

Proiectarea in detaliu

Crawler

- un mecanism prin care să mint site-ul că programul meu e browserul (se rezolvă cu php curl), între accesul paginilor din site putem pune un T wait (timp de așteptare) 1 min.


Baza de date

CrawledPage(id, timestamp, url, httpStatus, rawPagePath, parsedTextPath)

Link(id, url, canonicalUrl, domain, urlHash, crawledPageId)

httpStatus - HTTP status code

Verificam daca linkul a fost expandat prin a vedea dacă a intrat în tabelul CrawledPage

crawledPageId - același cu id de la CrawledPage, pagina în care am gasit link-ul

urlHash - comparăm ca să nu inserăm același link din nou(md5(canonicalUrl)).

Totuși o să avem o problemă la linkuri relative vs linkuri absolute. Putem să eliminăm partea de Domain atunci cănd procesăm linkul, dar în final trebuie să compunem linkul absolut. Trebuie ignorate linkurile care n-au extensii relevante (imagini, etc).

Nu am găsit încă o bibliotecă pentru asta asemănător cu realpath. Dacă e, facem noi un mecanism, compunem link-ul și apoi îl testăm încercând să accesăm pagina respectivă și vedem ce întoarce.

Parsare HTML

  • o bibliotecă pentru parsat pagini html, am folosit simple_html_dom (e mică dar își face treaba)
  • as merge si pe o biblioteca care face strip html tags, acum depinde ce gasim si cum se comporta cu broken html
  • dacă nu găsim nimic, putem trânti un regexp chior -- găsim
    -ul în care stă conținutul care ne interesează și facem un regexp doar pentru acela. Asta va insemna ca o sa folosim regexp-uri diferite per site

Indexer

Indexer - php baza de date - paris

Tabele

Cuvant

id cuvantCuDiacritice cuvantFaraDiacritice idLexem=null (null daca nu are definitie)


Freq

id caleFisier idCuvant freq(de aparitie sau de cate ori apare?)


UseCase

id idCuvant text (propozitii)


Mecanism diacritice


Am să fac un tabel cu toate zonele care contin diacritice pe 8 sa 10 litere lungime și probabilitatea să se intample așa, plus un tabel în care o să țin aceste zone fără diacritice

zonaFaraDiactice

id text(string(10))


ZonaNeformatata

id idZonaFaraDiacritice count(default 1) text(string(10))


Facem count idZonaFaraDiacritice, apoi toate zonele cu același id (idZonaFaraDiacritice), calculam freq in tabelul FreqZone

FreqZone

idZonaNeformatata freq(float)


Putem face un panou ca la diacritice.com (idee Catalin), dropdownselect cu cea mai probabilă variantă (urmate de restul).

S-ar putea să nu aibă logică pe undeva că am scris-o în grabă. O mai revizuiesc.


Old Post

  • să găsesc cuvinte pe care DEX nu le știe, e destul de challenging cum aș face asta rapid, dacă cuvintele sunt ordonate alfabetic, atunci e mai simplu puțin, depinde și dacă ai copii de tabele ordonate invers sau nu (așa am putea folosi LIMIT 1 pentru a opri query-ul).


Cred că asta se poate face în timpul indexării. Pentru căutarea full text pe dexonline, de exemplu, indexez un cuvânt găsit cu toate lexemele de care ar putea aparține. Astfel, „copii” poate proveni din „copie” sau din „copil”. Cele care nu aparțin de niciun lexem sunt cele pe care le dorim (ai să râzi, dar și baza de definiții a dexonline conține câteva cuvinte necunoscute).

Mai trebuie tratate câteva cazuri speciale:

  • Forme contrase (am uitat exact cum se numesc), de exemplu „gândindu-” din „gândindu-se”.
  • Forme compuse, care adesea nu apar ca atare în dicționar: nemai+verb (doar la participiu sau la gerunziu -- nemaipomenit, nemaicrezând), prefixe ca re-, ne-, anti- etc.
  • Nume proprii
  • daca avem o biblioteca toleranta la broken html, am putea face un parser general cu mai multe blocuri try-catch, (eventual logam tot ce se intampla aici), astfel evitam scrierea unei expresii regulate pentru fiecare site in parte.
  • la partea de store-tuples n-aș pune definiția în DB, mai degrabă un url local de fișier.

index, timestamp, URL, raw_page_path, parsed_text_path


Inserarea de diacritice

  • o tabelă de cuvinte care contin diacritice (cu toate formele), eventual un associative array în memorie folosind memcached sau altceva, cu cheia *cuvantul fara diacritice* si valoarea *cuvantul cu diacritice*
  • pentru fiecare cuvânt parsat, verificăm dacă se poate scrie cu diacritice și îl înlocuim cu varianta respectivă.

prelucrare tarball

  • daca link-urile sunt relative, ar merge crawler-ul si local, dar eu zic ca n-are rost sa functioneze la fel ca pentru parsare online, deoarece ar insemna salvarea din nou a paginii raw. In plus e mai rapid sa parcurgem toate fisierele si directoarele dintr-un director radacina. De aceea propun să avem un crawler local care doar extrage text si inserează în DB în tabelul CrawledPage.

checkpoint & resume

Ca sa nu parcurgem de mai multe ori acelasi link, ideea e sa facem hash pe linkuri si sa comparam hash-urile.

  • adaugare la panoul de monitorizare
  • functiuni la panoul de monitorizare cu posibilitatea de a reporni crawler-ul sau indexer-ul pe o anumita pagina/fisier text

fisier de configurare

2 variante 1) conf.ini [db] key1=value1 key2=value2 Global.php care incarca intr-o variabila array statica generată de parse_ini_file(config.ini)

2) conf.php

define("_KEY1_", "VAL1"); define("_KEY2_", "VAL2");

Documentația Crawlerului

[outdated]

Nu uitați să instalați php-curl

Baza de date

Setările de bază

1) în /DEX/www/Crawler trebuie: .htaccess, AbstractCrawler.php, AppLog.php, Crawler.php, MemoryManagement.php, simple_html_dom.php, WhiteList.txt, directoarele ParsedText și RawPage

2) în /DEX/: la dex.conf trebuie adăugat fișierul /DEX/www/Crawler/crawler_dex.conf (commentarii în fișier)

3) /DEX/lib/models/CrawledPage.php și Link.php trebuie puse în același director pe server

4) Trebuie să puneți un fișier conținând user_agent-ul crawler-ului undeva într-un director care nu este public (am observat că unele site-uri nu cer user_agent (ex: romlit)).

Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0

Și apoi să-i dați calea absolută în dex.conf :: user_agent_location

5) Editați fișierul /DEX/www/Crawler/WhiteList.txt, instrucțiuni de utilizare în fișier

Rulare crawler

în directorul /DEX/www/Crawler/ rulați comanda

php Crawler.php

va porni crawlerul, acesta va lua primul domeniu din WhiteList.txt și va căuta linkuri nedescoperite în baza de date.

Crawler-ul dispune de un fișier de log: /DEX/www/Crawler/crawler_log, iar ]n dex.conf puteți seta log2screen și log2file.

Setări pentru monitorul din browser

URL-ul relativ va fi /Crawler/index.php, nu /Crawler/

1) Necesitatea fișierului /DEX/www/Crawler/index.php

2) În directorul /DEX/lib/ trebuie adăugat fișierul Smart.php ce conține metoda

  static function smartyDisplay($skin) {
    
    self::$theSmarty->display($skin);
  }

3) În directorul /DEX/www/ajax trebuie adăugat fișierul fetchCrawlerStatus.php din același director de pe SVN

4) În directorul /DEX/www/styles trebuie adăugat fișierul crawler.css din același director de pe SVN

5) În directorul /DEX/templates/crawler trebuie adăugat fișierul crawler.ihtml din același director de pe SVN. Dacă am uitat ceva și programul nu merge, încercați să verificați scripturile încluse din crawler.ihtml.

6) În directorul /DEX/www/Crawler/ trebuie adăugat fișierul .htaccess din același director de pe SVN.

(Autor: Alin Ungureanu)