După 5 luni, Zelist …

Undeva în luna Aprilie a anului curent extrăgeam lista de bloguri a Zelist; poate vă amintiţi. Ei, iată, au trecut aproape 5 luni de atunci, şi am anumite curiozităţi vizavi de topul lor. Spre exemplu, oare câte bloguri or fi adăugat de atunci până acum? Şi mai exact ce bloguri? Înainte de a putea trece la a răspunde întrebării, vom avea nevoie de o copie a listei curente a Zelist. Cum data trecută nu am explicat clar cum se poate face acest lucru, cred că e momentul s-o fac.

~*~

Aveţi nevoie pentru început (prerequisite) fie de o distribuţie Linux fie de softul Cygwin pentru Windows. În cazul în care folosiţi Cygwin, trebuie selectat manual Curl (în categoria Net), el nefiind inclus în pachetul predefinit pentru instalare; de asemenea, nu este deloc recomandată o instalare completă a acestui software, fiind o operaţiune ce poate dura câteva ore bune şi care v-ar lăsa mai săraci cu 12gb.

Bun, pornim terminalul, alegem un director de lucru, facem acolo un script (stiinta.sh e un nume fain), iar în script zicem aşa:

for ( (i=1; i<=1297; i++) )
do
# echo "Pagina $i" >> f1.txt; # aceasta linie nu e musai necesara
curl "http://www.zelist.ro/bloguri/pagina-$i.html" | grep "infoBtn" >> f1.txt;
done

Notaţi că ghilimelele puse de WordPress sunt greşite, aveţi a pune manual ghilimele normale. A, şi e de preferat să editaţi scriptul în Notepad++, unde la final daţi din meniu Edit – EOL Conversion – Unix format; dacă editaţi cu Notepad din Windows vă va băga nişte caractere pe care Cygwin nu le digeră prea bine. Ah, şi nu lăsăm spaţiu între parantezele de la for, eu fac asta din motive de plugins ale WordPress(i).

(edit: Patru ani mai târziu, am descoperit tagul numit code..)

Textul se copiază într-un editor care poate salva fişierul în format specific pentru Linux – Notepadul simplu nu ştie, însă Notepad++ ştie. Iar parantezele duble se scriu fără spaţiu între ele.

Este destul de simplu de înţeles ce face scriptul dacă vă ştiţi cu variabile (de la mate, să zicem): avem o buclă (for) care face 1297 paşi (variabila i), la fiecare pas scriind în fişierul f1.txt două rânduri. Curl ne aduce întreg conţinutul paginii web, bara verticală “|” se numeşte pipe şi varsă rezultatul primei comenzi mai departe; grep alege doar acele rânduri care conţin un anume text (infoBtn), iar dacă priviţi în sursa html a unei pagini Zelist veţi înţelege şi de ce(ii). Operatorul “>>” indică un fişier în care să se scrie rezultatele întregii operaţiuni, în loc ca ele să ne fie vomate pe ecran(iii).

Scriptul ăsta este şi cel mai mare consumator de timp, de altfel – în funcţie de procesor şi viteza conexiunii la internet, poate dura câteva ore(iv). La final vom avea un fişier  de forma:

Pagina 1
<a href=”http://tudorchirila.blogspot.com” onClick=”window.open(‘http://tudorchirila.blogspot.com’);return false;”>
<a href=”http://www.umbrelaverde.ro” onClick=”window.open(‘http://www.umbrelaverde.ro’);return false;”>
<a href=”http://www.ciutacu.ro” onClick=”window.open(‘http://www.ciutacu.ro’);return false;”>

Deschideţi f1.txt într-un editor care ştie şi să numeroteze liniile (eu unul recomand Notepad++). Vă asiguraţi că numărul de bloguri de pe saitul Zelist este egal cu numărul de linii din fişier (minus 50, dacă aţi păstrat comanda echo în script). Dacă nu sunt egale numerele, vă spargeţi capul să detectaţi unde-i greşeala (dar în principiu rezultatele ar trebui să fie corecte).

Pentru a elimina liniile care indică pagina, folosim un grep inversat (care ne arată liniile ce nu conţin un anume text):

grep -v “Pagina” f1.txt > f2.txt

Apoi edităm f2.txt şi eliminăm cu un simplu search & replace textul din faţa adreselor web (la început sunt caractere tab, de acolo provine spaţiul gol):

                                    <a href=”

Ei, acum arată ceva mai uman:

http://tudorchirila.blogspot.com” onClick=”window.open(‘http://tudorchirila.blogspot.com’);return false;”>
http://www.umbrelaverde.ro” onClick=”window.open(‘http://www.umbrelaverde.ro’);return false;”>
http://www.ciutacu.ro” onClick=”window.open(‘http://www.ciutacu.ro’);return false;”>
http://www.bookblog.ro” onClick=”window.open(‘http://www.bookblog.ro’);return false;”>

Ne mai rămâne să scăpăm de resturile de html de după numele domeniului. Asta se poate face simplu, utilizăm comanda cut căreia îi dăm semnul de ghilimele drept delimitator:

cat f2.txt | cut -f 1 -d ‘”‘ >> f3.txt
# -d apostrof ghilimele apostrof
# cut împarte textul în mai multe bucăţi delimitate de anumite semne; tot ce-i înainte de token (ghilimele) va fi păstrat (-f 1), tot ce-i după se aruncă

