Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Tommy 23. 08. 2015, 10:37:23

Název: Parsing tabulky
Přispěvatel: Tommy 23. 08. 2015, 10:37:23
Zdravím

Pokouším se napsat parsing tabulky do txt resp. csv souboru. Adresa URL je zadávána v BASH a celkem je těch parsovaných stránek hodně. Příklad :
http://en.tutiempo.net/climate/07-2015/ws-115200.html ?? - 11520.txt tak aby zůstala jen tabulka a ve sloupcích výskytu jedničky a nuly.

Jedno řešení jsem vymyslel:
XXX=`wget -qO - "http://en.tutiempo.net/climate/${m}-${y}/${ID}.html" | gawk '/&nbsp;<\/td><td>&nbsp;/' | sed  "s;</tr>;\n;g" | sed "s/&nbsp;//g" | sed "s/<strong>//g" | sed "s/<\/strong>//g" | sed "s/<tr><td>//g" | sed "s/<\/td><td>/\t/g" | sed "s/<\/td>//g" | grep -A100 "Indicates whether there was fog" | grep -B100 "Medias y totales mensuales" | head -n-1 | tail -n+2 | sed 's;o\+;1;g' | sed "s;\(^[0-9]*\);\1.${mu}.${y};" | sed "s/\t\t/\t0\t/g" | sed "s/\t\t/\t0\t/g" | sed "s/\t\t/\t0\t/g" | sed "s/\t\t/\t0\t/g" | sed "s/\t\n/\t0\n/g"  | tr -s "\n" "@" | sed "s/\t@/\t0@/g" | tr -s "@" "\n" | tr "\n" "@" | tr "\t" "&"`
if [ "${XXX}" ]
then
LEN=`expr length "${XXX}"`
if [ "${LEN}" -ge "${LENmin}" ] ;
then
echo "${XXX}" | tr -s "@" "\n" | tr "&" "\t" >> ${W}TUTIEMPO/Tutiempo_ALL/${CONTINENT}/${Countries}/${Station}_${IDA}.txt
echo "${XXX}" | tr -s "@" "\n" | tr "&" ";" >> ${W}TUTIEMPO/Tutiempo_ALL_CSV/${CONTINENT}/${Countries}/${Station}_${IDA}.csv
echo "${XXX}" | tr -s "@" "\n" | tr "&" "\t" >> ${W}TUTIEMPO/Tutiempo_ALL_By_Years/${CONTINENT}/${Countries}/${Station}_${IDA}/${Station}_${IDA}_${y}.txt
echo "${XXX}" | tr -s "@" "\n" | tr "&" ";" >> ${W}TUTIEMPO/Tutiempo_ALL_By_Years_CSV/${CONTINENT}/${Countries}/${Station}_${IDA}/${Station}_${IDA}_${y}.csv
echo "${CONTINENT};${Countries};${Station};${IDA};${y};${m};${XXX};" | sed "s/@/"@${CONTINENT}\;${Countries}\;${Station}\;${IDA}\;${y}\;${m}\;"/g" | tr -s "@" "\n" | tr -s "&" "\t" | tr -s ";" "\t" | grep "[0-9]\.[0-9]" >> ${W}TUTIEMPO/Tutiempo_ALL_By_Years_Solid/Tutiempo_ALL_By_Years_Solid.txt
echo "${CONTINENT};${Countries};${Station};${IDA};${y};${m};${XXX};" | sed "s/@/"@${CONTINENT}\;${Countries}\;${Station}\;${IDA}\;${y}\;${m}\;"/g" | tr -s "@" "\n" | tr -s "&" "\t" | tr -s "\t" ";" | grep "[0-9]\.[0-9]" >> ${W}TUTIEMPO/Tutiempo_ALL_By_Years_Solid/Tutiempo_ALL_By_Years_Solid.csv
fi
fi


Jenže zpracování proměnné XXX potřebje spustit hodně procesů, což není yrovna ideální. U pár stránek by to bylo jedno, ale při velkém počtu se to dost projeví na rychlosti. V awk se nevyznám.

Díky za nápad
Název: Re:Parsing tabulky
Přispěvatel: Kit 23. 08. 2015, 11:26:18
Parsovat HTML ručně mi připadá jako pokus o sebevraždu. Zkusil bych se raději odpíchnout od tohoto kousku kódu:
Kód: [Vybrat]
xmllint --html --xpath '//*[@class="medias mensuales"]/tr' ws-115200.htmlNení to celé, ale snad to pomůže. Teď po ránu mě nic lepšího nenapadá.
Název: Re:Parsing tabulky
Přispěvatel: wamba 23. 08. 2015, 14:42:52
imho bude lepší to přepsat celé, nebo velkou část do nějakého skriptovacího jazyka (Perl, Python, Awk, ...), např.
Kód: [Vybrat]
use 5.010;
use strict;
use warnings;
#use lib '/home/wamba/perl5/lib/perl5/';

