Töissä tuli kerran tarve järjestää lista nettisivuja sivuston teknologian vanhuuden mukaiseen järjestykseen. Koska emme löytäneet valmista palvelua/ohjelmaa, joka tämän tekisi, otin tästä itselleni pienen pähkinän purtavaksi. Tuli nimittäin tunne, ettei tuollaiseen kovin monta tuntia mene, sillä tiesin, ettei järjestelmän tarvitse olla täydellinen. Noin viiden tunnin päästä pystyin tuottamaan nettisivulistan yllättävänkin uskottavasti ikäjärjestyksessä.
Voisin näyttää, miten sen tein, jos joku innostuisi kehittämään tätä ideaa pidemmälle. Otan mielelläni vastaan kehitysehdotuksia! 🙂
Näin aloitin
Sain ajatuksen, että sivustoja voisi rankata niiden html-koodissa löytyvien tekstipätkien ja html-tägien mukaan. Web-teknologia on 1990-luvun alkuvuosien jälkeen kehittynyt kovasti, ja olen itse työskennellyt sen parissa alusta asti. Siksi ajattelin, että minulla voisi olla jonkinlainen mutu-pohjainen käsitys siitä, millä vuosikymmenellä löytyi mitäkin html-tägejä jne.
Jatkoajatuksena tuli, että tägejä voisi pisteyttää plus- ja miinuspisteillä tägien ”moderniuden” mukaan: miinuspisteitä tulee vanhoista tägeistä ja pluspisteitä uudemmista. Tein hakuammunnalla tällaisen listan tägeistä ja koitin muutaman testisivun perusteella arvioida niiden pisteytyksiä:
Nyt tarvitaan vielä ohjelma, joka lukee listan nettiosoitteista ja tuon Rankdata.xlsx:n. Nettiosoitelista (tässä Yritykset.xlsx) sisältää kolme saraketta:
Y-tunnus | Yritys | WWW-osoite |
1234567-8 | Yritys Oy | http://www.yritys.fi |
Koska työympäristöni oli tuota tehdessä Windows ja halusin päästä nopeasti liikkelle, päätin käyttää koodauskielenä minulle hyvin tuttua Perliä. (En vielä tuolloin ollut opetellut Pythonia, joka olisi nykyisin valintani tällaiseen). Latasin läppärilleni ActivePerlin ja aloin koodata. Muistin, että 2000-luvun alussa Professional Tester-lehteen kirjoittamassani artikkelissa, on valmiita pätkiä copy-pastettavaksi, joten hyödynsin tietenkin sitä. (Kai tiesit, että kaikki koodaajat copy-pastettavat ratkaisuja, tyypillisesti googlettamalla? 🙂 )
Jouduin asentelemaan Perliin lisämoduleja, jotta sain sen kutsumaan nettisivuja. En enää muista, oliko ActivePerlissä oma lisäosien lataamisohjelma, vai hainko niitä CPANista.
Ohjelmastani ei tullut mitenkään kovin kaunis, mutta sain sen kyllä toimimaan. Tässä on koko koodi:
use LWP::UserAgent;
use Spreadsheet::ParseXLSX;
use Spreadsheet::WriteExcel;
my $parser = Spreadsheet::ParseXLSX->new;
#
# Read the input data from rankdata.xlsx into the @data hash
#
my @data;
my $excel = $parser->parse("rankdata.xlsx");
foreach my $sheet (@{$excel -> {Worksheet}}) {
$sheet -> {MaxRow} ||= $sheet -> {MinRow};
foreach my $row (1 .. $sheet -> {MaxRow}) {
$sheet -> {MaxCol} ||= $sheet -> {MinCol};
$data[$row]{"tag"} = lc($sheet -> {Cells}[$row][0]->{Val});
$data[$row]{"points"} = $sheet -> {Cells}[$row][1]->{Val};
}
}
#
# Read the company info to the @companies hash
#
my @companies;
$excel = $parser->parse("Yritykset.xlsx");
foreach my $sheet (@{$excel -> {Worksheet}}) {
$sheet -> {MaxRow} ||= $sheet -> {MinRow};
foreach my $row (1 .. $sheet -> {MaxRow}) {
$sheet -> {MaxCol} ||= $sheet -> {MinCol};
$companies[$row]{"businessid"} = $sheet -> {Cells}[$row][0]->{Val};
$companies[$row]{"company"} = $sheet -> {Cells}[$row][1]->{Val};
$companies[$row]{"url"} = $sheet -> {Cells}[$row][2]->{Val};
$companies[$row]{"points"} = 0;
}
}
# Open excel file for writing and write headers
my $workbook = Spreadsheet::WriteExcel->new('Output.xls');
$worksheet = $workbook->add_worksheet();
$format = $workbook->add_format();
$format->set_bold();
$worksheet->write(0,0, "Business ID",$format);
$worksheet->write(0,1, "Company",$format);
$worksheet->write(0,2, "URL",$format);
$worksheet->write(0,3, "Points",$format);
$worksheet->write(0,4, "Size",$format);
$worksheet->write(0,5, "Other",$format);
$worksheet->write(0,6, "Tags",$format);
#
# Loop all companies, call URLs, determine points, write result to Output.xls
#
my $ua = LWP::UserAgent->new;
for my $c (1 .. $#companies) {
print "Analyzing ".$companies[$c]{"url"}."...";
my $req = HTTP::Request->new(GET => $companies[$c]{"url"});
my $resp = $ua->request($req);
if (!$resp->is_success) {
$companies[$c]{"error"} = "Error ".$resp->code.". ";
if (!$resp->code == 500) {
$companies[$c]{"points"} = -100;
}
}
else {
$companies[$c]{"error"} = "";
}
# Loop the http response
$companies[$c]{"tags"} = "";
$page_content = lc($resp->as_string);
$companies[$c]{"size"} = length($page_content);
my @lines = split /\n/, $page_content;
foreach my $line (@lines) {
# Check with tag data
for my $i (1 .. $#data) {
if ( index($line, $data[$i]{"tag"}) > 0 && !$data[$i]{"found"}) {
$companies[$c]{"points"} += $data[$i]{"points"};
$companies[$c]{"tags"} = $companies[$c]{"tags"}.", ".$data[$i]{"tag"};
print $companies[$c]{"tags"}.";";
$data[$i]{"found"} = 1;
}
}
}
print $companies[$c]{"error"};
# Penalize small pages
if ($companies[$c]{"size"} < 5000) {
$companies[$c]{"points"} -= 30;
}
elsif ($companies[$c]{"size"} < 10000) {
$companies[$c]{"points"} -= 15;
}
$worksheet->write($c,0, $companies[$c]{"businessid"});
$worksheet->write($c,1, $companies[$c]{"company"});
$worksheet->write($c,2, $companies[$c]{"url"});
$worksheet->write($c,3, $companies[$c]{"points"});
$worksheet->write($c,4, $companies[$c]{"size"});
$worksheet->write($c,5, $companies[$c]{"error"});
$worksheet->write($c,6, $companies[$c]{"tags"});
print $companies[$c]{"points"}." points. ";
print "Done.\n $c.";
# Reset "tag found" status for the next page in loop
for my $i (1 .. $#data) {
$data[$i]{"found"} = 0;
}
}
print "Analyze completed.";
Ylläoleva ohjelma tuotti noin 20 minuutissa (kävi siisläpi 1700 nettiosoitetta) Excel-tiedoston, jossa nettisivut olivat saaneet rankkauksia sen mukaan, mitä sivulta löytyi (yritystiedot poistettu ennen kuvakaappauksen ottamista…ymmärrätte varmaan).