Se putea şi mai simplu, dând f2.txt direct ca parametru pentru cut, însă voiam să mai folosesc o dată un pipe. Rămâne sarcină cititorului să vadă ce-i cu comanda cat. Ei, acum avem într-adevăr un f3 curat de tot, în care avem doar adrese!

tudorchirila.blogspot.com
umbrelaverde.ro
ciutacu.ro
bookblog.ro

Întâmplarea face însă că Zelist păstrează unele adrese cu numele subdomeniului “www.” în faţă. Cum facem? Soluţia rapidă este să edităm manual cu search & replace, însă dezavantajul ar fi că astfel un domeniu numit “awww.ro” va deveni “aro”, deci inutilizabil. Eu am ales o soluţie manuală, şi anume:

grep “www.” f3.txt > temp
sort temp > temp2

Din ceva motiv, grep îmi caută doar textul “www”, fără punct; ţinem minte. Fişierul temp2 reprezintă toate liniile ce vor fi afectate de operaţiune, sortate alfabetic. Vasta majoritate chiar trebuie să se afle acolo, însă primele 5 nu:

angiwww.blogspot.com
awww.ro
qqwwwrrrrttttt.blogspot.com
rawwww.blogspot.com
www,fansf.wordpress.com

Aşa că efectuez search & replace în editorul text, însă apoi revin şi editez înapoi unde-i cazul. Astfel, într-un final am ajuns la f4.txt, un fişier care poate fi comparat cu cel din Aprilie. Nici n-a durat mult.

(continuarea într-un articol viitor)
(am urcat pe server o arhivă ce conţine fişierul f4.txt şi la care voi adăuga fişiere relevante pe măsură ce mai scriu articole)

----------
  1. din dezavantajele tehnologiei lol []
  2. editare: Articolul iniţial folosea onClick. Între timp Treeworks au introdus variaţiuni în felul cum linkează către blogurile listate, nefolosind javascript pentru toate elementele din listă. La data curentă atributul infoBtn pare a fi prezent la toate blogurile din listă, pasibil însă de a fi schimbat în viitor []
  3. De fapt aveţi mai multe opţiuni: operatorul “>” scrie şi el într-un fişier, însă dacă fişierul există deja atunci la fiecare pas el va fi rescris de la zero. Operatorul “>>” doar adaugă dacă fişierul există deja, lucru de care avem nevoie în acest caz particular. []
  4. La data scrierii articolului, “topul” Zelist arăta spre 60.000 de bloguri. Astăzi, în Martie 2013, arată doar top-5000, ceea ce reduce şi timpul de rulare la doar câteva zeci de minute []
----------
Epifanie cu DEXu-n braţe
După 5 luni, Zelist ... #2

Comments 6

  • Dacă vrei să parsezi “www.” la începutul unui șir folosește ancora “^” pentru a-i zice că începe șirul (“$” pentur final) și escapează punctul care înseamnă orice caracter.

    Deci, grep “^www.”

    Also, unele înlocuiri le puteai face cu sed, eventual in place (-i) ca să nu ai nevoie de atâtea fișiere. Mai putea reduce numărul de fișiere folosind mai multe pipe-uri dar atunci era mai greu de explicat ce fac bucățile de comenzi.

    La final, sed și cut pot fi înlocuite cu succes de awk. Pe lângă flexibilitatea mai mare ai și un spor de performanță.

    0.02€ \\//_

  • Mulţam fain de sugestia pentru grep, chiar e utilă. Din păcate mi-e o lene groaznică să învăţ suficient regex cât să-mi fie util.

    Prefer să am mai multe fişiere intermediare, pentru a putea să revin dacă execut o chestie care iese prost.

    Nu ştiu ce spui cu sporul de performanţă al awk, am folosit un script simplu gen awk ‘{print “firefox ” $0 }’ 1.txt > 2.txt şi-am cam adormit lângă el. Ce-i drept, pe o altă maşină, poate pe un i3 va merge acceptabil.

  • Din ceva motiv, grep îmi caută doar textul “www”, fără punct; ţinem minte.

    Explicația ar fi aceea că simbolul „.” are în expresiile regulate GNU semnificația de „orice caracter” – motiv pentru care wildcard-ul din globbing se înlocuiește cu „.*” în regex. Evident, poți să folosești o secvență de escape, astfel că „grep “www\.”” o să includă și punctul în căutare.

    Justificarea apropo de ce a zis Mihai legat de awk e că fiecare operator pipe/operație pe fișiere are drept consecință crearea unui nou proces în sistemul de operare, respectiv o scriere pe hard-disk. Asta ar duce teoretic la penalizări de performanță, motiv pentru care un apel de awk poate fi mai eficient decât un pipeline de sed-uri și/sau operații pe fișiere. Practic s-ar putea însă să nu conteze prea tare.

    Pe mine mă bătea gândul într-o vreme să folosesc Perl pentru procesări de text, deoarece am auzit că are un sistem foarte puternic de expresii-regulate-care-s-mai-mult-decât-regulate. Până la urmă lenea a învins.

  • Dupa 5 luni- Zelist — – dAImon-s blog…

    O metodă de parsat ZeLista. DAImon s-o pus pe scris, văd….

  • […] articolul precedent am explicat cum se pot extrage date din paginile web ale saitului Zelist, cu demonstraţie […]

  • […] Apoi, hiatus. Vreo 5 ani, cît mi-am pierdut timpu’ ca operator pc (data entry clerk). Am mai atins scripting de bash, culmea, cu ocazia explorărilor Zelist. […]