use HTML::TreeBuilder;
use Text::CSV;

my $html      = HTML::TreeBuilder->new_from_url(shift);
my $table     = $html->find('table');
my @tablerows = $table->find('tr');

my $csv = Text::CSV->new( { binary => 1, eol => qq{$/} } );

foreach my $tr (@tablerows) {
    my @arr = map { $_->as_text } $tr->find( 'th', 'td' );
    $csv->print( *STDOUT, \@arr );
}
tento Perl skript převede první tabulku z HTML do CSV,
parametr je URL stránky, výsledné CSV vytiskne na standardní výstup
perl html_table_to_csv.pl http://en.tutiempo.net/climate/ws-115200.html
Název: Re:Parsing tabulky
Přispěvatel: Kit 23. 08. 2015, 15:51:47
Tohle mi vyplivne CSV:
Kód: [Vybrat]
xmllint --html --xmlout --xpath '//*[@class="medias mensuales"]' ws-115200.html 2>/dev/null |
    xsltproc climate.xsl -

a tohle je výstupní šablona climate.xsl:
Kód: [Vybrat]
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="text" encoding="UTF-8"/>

<xsl:template match="//table">
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="tr">
<xsl:apply-templates/>
<xsl:text>
</xsl:text>
</xsl:template>

<xsl:template match="td">
<xsl:apply-templates/>
<xsl:text>,</xsl:text>
</xsl:template>

<xsl:template match="strong">
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="*"/>
</xsl:stylesheet>
Název: Re:Parsing tabulky
Přispěvatel: Unknown 23. 08. 2015, 21:50:03
Zkuste Xidel http://www.videlibri.de/xidel.html
Název: Re:Parsing tabulky
Přispěvatel: Unknown 23. 08. 2015, 22:06:37
Prosty extract cele tabulky z HTML:

xidel -q -e '//*[@id="ColumnaIzquierda"]/div/div[3]/table/tbody/tr
-115200.html'
Název: Re:Parsing tabulky
Přispěvatel: Unknown 23. 08. 2015, 22:08:30
Nejak se to domrvilo, tak jeste jednou:

Kód: [Vybrat]
xidel -q -e '//*[@id="ColumnaIzquierda"]/div/div[3]/table/tbody/tr[*]/ join(td)' 'http://en.tutiempo.net/climate/07-2015/ws-115200.html'
Název: Re:Parsing tabulky
Přispěvatel: Tommy 25. 08. 2015, 10:50:52
Diky moc, tahle to bude mnohem rychlejsi, nez spouset desitky procesu pro kazdou tabulku. Zatim se mi neopdarilo, jak to presne do toho skriptu implementovat.
Název: Re:Parsing tabulky
Přispěvatel: Unknown 25. 08. 2015, 13:30:21
Na windows vcetne downloadu:

Execution time: 0.368 s
Název: Re:Parsing tabulky
Přispěvatel: Kit 25. 08. 2015, 18:18:59
Na windows vcetne downloadu:
Execution time: 0.368 s

Na Ubuntu jsem měl se svým skriptem podobný výsledek a myslím si, že obojí měření bude silně zatíženo chybou. Nehledě k tomu, že určitě máme rozdílné procesory - u mne jednojádrový Celeron na 2.8 GHz.

Kód: [Vybrat]
curl -s http://en.tutiempo.net/climate/07-2015/ws-115200.html |
    xmllint --html --xmlout --xpath '//*[@class="medias mensuales"]' - 2>/dev/null |
    xsltproc climate.xsl -

Rozdělení na více procesů může být výhodné, pokud má procesor více jader. Hezky se o ně podělí.
Název: Re:Parsing tabulky
Přispěvatel: fos4 26. 08. 2015, 12:42:37
Kit: proč tam máš "enter" a nehodíš tam entitu? Aspoň můžeš zachovat formátování xsl..
<xsl:text>&#10;</xsl:text>
Název: Re:Parsing tabulky
Přispěvatel: Kit 26. 08. 2015, 15:14:08
Kit: proč tam máš "enter" a nehodíš tam entitu? Aspoň můžeš zachovat formátování xsl..
<xsl:text>&#10;</xsl:text>

