Ściągnąłem protokoły z wyborów do sejmików wojewódzkich jeszcze raz. Punktem wyjścia były indywidualne pliki dla każdej gminy pobrane ze strony samorzad2014.pkw.gov.pl
. Te pliki zawierają zsumowane wyniki wyborów dla danej gminy, ale także zawierają adresy URL do plików z wynikami na poziomie poszczególnych komisji (z tej gminy). Mają one adres URL wg schematu:
http://samorzad2014.pkw.gov.pl/357_rady_woj/0/NR_TERYT_GMINY
Mając zestawienie numerów TERYT gmin pobieram indywidualne pliki za pomocą prostego skryptu:
use LWP::Simple; ## Na wejściu lista 6-cyfrowych numerów gmin while (<>) { $nn++; chomp(); $File{"$_"}++; $url = "http://samorzad2014.pkw.gov.pl/357_Sejmiki_wojewodztw/0/$_"; if ( $File{"$_"} > 1 ) { $file = "./html/$_" . "$File{$_}_" . ".html"; } else { $file = "./html/$_" . ".html"; } getstore($url, $file); print STDERR "$nn = $url => $file... stored\n"; }
Z tych plików wydłubuję numery komisji (które są wartościami atrybutu href
do pliku z protokołem i mają postać 321_protokol_komisji_obwodowej/NRKOMISJI
) i zapisuję do pliku o strukturze:
020101;321_protokol_komisji_obwodowej/NRKOMISJI
Teraz z plików komisji odczytuję adresy URL protokołów wyborów do sejmików. Ten URL wygląda następująco:
020101;321_protokol_komisji_obwodowej/NRKOMISJI/rdw_COŚTAM
Przy czym COŚTAM
to cyfra, np. rdw_5
. Problem, że ta cyfra nie zawsze jest taka sama, stąd konieczność przeczytania pliku i odszukania w nim odsyłacza do protokołu wyborów do sejmików. Na szczęście pliki HTML są w miarę proste i do odszukania tego co trzeba wystarczy proste wyrażenie regularne. Poniższy skrypt po odszukaniu odsyłacza pobiera plik protokołu i zapisuje w katalogu ./protokoly_sw/
:
#!/usr/bin/perl use LWP::Simple; my $log = "protokoly_sw.log"; open (LOG, ">$log") || die ("Nie mogę pisać do $log"); while (<>) { $nn++; chomp(); ($teryt, $postfix, $nrk) = split /[;\/]/, $_; unless ( -f "./protokoly_sw/$nrk" ) { $file = "./protokoly_sw/$nrk"; open (LOGP, "./komisje/$nrk"); while (<LOGP>) { chomp(); if (/([^\/]*protokol_komisji.*)">Sejmik/) {## URL do protokołu $prot_url = $1; print "$1\n"; last } } close (LOGP); $url = "http://samorzad2014.pkw.gov.pl/$prot_url"; getstore($url, $file); print LOG "$nn = $url => $file stored\n"; print STDERR "*** $nn = $url => $file stored\n"; } else { print STDERR "*** $url => $file stored already\n"; } }
Teraz analizuję pobrane protokoły zapisując informacje do trzech plików .csv
: ws2014_komisje.csv
ws2014_listy.csv
oraz ws2014_kandydaci.csv
. Pierwszy zawiera informacje zbiorcze takie jak liczba uprawnionych czy liczba głosów ważnych dla każdej komisji, drugi informacje zbiorcze o liczbie głosów oddanych na każdą listę wyborczą w każdej komisji a trzeci o liczbie głosów oddanych na każdego kandydata w każdej komisji. W związu z tym:
wc -l ws2014_*csv 3062457 ws2014_kandydaci.csv 301876 ws2014_listy.csv 27393 ws2014_komisje.csv
Tj. ws2014_komisje.csv
ma 27393 wierszy (i tyle jest komisji); ws2014_listy.csv
ma 301876, a ws2014_kandydaci.csv
ponad 3mln wierszy (wynik kandydata w każdej komisji, w której był zarejestrowany). Skrypt (nieco uproszczony) wydłubujący potrzebne informacje z pliku protokołu wygląda następująco:
#!/usr/bin/perl open (LOG, ">>ws2014_log.log"); open (L, ">>ws2014_listy.csv"); open (K, ">>ws2014_kandydaci.csv"); open (X, ">>ws2014_komisje.csv"); $fileName = $ARGV[0]; $fileName =~ s/(\/[^\/]+)$/$1/; while(<>) { chomp(); if (/<h2>/) { $mode = 'I'; while (<>) { chomp(); if (/<div>Kod terytorialny/) { $Teryt = next_line(); } if (/<div>Numer obwodu/) { $IdO = next_line(); } if (/<div>Adres/) { $Addr = next_line(); $IdDataFull = "$fileName;$Teryt;$IdO;$Addr"; $IdData = "$fileName;$Teryt;$IdO"; last; } } } if ($mode eq 'I') { } if (/Wyniki wyborów na Kandydatów/) { $mode = 'C' } if (/ZESTAWIENIE WYNIKÓW/) { $mode = 'S'; while (<>) { chomp(); ## pobieranie informacji nt. komisji ## pominięto kilkanaście wierszy postaci: ## if (/<div>###/) { $xxx = next_line() } ## ... if (/<div>Liczba kart ważnych/) { $N_karty_wazne = next_line(); } if (/<div>Liczba głosów ważnych oddanych/) { $N_glosy_wazne = next_line() ; print X "$IdDataFull;$N_uprawnieni;$N_karty_otrzymane;$N_karty_niewykorzystane;" . "$N_karty_wydane;$N_pelnomocnicy;$N_pakiety;$N_karty_wyjete;$karty_z_kopert;" . "$N_karty_niewazne;$N_karty_wazne;$N_glosy_wazne;$N_glosy_niewazne\n"; last; } } ########## if (/Wyniki wyborów na listy/) { $mode = 'L' ; $colNo=0; %List = (); $start = 0; while (<>) { chomp(); if (/<tbody>/) {$start = 1} if ($start == 1 ) { if (/<td[^<>]*>/ ) { $colNo++; $List{$colNo} = clean($_); } if (/<tr>/) { $colNo=0; %List = (); } if (/<\/tr>/) { $line_ = "$IdData;"; for $x (sort keys %List ) { $line_ .= "$List{$x};" } print L "$line_\n"; } if (/<\/tbody>/ ) {### last; } ##// } } } ########### if ($mode eq 'C' && /<tr>/) { $colNo=0; %Candidate = (); while (<>) { chomp(); if (/<table>/) { next } ## skip this line if (/<\/tr>/ ) { $line_ = "$IdData;"; for $x (sort keys %Candidate ) { $line_ .= "$Candidate{$x};" } print K "$line_\n"; last; } ## //end if (/<td[^<>]*>/ ) { ############# $colNo++; $Candidate{$colNo} = clean($_); } } } } ### ### ### sub clean { my $x = shift; $x =~ s/<[^<>]+>//g; $x =~ s/^[\t ]+|[\t ]+$//g; $x =~ s/"//g; return ($x) } sub next_line { while (<>) { chomp(); return (clean ($_)); } } close(L); close(K); close(X); print LOG "$fileName...\n"; close (LOG);
Kilka minut i po bólu. Teraz sprawdzam czy to co się pobrało i to co było do tej pory z grubsza się zgadza.
#!/usr/bin/perl $pobranie1="komisje-frekwencja-ws2014.csv"; ## z 2015r $pobranie2="ws2014_komisje.csv"; open(WX, $pobranie1) || die "cannot open $pobranie1\n"; while (<WX>) { chomp(); ($teryt, $nrk, $nro, $adres, $lwug, $lkw, $lkwzu, $lgnw, $lgw, $freq, $pgnw) = split /;/, $_; $LWUG1{"$teryt:$nro"} = $lwug; ## liczba wyborców $LGW1{"$teryt:$nro"} = $lgw; ## glosy ważne $ADDR1{"$teryt:$nro"} = $adres; ## } close (WX); ### ### ### open(WY, $pobranie2) || die "cannot open $pobranie2\n"; while (<WY>) { chomp(); ($id, $teryt, $idk, $adres, $uprawnieni, $kartyOtrzymane, $kartyNiewydane, $kartyWydane, $pelnomocnicy, $pakiety, $kartyWyjete, $koperty, $kartyNiewazne, $kartyWazne, $glosy, $glosyNiewazne) = split /;/, $_; $LWUG2{"$teryt:$idk"} = $uprawnieni; $LGW2{"$teryt:$idk"} = $glosy; $ADDR2{"$teryt:$idk"} = $adres; } close (WY); ### LWUG1 ma mniej głosów ## ### ### ### ### for $ik ( sort keys %LWUG1 ) { if ( ( $LWUG1{$ik} != $LWUG2{$ik} ) || ($LGW1{$ik} != $LGW2{$ik} )) { print "$ik $LWUG1{$ik} = $LWUG2{$ik} $LGW1{$ik} = $LGW2{$ik}\n"; } }
Identyfikatorem komisji na stronach PKW jest 6-cyfrowy numer TERYT + numer komisji (w gminie). Porównanie 26477 komisji pobranych 2015r. z 27446 komisjami pobranymi teraz (+969 komisji) daje w rezultacie:
021901:1 2020 = 2020 914 = 913 021901:2 2189 = 2189 742 = 741 026401:112 2039 = 2039 746 = 744 026401:17 2001 = 2001 536 = 534 026401:178 2073 = 2073 765 = 762 026401:18 1600 = 1600 474 = 473 026401:194 1615 = 1615 637 = 628 026401:215 1457 = 1457 528 = 527 026401:245 2058 = 2058 695 = 697 026401:42 1892 = 1892 504 = 503 026401:70 1823 = 1823 597 = 593 026401:78 1918 = 1918 762 = 760 241004:4 994 = 850 350 = 350 241005:13 1736 = 1736 764 = 762 241005:22 1422 = 1422 569 = 567 241005:6 1441 = 1441 732 = 723 241005:7 1668 = 1668 623 = 621
Czyli dane nie były picowane :-) Dobrze wiedzieć
Pobrane dane są tutaj.
Brak komentarzy:
Prześlij komentarz