Azt gondolná az ember, hogy egy autóval kapcsolatban csak az ECU programozása merülhet fel, mint programozás, pedig az szigorúan véve “csak” adatbevitel. Marcsi néni sem Excelt programoz, amikor a számlák sorszámát rögzíti. Sarkított példa persze, de új kód nem születik, a programozás pedig arról szól.

Nem tudom említettem-e, hogy napjaim nagy részét (szerencsés esetben) kódolással töltöm. Talán az első posztok egyikében előjött. Szóval programozok, vagy másokat próbálok rávenni arra, hogy programozzanak. (Ez a kevésbé szerencsés eset.) Régen még hittem, hogy ez valamiféle előremutató dolog, azóta erről már nem vagyok teljesen meggyőződve. Ahogy “öregszik” az ember, úgy nyílik ki a világ – jobb esetben. Nekem ez a gép előtt ülés egy idő után nyűg lett, az emberek, az ügyfelek és a kollégák csesztetésével együtt. Vannak persze sikerélmények, de szerintem idióta az, aki az életében a “jó érzéseket” kizárólag a munkahelyétől várja. Ez egyszerűen csak egy forrás ahhoz, hogy a “jó érzéseket” finanszírozzuk. 🙂

Node elkalandoztam. Hogy jön ide a Perl? Az egy programnyelv? – Az bizony. Méghozzá egy elég egyszerű scripting nyelv, azaz nem kell lefordítani a kódot ahhoz, hogy fusson, elég hozzá egy futtató környezet. Könnyen tanulható, és már kis tudással is egészen jó dolgokat lehet megvalósítani vele. (Welcome to my life. :D)

 Egyik este azzal a problémával találkoztam, hogy át kéne rágnom magam az Atkins Rotary terméklistáján, és azokat a termékeket, melyekre szükségem lehet, le kéne mentenem egy táblázatba a tulajdonságaikkal együtt. (Amilyen pl. a név, az ár, a leírás, stb.) Tekintve az AR több ezeres terméklistáját, már az elején éreztem, hogy ez biza el fog tartani egy darabig. Utálok “fát vágni”, azaz repetitív dolgokat csinálni, mert az majdnem minden esetben a drága idő elb@szását jelenti. Így viszonylag gyorsan jött az ötlet, hogy kéne egy baromi egyszerű kis progi, ami ha kigyűjtöm az URL-eket, akkor lehúzza a számomra fontos infókat. 

Ebből lett ez:

#!perl

use LWP::Simple;
use HTML::TreeBuilder::XPath;
use POSIX;

use strict;
use warnings;
use utf8;

no warnings 'uninitialized';

binmode STDOUT, ":utf8";
binmode STDERR, ":utf8";
binmode STDIN, ":utf8";

if (open(my $fh,"urls.txt")) {
my @lines = <$fh>;
close($fh);

print "File Opened.\n\n";

for my $line (@lines) {

chomp($line);
my ($url, $num) = split(/\t/,$line);

print "Requesting -- $num -- $url\n";

my $page = get($url) or warn $!;
my $p = HTML::TreeBuilder::XPath->new_from_content( $page );

my $name = $p->findvalue( '/html/body//div[@class="product-details-info"]/h1[@class="fn title"]');
my $description = $p->findvalue( '/html/body//div[@class="product-details-info"]/div[@class="brief-descr product-description"]');
my $price = $p->findvalue( '/html/body//div[@class="product-details-info"]/div[@class="product-price widget-fingerprint-product-price"]/ul[@class="product-price"]/li/span[@class="price product-price"]');
$p->delete;
if (open(my $sd,">>data.txt")) {
print $sd "$name\t$description\t$price\n";
close($sd);
}

print "Done.\n\n";

undef $page;
undef $p;
undef $name;
undef $description;
undef $price;
undef $url;
undef $num;

}

print "Processing done.\n";

}
else {

print "Could not open URL file.\n";

}

exit;

 

Felmerül a kérdés, hogy “Mi ez a sz@r????” UNSUBSCRIBE!!!!!

Nyugi. Ezt jelenti:

 

1. Ez a fejléc, a használt modulok és az alapbeállítások:

#!perl

use LWP::Simple;
use HTML::TreeBuilder::XPath;
use POSIX;

use strict;
use warnings;
use utf8;

no warnings 'uninitialized';

binmode STDOUT, ":utf8";
binmode STDERR, ":utf8";
binmode STDIN, ":utf8";

 

2. Megnyitjuk az URL fájlunkat, ami a webcímeket az alábbi formában tárolja:

http://webhely neve/elérési út/stb<TAB>sorszám

Például: http://www.atkinsrotary.com/store/79-11-Rx7-Flywheel-Ring-Gear-Brake-ARE923.html?category_id=569 1

(Az 569 és az 1 között nem szóköz, hanem tab van.)

A fájl megnyitását és felolvasását a következő rész végzi:

if (open(my $fh,"urls.txt")) {
my @lines = <$fh>;
close($fh);

print "File Opened.\n\n";

A végén ki is írtuk, hogy a fájlt faxán megnyitottuk. Tudja már a júzer, hogy merre hány óra.

 

3. Itt most fura dolog történik, a beolvasott fájl minden sorára végrehajtunk majd valamit, ezt jelenti a következő rész:

for my $line (@lines) {

 

4. Ezt hajtjuk végre soronként:

print "Requesting -- $num -- $url\n";

my $page = get($url) or warn $!;
my $p = HTML::TreeBuilder::XPath->new_from_content( $page );

Azaz kiírjuk, hogy hanyadik linket dolgozzuk fel, és a címet.

Letöltjük a $page változóba a weblapot.

A $p változóban fa szerkezetben eltároljuk az imént letöltött weblapot. Egyszerűbb mint a szelepillesztés, mi?

 

5. Innen jönnek az érdekes dolgok:

my $name = $p->findvalue( '/html/body//div[@class="product-details-info"]/h1[@class="fn title"]');
my $description = $p->findvalue( '/html/body//div[@class="product-details-info"]/div[@class="brief-descr product-description"]');
my $price = $p->findvalue( '/html/body//div[@class="product-details-info"]/div[@class="product-price widget-fingerprint-product-price"]/ul[@class="product-price"]/li/span[@class="price product-price"]');

A $name változóba beletesszük azt az értéket, ami a weblapon egy product-details-info stílusú div-ben található, fn title stílusú h1-ben van. A div egy “tárolódoboz”, a h1 pedig Heading 1, ilyen a Wordben is van, ezeken ne akadunk fel. Amin viszont érdemes elgondolkozni, az az, hogy hogyan találjuk meg ezeket a dolgokat. Tök egyszerű: ha pl. a fenti Atkins Rotary-s linket megnyitod Chrome-ban, és a termék nevén nyomsz egy “Inspect”-et (magyarul gondolom “vizsgálat”) akkor felhozza a HTML kód vonatkozó részét.

Itt szemügyre vehetjük, hogy a szövegrész milyen konténerekben van benne, melyekre esetleg kereshetünk. (Furcsa módon egy “product-details-info” class-ú DIV-ben egy “fn title” class-ú H1-et fogunk találni…

Ugyanezzel a módszerrel megvizsgáljuk a descriptiont is.

Itt egy “product-details-info” class-ú DIV-ben találunk egy “brief-descr product-description”-class-ú DIV-et. Ebben van a description, azaz a termék leírása. Ezt töltjük a $description változóba.

Az ár szivatósabb, mert az oldal tele van az AR saját reklámjaival, tehát itt az eddigieknél jóval specifikusabbnak kell lennünk, hogy CSAK a termékünk árát hozza fel.

Itt ugyancsak a “product-details-info” class-ú DIV-ben kutakodunk, találunk benne egy “product-price widget-fingerprint-product-price” class-ú DIV-et, azon belül egy “product-price” class-ú UL tárolót, azon belül egy LI tárolót, azon belül ott van a SPAN-unk, akit kerestünk. A class-a “price product-price”. Tehát DIV/DIV/UL/LI/SPAN, ebből lett a stílusjelöléseket (class-okat) felhasználva a $price változót feltöltő kód.

 

6. Túl vagyunk a nehezén. Hogy ne fossa tele a memóriát, letöröljük a $p változóban tárolt honlap struktúrát:

$p->delete;

 

7. Kiírjuk a data.txt fájlba a termék nevét, a leírást és az árat, tabokkal elválasztva. Ez azért jó, mert megnyitom a TXT fájlt, mindent kijelölök, nyomok egy másolást, nyitok egy Excelt, ott beillesztés. Minden ott lesz a helyén. Ez a rész gondoskodik erről:

if (open(my $sd,">>data.txt")) {
print $sd "$name\t$description\t$price\n";
close($sd);
}

 

8. A többi már csak sallang, és a különböző ciklusok lezárása:

print "Done.\n\n";

undef $page;
undef $p;
undef $name;
undef $description;
undef $price;
undef $url;
undef $num;

}

print "Processing done.\n";

}
else {

print "Could not open URL file.\n";

}

exit;

Azaz, kiírjuk, hogy sikeresen eljutottunk eddig a részig, mert itt lusta voltam hibakezelést készíteni, feltételezhetjük, hogy egy gagyi TXT fájlba sikerül beszúrni egy sort.

Az undef sorok eltakarítják az eddig használt változókat. Régi hagyomány, szentimentális értéke van. Nyugodtan kihagyhatjátok.

Hoppá! A “}” jel lezárja a ciklusunkat! Melyiket? Amellyel az urls.txt fájl minden során végigmentünk.

Kiírjuk, hogy véget ért a feldolgozás.

A következő “}” jel lezárja azt a feltételt, amit az elején adtunk: csak akkor hajtjuk végre a “{}” jelek közti részt, ha az urls.txt-t sikeresen megnyitottuk.

Az else { valami; } arra vonatkozik, hogy ha az előző dolog nem teljesül, akkor mi legyen. Tehát ha nem lehet megnyitni az urls.txt-t, akkor írja ki, hogy sikertelen a megnyitás.

Az exit vajon mi? Készen vagyunk! Sokkal egyszerűbb, mint egy gátló csere, és egy csomó időt megtakarítottunk.

 

Lehetett volna még csicsázni a szkriptet (tanuljuk meg ezt a gyönyörű magyar szót), hogy legyen drag&drop doboz, és csak bele kelljen húzni a könyvjelzőket vagy a címeket, de profi módon a hatékonyságra mentem rá a részletek helyett, tehát a legkisebb kódolási befektetéssel a legnagyobb időmegtakarítást elérni. Ez faxán sikerült is.

Bárcsak két bolttal az Atkins Rotary előtt eszembe jutott volna… 😉

Ahhoz, hogy működésre bírd a kódot, el kell battyognod a http://activestate.com-ra, és letöltened egy ActivePerl-t. Az 5.22-es x86-os verzió tökéletes a script futtatásához. Telepítés után egy admin parancssorban add ki a “ppm install HTML-TreeBuilder-XPath” parancsot, és felteszi a TreeBuilder XPath modulját.

Innentől a progi működőképes.

Drága közönség, remélem ezt a posztot legalább annyira élveztétek, mint én. 🙂 

 

 

 

Hozzászólások