Na číselné entity jsem si moc nezvykl, ale je to alternativa.
Název: Re:Parsing tabulky
Přispěvatel: Tommy 26. 08. 2015, 15:51:14
Na jednu tabulku 0,35-0,4 s by odpovídalo i s tím mým prvním skriptem, kde se spouští velké množství procesů. Co tabulka, to měsíc a rok trvá okolo 2,5-4 s. Rozsah dat je různý, většinou od 1973, obecně ale 1929-2015, tedy 87 let, což znamená 3-6 minut na jednu stanici. Vytvořit list stanic nebylo těžké, je jich něco málo přez 18 000. 18000*87 = 1 566 000 let, při 2,5-4 s na jeden rok tedy okolo 7-10 mil. s, tedy 80-110 dní celková doba procesu. Co měsíc, to dotaz, takže celkem 19 000 000 dotazů. Naštrěstí u prázdných stránek je čas nižší, celkově je tedy doba odhadnuta na 40-50 dní. Vzhledem k počtu puštěných procesů s každou stránkou je to cca 300 -600 mil. spuštěných procesů v té první navržené verzi.

Samotný download není tak dlouhý, do 0,2 s u plných stránek. Zatížení CPU 5-7 % takže vícejaderný proces nepomůže.
Název: Re:Parsing tabulky
Přispěvatel: Kit 26. 08. 2015, 16:18:11
V tom prvním skriptu bych se tedy vrtat nechtěl. Program má být robustní a čitelný. Nevím, co budeš dělat, když některá ze stanic bude mít odlišnou strukturu HTML.

Spotřeba strojového času u mého skriptu je 0.07 sekundy, ale úzkým hrdlem bude spíš komunikace se serverem a I/O režie, která v tom není započtena.

Nebylo by jednodušší požádat provozovatele těch stanic o poslání celého balíku dat, případně najít jiné rozhraní či formát než HTML? Třeba tam někde mají data úhledně zabalená do zipu...
Název: Re:Parsing tabulky
Přispěvatel: singerko 26. 08. 2015, 16:32:59
mozes pouzit nejaky prehliadac, napriklad links

links -dump ws-115200.html > ws-115200.txt

spravi to peknu tabulku s fixnou sirkou slpcov, potom uz rozparsujes iba tu tabulku. Do toho html mozes dat uz iba cast kodu obsahujucu iba html tabulku (vyparsujes nariklad cez xmlint)...
Název: Re:Parsing tabulky
Přispěvatel: Kit 26. 08. 2015, 20:45:30
mozes pouzit nejaky prehliadac, napriklad links

links -dump ws-115200.html > ws-115200.txt

spravi to peknu tabulku s fixnou sirkou slpcov, potom uz rozparsujes iba tu tabulku. Do toho html mozes dat uz iba cast kodu obsahujucu iba html tabulku (vyparsujes nariklad cez xmlint)...

To jsem chtěl původně navrhnout také, ale nenašel jsem v manuálu vstup přes STDIN. Dalo by se to však použít jako vstup pro silně ořezaný původní skript. V Sedu nejsem příliš zběhlý, určitě se následující skript dá ještě zkrátit, Jsou to jen dva procesy.

Kód: [Vybrat]
links -dump http://en.tutiempo.net/climate/07-2015/ws-115200.html |
    sed -e '1,/Day T/d' -e '/Medias/,$d' -e 's/^ *//' -e 's/ *$//' -e 's/  */,/g'
Název: Re:Parsing tabulky
Přispěvatel: Tommy 26. 08. 2015, 22:40:00
Kit

Jj, je ten program docela dost slozity, o tom zadna. Napsal jsem to tak jak umim (a vyvoj trval hodiny a hodiny). Nejvetsi problem je ve spousteni mnoha procesu na kazdou stranku. To zabrat muze okolo 0.2 s, takze v tvem pripade je zpracovani mnohem rychlejsi.

Co se tyce jineho formatu dat nez html, tak ten k dispozici neni, jinak by se slozity proces vubec resit nemusel. Stanice maji nastesti vsechny stejnou html strukturu, ale obcas (jednou za par let) se zmeni struktura celeho webu a skript je na nic razem. Mival jsem na to lepsi a rchlejsi skript co pouzival awk, ale ten uz nehraje a ja v awk neumim.

