Marian Buchta - Vyhľadávanie informácií z obrázkov WEB stránky

    Table of contents
    No headers

    Úvod

    Obrázky patria k web stránkam od nepamäti. Robia ich pestrejšími, zaujímavejšími a príťažlivejšími pre návštevníka. Vo svete digitálnych fotografií sa človek túži podeliť so svojimi fotografiami rodine, priateľmi alebo ich jednoducho ukázať ostatným. Jedným z riešení sú špecializované web stránky, ktoré okrem samotného uloženia fotografií poskytujú užívateľovi veľké množstvo doplňujúcich informácií. Medzi spomínané špecializované web stránky patria:

     

    Niektoré obrázky obsahujú popisy alebo komentáre, ktoré sa nachádzajú v ich okolí alebo pre lepšiu čitateľnosť sú umiestnené do navonok neviditeľného tzv. ALT tagu.

    Pri väčšom množstve obrázkov sa stávajú webové stránky neprehľadné. Preto by bolo vhodné zozbierať všetky údaje a umiestniť ich v kompaktnej a prehľadnej forme na jedno miesto.

     

    Projekt

     

    Cieľom projektu je extrakcia doplňujúcich informácií z obrázkov web stránok. Primárne sa zameriame na stránku http://picasaweb.google.com , z ktorej sa pokúsime získať všetky informácie týkajúce sa samotných albumov. Extrakcia informácií sa bude vykonávať pomocou regulárnych výrazov, ktoré nájdu nasledovné údaje:

    • vlastník albumu
    • názov albumu
    • počet fotiek v albume
    • dátum poslednej aktualizácie albumu

     

    Na iných stránkach sa zameriame hlavne na hľadanie obrázkov, ktoré môžu ale nemusia byť doplnené tagom ALT.

    Program bude implementovaný v jazyku C#  s použitím regulárnych výrazov, ktoré sa nachádzajú v "namespace" System.Text.RegularExpressions.

    Na indexovanie a hľadanie údajov použijeme knižnicu Lucene.NET verzie 2.0.

     

    Analýza a návrh

    Rád by som uviedol poznámku na úvod. Po odovzdaní práce sa zmenila štruktúra zdrojových kódov pre webovú stránku Google Picasa. Preto bude analýza a návrh pre tento problém opísaná starým a novým spôsobom.

    V prvej časti analýzy sa budeme venovať problematike webovej stránke Google Picasa. Druhá časť sa bude zaoberať všeobecným vyhľadávaním obrázkov spolu s ich popismi. Ukážeme si, ktoré informácie a akým spôsobom vyberieme.

    Google Picasa (staršia verzia zdrojových kódov)

    Postup extrakcie informácií z Google Picasa je nasledovný:

    1. Vstupom pre program bude URL odkaz (alebo uložený zdrojový súbor html stránky vlastníka Picasa konta, napr. http://picasaweb.google.com/stanka.leitmanova). Vstupný formát URL adresy môže mať 2 formáty:
    1. Pomocou regulárneho výrazu zistíme, či je web stránka validná alebo nie.
      @"^((ht|f)tp(s?)\:\/\/|~/|/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)?";
    2. Ak je validná, extrahujeme z nej vlastníka albumu.
    3. Hľadáme informácie: názov albumu, počet fotiek a dátum poslednej úpravy albumu.
    4. Vypíšeme výsledok.

     

    Detailnejšiu analýzu problematiky si ukážeme na príklade albumov používateľa stanka.leitmanova (http://picasaweb.google.com/stanka.leitmanova ).

     

    Vlastník a názov albumu

    Oba údaje získame z odkazu, ktorý sa nachádza v zdrojových kódoch. Prvý údaj "vlastík albumu" sa nachádza priamo za lomítkom názvu domény a "názov albumu" sa nachádza za vlastníkom albumu.

    <a href="http://picasaweb.google.com/stanka.leitmanova/PragueBotanicGardenAugust2008" id="title_5232885563019266929">

     

    Problém: Na prvý pohľad by nám stačilo uviesť predchádzajúci odkaz bez parametra id. Ak by sme to tak urobili a vyhľadávali názvy albumov, dospeli by sme k nájdeniu albumu na viacerých miestach.

     

    Regulárny výraz:

    "<a href=\"http://picasaweb.google.com/" + "(?<userName>[^//]*)" + "/(?<album>[^\"]*)\"" + " id"

     

    Popis:

    Do premennej userName sa uloží podreťazec, ktorého začiatok sa nachádza za názvom domény, tzn. reťazcom http://picasaweb.google.com/ a koniec pred nasledujúcim "/" znakom. V našom prípade sa do premennej userName vloží podreťazec "stanka.leitmanova".

    Do premennej Album sa nám uloží požadovaný názov albumu. Podreťazec sa začína za menom vlastníka albumu a končí pri prvom výskyte znaku " " "(dvojité uvodzovky). Na záver nám stačí zadať podreťazec "id", ktorý nám vyrieši spomínaný problém s opakovaným nájdením albumu. V našom prípade sa premenná Album naplní reťazcom "PragueBotanicGardenAugust2008".

     

    Počet fotiek v albume

    Počet fotiek albumu môžeme nájsť za názvom albumu  v nasledujúcej forme:

    <span class="lhcl_info"> (45)</span>
    

    Tento reťazec sa nachádza v html kóde iba za názvom albumu. Z toho vyplýva, že poradie nájdenia názvu albumu je totožné s poradím nájdenia počtu fotiek v albume.

     

    Regulárny výraz:

    "<span class=\"lhcl_info\"> " + "\\(" + "(?<pocetFotiek>[0-9]*)" + "\\)"
    

     

    Popis:

    Z príkladu a regulárneho výrazu je zrejmé, že do premennej pocetFotiek sa uloží počet fotiek albumu. Minimálny hodnota počtu fotiek je 0 a maximálny 500 pre bežných užívateľov a 1000 pre platených. V našom prípade je ich 45.

     

    Dátum poslednej aktualizácie albumu

    Podobným spôsobom ako v predchádzajúcom odseku, aj v tomto prípade je dátum poslednej zmeny v blízkosti názvu albumu, presnejšie pod tagmi počtu fotiek v albume.

    <script>_pd(7,8,2008);</script>
    

     

    Regulárny výraz:

    @"_pd" + "\\(" + "(?<den>[0-9]{1,2})" + "," + "(?<mesiac>[0-9]{1,2})" + "," + "(?<rok>[0-9]{4})" + "\\)"

     

    Popis:

    Regulárny výraz je o niečo komplikovanejší ako v predchádzajúcich prípadoch. Premenné den a mesiac môžu byť iba jedno alebo dvojciferné a premenná rok môže mať iba štvorciferné číslo. Regulárny výraz končí ľavou zátvorkou, pretože zvyšok reťazca už nemusíme hľadať.

     

    Google Picasa (novšia verzia zdrojových kódov)

    Postup extrakcie informácií z Google Picasa je nasledovný:

    1. Vstupom pre program bude URL odkaz (alebo uložený zdrojový súbor html stránky vlastníka Picasa konta, napr. http://picasaweb.google.com/stanka.leitmanova). Vstupný formát URL adresy môže mať 2 formáty:
    1. Pomocou regulárneho výrazu zistíme, či je web stránka validná alebo nie.
      @"^((ht|f)tp(s?)\:\/\/|~/|/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)?";
    2. Ak je validná, zo zdrojových kódov vyextrahujeme vlastníka albumu.
    3. Hľadáme informácie: názov albumu, počet fotiek a dátum poslednej úpravy albumu.
    4. Vypíšeme výsledok.

     

    Detailnejšiu analýzu problematiky si ukážeme na príklade albumov používateľa stanka.leitmanova (http://picasaweb.google.com/stanka.leitmanova ).

     

    Vlastník albumu

    Vlastníka albumu získame z odkazu, ktorý slúži ako RSS.

    href="http://picasaweb.google.com/data/feed/base/user/stanka.leitmanova?alt=rss&kind=album&hl=en_US&access=public"

     

    Problém: Samotného vlastníka môžeme vyextrahovať aj priamo z vloženej URL adresy. Pokiaľ budú dáta načítané zo súboru, tento spôsob bude nepoužiteľný. V zdrojových kódoch sa nachádza RSS odkaz, ktorý je určený k rýchlemu čítaniu noviniek na webových stránkach. Vlastník albumu sa nachádza od miesta posledného lomítka po otáznik. Podreťazec href="http://picasaweb.google.com/data/fee...nka.leitmanova sa v zdrojových kódoch nachádza 2x, preto použijeme prvý nájdený.

     

    Regulárny výraz:

    "href=\"http://picasaweb.google.com/data/feed/base/user/" + "(?<userName>[^\\?]*)"

     

    Albumy

    Albumy sa v novšej štruktúre Google Picasa nachádzajú na jednom mieste. Preto bude vhodné extrakciu rozdeliť do dvoch častí:

    1. extrakcia všetkých albumov
    2. extrakcia jednotlivých údajov z albumov

     

    Extrakcia všetkých albumov

    Všetky albumy sú ohraničené hlavnými hranatými zátvorkami ako je uvedené nasledovne:

    _user.albums =
    [
    {
    ...
    }
    {
    ...
    }
    ]
    

     

    Popis:

    Navrhneme jednoduchý regulárny výraz, ktorý nám uloží podreťazec, ktorý sa nachádza medzi prvou a poslednou hranatou zátvorkou.

    Regulárny výraz:

    "_user.albums" + "(?<userAlbums>[^\\]]*)\\]"
    

     

     Extrakcia údajov z albumu

     Uvedieme príklad jedného albumu:

    {
    id:'5232879863666674305'
    ,access:'public'
    ,title:'some photos'
    ,url:'http:\x2F\x2Fpicasaweb.google.com\x2Fstanka.leitmanova\x2FSomePhotos'
    ,src:'http:\x2F\x2Flh5.ggpht.com\x2F_93MtlyS5ygI\x2FSJ7sgtIlioE\x2FAAAAAAAAA8E\x2FiMYxPuYXFTo\x2Fs144-c\x2FSomePhotos.jpg'
    ,count:39
    ,date:'10,8,2008'
    ,upload_secs:1218374786000},

     Každý album obsahuje vždy všetky uvedené údaje. Pre nás budú zaujímavé nasledovné údaje, ku ktorým navrhneme regulárne výrazy:

    • id - identifikačné číslo albumu
    "id:\'" + "(?<albumID>[^\']*)" + "\'[^,]"
    

     

    • access - typ prístupu do albumu
    "access:\'" + "(?<albumAccess>[^\']*)" + "\'[^,]"
    

     

    • title - názov albumu
    "title:\'" + "(?<albumTittle>[^\']*)" + "\'[^,]"
    

     

    • cout - počet fotiek
    "count:" + "(?<photoCount>[0-9]*)"
    

    Popis:

    Z príkladu a regulárneho výrazu je zrejmé, že do premennej pocetFotiek sa uloží počet fotiek albumu. Minimálny hodnota počtu fotiek je 0 a maximálny 500 pre bežných užívateľov a 1000 pre platených. V našom prípade je ich 45.

     

    • date - dátum poslednej zmeny
    "date:\'" + "(?<day>[0-9]{1,2})" + "," + "(?<month>[0-9]{1,2})" + "," + "(?<year>[0-9]{4})" + "\'"
    

    Popis:

    Regulárny výraz je o niečo komplikovanejší ako v predchádzajúcich prípadoch. Premenné day a month môžu byť iba jedno alebo dvojciferné a premenná year môže mať iba štvorciferné číslo. Regulárny výraz končí ľavou zátvorkou, pretože zvyšok reťazca už nemusíme hľadať.

     

    Výsledok:

    Výsledok pre oba spôsoby verzie zdrojových kódov sú rovnaké. Na obrázku obr.1 vidíme výsledok extrakcie informácií. Pre porovnanie uvádzame na obrázku obr.2 aj časť originálnej webovej stránky.

     

     stanka (2).JPG

    Obr.1: Výsledok extrakcie informácií

     

    stanka-web.JPG

    Obr.2: Náhľad web stránky Google Picasa vlastníka stanka.leitmanova

     

     Ostatné webové stránky

    Druhej časti dokumentácie sa venujeme webovým stránkam, na ktorých chceme vyhľadať informácie o obrázkoch. Aj v tomto prípade bude analýza a návrh prebiehať na príklade webovej stránky File:C:/DOCUME~1/Dupi/LOCALS~1/Temp/moz-screenshot.jpghttp://www.stargate.scifi-guide.net/ .Z webovej stránky budeme hľadať z obrázkov nasledovné informácie:

    • meno obrázku
    • alt tag obrázka

    Pri zdanlivo jednoduchých údajov sme sa stretli s najväčším počtom problémov pri tvorbe celého projektu.

    Postup pri hľadaní informácií

    Každý obrázok je na webstránke uložený pod html tagom img. Zo skúsenosti a testovania počas tvorby regulárnych výrazov sme sa rozhodli, že vyhľadávanie bude dvojúrovňové. V prvom stupni sa zameriame na vyhľadanie tagu img. V druhom stupni sa zameriame na hľadanie "src" a "alt" atribútov. Riešenie si uvedieme na nasledujúcom príklade:

    <img src="http://www.google.com/logos/Logo_25blk.gif" border="0" alt="Google" align="middle"></img>
    

     

    Pri prvom stupni hľadania hľadáme img tag. Nasledujúci regulárny výraz nám to umožňuje:

    "<img[^>]+>"
    

     

    Popis:

    Regulárny výraz vyhľadáva všetky výrazy, ktoré začínajú podreťazcom "<img" a končia ">". Medzi nimi sa môže vyskytovať akýkoľvek znak rôzny od ukončovacieho znaku ">".

     Pri druhom stupni hľadania sa zameriavane na hľadanie tagov "src" a "alt". Pri tvorbe regulárneho výrazu sme narazili na niekoľko problémov:

    1. Hodnoty tagov môžu byť uložené troma rôznymi spôsobmi:
    1. Tagy "src" a "alt" môžu byť vo vnútri tagu na rôznych miestach, napr. "alt" tag je skôr zadefinovaný ako "src" tag
    2. "alt" tag môže byť zadefinovaný, ale jeho hodnota je prázdna, napr. alt=""
    3. "img" tag nemusí obsahovať "alt" tag, ale "src" tag áno.

    Pri dlhšom hľadaní a testovaní sme dospeli k tvorbe nasledujúceho regulárneho výrazu:

    "(?<type>(src|alt)=\"(?<value>[^\"]*)?\")|(?<type>(src|alt)='(?<value>[^']*)?')|(?<type>(src|alt)=(?<value>[^ ]*)?)"
    

     

    Popis:

    Výraz je tvorený z množiny troch alternatívnych reťazcov, ktoré sa môžu objaviť v zdrojovom kóde web stránky. Týmto sme vyriešili problém číslo 1. Do premennej type sa uloží typ tagu ("src" alebo "alt") a do premennej "value" jeho hodnota. Hodnota môže obsahovať akýkoľvek reťazec, ktorý neobsahuje ukončovací znak (dvojitú, jednoduchú úvodzovku alebo medzeru), pričom môže obsahovať aj prázdny reťazec. Týmto sme vyriešili problémy 2,3 a 4.

    Medzi ďalšie problémy patrí výskyt viacnásobne sa opakujúcich obrázkov. Ten sme vyriešili výpisom jedného obrázku. Každý opakujúci sa obrázok bol pripočítaní do štatistiky (viď obr. 3). Rovnosť obrázkov sme porovnávali na základe relatívnej, resp. absolútnej zdrojovej cesty. Za rovnosť nepovažuje rovnaký názov obrázka na rôznych miestach, pretože sa môže jednať o iný obrázok.

    Za korektný obrázok považujeme obrázok, ktorý sa skladá z názvu, bodky a koncovky. Každý iný obrázok bude považovaný za chybný, resp. nekorektný. Príklad:

    <IMG SRC="http://toplist.cz/count.asp?id=58602&amp;logo=mc&amp;start=19936" BORDER="0" ALT="TOPlist" WIDTH="88" HEIGHT="60"/>
    

     

    Na obrázku obr.3 vidíme časť výpisu obrázkov zo spomínanej stránky http://www.stargate.scifi-guide.net/ . Celkový počet nájdených obrázkov sa rovná súčtu zobrazených, opakujúcich sa a chybných resp. nekorektných obrázkov. Každý obrázok obsahuje:

    • Typ obrázka, resp. jeho koncovku
    • Názov obrázka
    • Cesta k obrázku
    • Doplňujúca informácia

     

    stargate (1).JPG

    Obr.3 - Ukážka výpisu z webovej stránky


    Lucene.NET

    Nájdené údaje je potrebné indexovať. Využijeme preto port java knižnice Lucene, Lucene.NET verzie 2.0 pre prostredie .NET.

    Najprv musíme navrhnúť políčka (fields), ktoré chceme indexovať pre oba prípady obrázkov:

    • Google Picasa:
      • url - úplná url adresa vlastníka
      • userName - meno vlastníka
      • id - identifikačné číslo albumu
      • access - prístup do albumu
      • title - názov albumu
      • count - počet fotiek
      • date - dátum poslednej zmeny

     

          doc.Add(new Field("url", url, Field.Store.YES, Field.Index.UN_TOKENIZED));
          doc.Add(new Field("userName",userName, Field.Store.YES, Field.Index.TOKENIZED));
          doc.Add(new Field("id", id, Field.Store.YES, Field.Index.TOKENIZED));
          doc.Add(new Field("access", access, Field.Store.YES, Field.Index.TOKENIZED));
          doc.Add(new Field("title", title, Field.Store.YES, Field.Index.TOKENIZED));
          doc.Add(new Field("count", count, Field.Store.YES, Field.Index.TOKENIZED));
          doc.Add(new Field("date", date, Field.Store.YES, Field.Index.UN_TOKENIZED));
    
    • Ostatné stránky
      • url - úplná url adresa
      • type - typ obrázka (jpg, gif apod.)
      • picture - názov obrázka
      • path - úplná cesta k obrázku
      • alt - tag obrázka (popis)
         doc.Add(new Field("url",url, Field.Store.YES, Field.Index.UN_TOKENIZED));
         doc.Add(new Field("type", type, Field.Store.YES, Field.Index.TOKENIZED));
         doc.Add(new Field("picture", picture, Field.Store.YES, Field.Index.TOKENIZED));
         doc.Add(new Field("path", path, Field.Store.YES, Field.Index.TOKENIZED));
         doc.Add(new Field("alt", alt, Field.Store.YES, Field.Index.TOKENIZED));

     

    Pred samotným indexovaním sme museli kontrolovať, či sme už danú url adresu indexovali a tak zabránili viacnásobnému indexovaniu.

    Pri tvorbe vyhľadávania sme narazili na problém. Ako prehľadávať jeden reťazec cez všetky zadefinované polia? Najprv sme si zadefinovali všetky polia, ktoré chceme prechádzať.

    String[] picasaFields = { "url", "userName", "id", "access", "title", "count", "date"};
    String[] othersFields = { "url", "type", "picture","path", "alt"};
    

    Potom vytvorili pre oba typy obrázkov tzv. MultiFieldQueryParsera.

    Query multiQueryPicasa = new MultiFieldQueryParser(picasaFields, new StandardAnalyzer()).Parse(queryString);
    Query multiQueryOthers = new MultiFieldQueryParser(othersFields, new StandardAnalyzer()).Parse(queryString);
    

    Nájdeme výsledky:

    IndexSearcher s = new IndexSearcher(directory);
    Hits hitsPicasa = s.Search(multiQueryPicasa);
    Hits hitsOthers = s.Search(multiQueryOthers);
    

    A vypíšeme (reťazec hľadáme v oboch "dokumentoch"):

    for (int i = 0; i < hitsPicasa.Length(); ++i)
    {
        sb.Append((i + 1) + ". " + Environment.NewLine);
        sb.Append("Vlastnik: " + hitsPicasa.Doc(i).Get("userName") + Environment.NewLine);
        sb.Append("ID: " + hitsPicasa.Doc(i).Get("id") + Environment.NewLine);
        sb.Append("Pristup: " + hitsPicasa.Doc(i).Get("access") + Environment.NewLine);
        sb.Append("Album: " + hitsPicasa.Doc(i).Get("title") + Environment.NewLine);
        sb.Append("Pocet fotiek: " + hitsPicasa.Doc(i).Get("count") + Environment.NewLine);
        sb.Append("Datum poslednej upravy [D.M.R]: " + hitsPicasa.Doc(i).Get("date") + Environment.NewLine + Environment.NewLine);
    }
    for (int i = 0; i < hitsOthers.Length(); ++i)
    {
        sb.Append((i + 1) + ". " + Environment.NewLine);
        sb.Append("URL: " + hitsOthers.Doc(i).Get("url") + Environment.NewLine);
        sb.Append("Typ: " + hitsOthers.Doc(i).Get("type") + Environment.NewLine);
        sb.Append("Obrazok: " + hitsOthers.Doc(i).Get("picture") + Environment.NewLine);
        sb.Append("Cesta k obr: " + hitsOthers.Doc(i).Get("path") + Environment.NewLine);
        sb.Append("Alt: " + hitsOthers.Doc(i).Get("alt") + Environment.NewLine + Environment.NewLine);
    }
    

     

    Použitie programu

     Po spustení programu musíme zadefinovať, ktorý spôsob indexovania použijeme:

    • RAM - indexovanie do RAM pamäte
    • HDD - indexovanie na harddisk

     Po výbere sa nám odblokujú tlačidla "OK" a "Browse". Vloženie údajov sa uskutočňuje dvoma spôsobmi:

    1. vloženie URL adresy
    2. načítanie uložených dát s koncovkou urldata. Súbory obsahujú zdrojový kód stránky.

    Do hlavného okna sa nám vypíše výsledok hľadania a zároveň odblokuje okienko pre zadávanie hľadaných reťazcov a zablokuje výber spôsobu indexovania. Opätovný výber spôsobu indexovania je možný len po stlačení tlačidla "Reset". Po zadaní hľadaného reťazca sa nám vypíšu všetky "dokumenty", ktoré ho obsahujú. Príklad si ukážeme na stránke http://www.stargate.scifi-guide.net/ . Výsledok je zobrazený na obrázku Obr.4.

     

    stargate-find.jpg 

    Obr.4 - Ukážka výpisu hľadania reťazca "jpg"

    Pôvodný výsledok obsahuje 37 relevantných údajov (obrázkov). Hľadáme reťazec "jpg". Program nám našiel 24 záznamov, ktoré sa zobrazia.

     Záver

    Počas testovania regulárnych výrazov na stránkach Google Picasa sme dosiahli 100% úspešnosť pri najväčšom nájdenom množstve 151 albumov na vlastníka (http://picasaweb.google.com/EMBLETON66?showall=true#100). V druhej časti projektu sme úspešne vytvorili regulárne výrazy na vyhľadávanie informácií z obrázkov. Spolu so štatistikou sa vypíšu do programu. Na testovaných webových stránkach sme dosiahli 100% úspešnosť rozpoznania všetkých potrebných informácií. Na indexovanie a hľadanie údajov sme použili knižnicu Lucene.NET pre prostredie .NET. Na tvorbu regulárnych výrazov sme použili program RegexBuddy [1].

    Literatúra

    [1] http://www.regexbuddy.com/

    http://www.csharp-station.com/HowTo/HttpWebFetch.aspx

    http://www.cambiaresearch.com/c4/890160aa-bc4e-40fc-ac36-c1031858c048/Parsing-URLs-with-Regular-Expressions-and-the-Regex-Object.aspx

    http://geekswithblogs.net/casualjim/archive/2005/12/01/61722.aspx

    http://www.lucenetutorial.com/

    http://darksleep.com/lucene/

    http://incubator.apache.org/lucene.net/docs/2.1/

    Tag page (Edit tags)
    • No tags
    Viewing 2 of 2 comments: view all
    I took 1 st <a href="http://goodfinance-blog.com/topics/credit-loans">credit loans</a> when I was a teenager and it supported my family very much. However, I need the student loan once more time.
    Posted 06:32, 12 Dec 2011
    I opine that to get the personal loans from creditors you ought to have a firm motivation. But, one time I have received a credit loan, just because I wanted to buy a building.
    Posted 08:25, 12 Dec 2011
    Viewing 2 of 2 comments: view all
    You must login to post a comment.
    Powered by MindTouch Core