Ei mitenkään kaunista, mutta siivoilin listan käsin ja järjestelin sen Points-sarakkeen mukaana ja muutama pistokoe todisti, että olin onnistunut hankkeessani melko hyvin.
Mitä opin?
- Perl on vanha ohjelmointikieli ja teknologia, opin sen 1990-luvulla. Oli esim. vaikea saada SSL-modulia toimimaan; sitä tarvittiin https-suojattujen sivujen tutkimiseen. Myöhemmin tajusin, että esim. modernilla Pythonilla tuo ohjelma olisi ollut kaikin puolin kätevämpi tehdä, sillä se kommunikoi sujuvammin nykyrajapintojen kanssa.
- Kaikki sivustot eivät päästäneet skriptiä läpi, sillä ne tunnistivat sen todennäköisesti ”robotiksi” User Agent-tiedon perusteella. Myöhemmin testasin User Agentin feikkaamista (sai nettisivut luulemaan systeemiäni Chrome-selaimeksi) ihan hyvällä menestyksellä. Tässä Perl-koodinpätkä siihen:
$ua->agent(”Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36”);
Vielä yksi asia!
Varomaton nettisivujen tutkiminen tällaisella ”robotilla” voidaan hyvällä syyllä pitää vähän kyseenalaisena puuhana. Kannattaa olla tarkkana, ettei vahingossa kehitä vaikkapa silmukkaa, joka pommittaa jotain tiettyä nettisivua kutsuilla. Sellaista voisi kutsua jonkinlaiseksi alkeelliseksi palvelunestohyökkäykseksi. Nykyiset nettisivut eivät tällaisesta yleensä kyykähdä, mutta onhan vastuuton robottien käyttö kiusantekoa ja sotkee ainakin ”pommituskohteiden” nettisivu-kävijätilastoja.