Dale zabere download stranky okolo 0.2 s v pripade, ze dany mesic na stanici existuje (pokud ne, je cas pod 100 ms). Jedna html stranka s daty ma radove 50-70 kB. To se da resit tim, pouziji web offline (webreap pomoci wget). To ale take neni zadna sranda - bezelo to 4-5 tydnu (2 tydny konvert odkazu), spotreba RAM 5-15 GiB, vice nez 5 000 000 html souboru a 200 GiB dat. Pri kompresi 7z/LZMA/ULTRA je vysledny archiv cca 1.9 GiB. Neni prakticke mit na disku 5 000 000 malych souboru, tak jesm z toho udelal iso image (velikost okolo 200 GiB, jen 1 soubor, po kompresi cca 2 GiB, ISO soubor se da pripojit na virtualni mechaniku jako virtualni DVD disk).

Zkousel jsem pustit skript na stazene html stranky, misto wget tedy cat SOUBOR a pak ty procesy Parsing. Zahadne to ale bezelo mnohem pomaleji (zpomaleni moc soubory na disku) ? Takze pouzit skript na offline html nebylo ucinne.
Název: Re:Parsing tabulky
Přispěvatel: Tommy 26. 08. 2015, 22:45:48

Spotřeba strojového času u mého skriptu je 0.07 sekundy, ale úzkým hrdlem bude spíš komunikace se serverem a I/O režie, která v tom není započtena.


I/O myslis zapis stranky na disk jako soubor ? To mam udelane prave tak ze zapisuje az txt data a stranku posle prez cat do RAM. Komunikace se serverem - pri kazde strance se posila reqest a odpoved (podle vseho ze Spanelska) chvilku trva. Datovy tok neni tak hrozny, do 2 Mbit, 2-3 Mbit v pripade plnych stranek z daty a temer nulovem case pro parsing dat a zapis na disk.
Název: Re:Parsing tabulky
Přispěvatel: Kit 26. 08. 2015, 23:18:03
Zatím nejrychlejší řešení, které se mi podařilo napsat:

Kód: [Vybrat]
links -dump ws-115200.html |
    awk 'BEGIN { OFS="," } /Day T/, /Medias/ { if ($1~/[[:digit:]]/) print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11 }'

real   0m0.087s
user   0m0.012s
sys    0m0.012s
Název: Re:Parsing tabulky
Přispěvatel: Tommy 27. 08. 2015, 16:29:28
Kit

Diky, parsing vypada ze by touto cestou sel. Ale pokud zadam ten prikaz z tvych poslednich 2 prispevku, tak to hodi nulovy pocet znaku, kdyz zadam jem tak to tu tabulku jakytak vypise.
Název: Re:Parsing tabulky
Přispěvatel: Kit 27. 08. 2015, 16:49:57
Kit

Diky, parsing vypada ze by touto cestou sel. Ale pokud zadam ten prikaz z tvych poslednich 2 prispevku, tak to hodi nulovy pocet znaku, kdyz zadam jem tak to tu tabulku jakytak vypise.

Na datech, která jsi mi poskytl, mi to funguje. Pokud do toho sypeš data v jiné struktuře, tak to fungovat nemusí, jenže jsi mi je nedodal. Nemám to tedy na čem testovat - z mého pohledu je ten skript OK. Kdybys aspoň napsal URL vstupních dat, pro které to nefunguje, zařadil bych je do testu.
Název: Re:Parsing tabulky
Přispěvatel: Tommy 27. 08. 2015, 23:28:23
Kit

Ona chyba nejspíš stejně bude u mě v tom že mam nějaký program ve starší verzi (už jen Gnuplot 4.2 vs. 4.6+ jak blbnul) nebo mi něco chybí v programech.

Data jsem poskytnul právě v podobě na webu jakožto odkaz, tedy http://en.tutiempo.net/climate/07-2015/ws-115200.html . Měsíc, rok či stanice s můžou měnit, ale html struktura by měla být konstantní (nebo prázdno, když nejsou data http://en.tutiempo.net/climate/07-1915/ws-115200.html )

HTML data pro offline tedz takz existují, http://meteotommy.twilightsparkle.cz/DATA/TUTIEMPO/TUTIEMPO_HTML_DATA.7z
popř. ISO soubor http://meteotommy.twilightsparkle.cz/DATA/TUTIEMPO/Tutiempo_Climate_HTML_Data_IMAGE.7z
ostatní sobory v tomto adresáři jsou hotová TXT resp. CSV data., dennní data pro všechny stanice zatim nedoběhli.


Kdytak mi napiš mail, muj mail je TommyAst zavinac gmail com, muzu ti poslat skript, jak to vypada. Kdyz bz te napadla nejaka ta optimalizace, dal bych to jako zakazku a domluvili mz jsme se za kolik, uz je to slozitejsi ukon.