Univerzita Karlova v Praze Matematicko-fyzikální fakulta
DIPLOMOVÁ PRÁCE
Bc. Michal Kaska Systém pro sledování a analýzu změn stránek vybraných webových serverů Katedra softwarového inženýrství Vedoucí diplomové práce: RNDr. Michal Kopecký, Ph.D. Studijní program: Informatika, Softwarové systémy
Prohlašuji, že jsem svou diplomovou práci napsal samostatně a výhradně s použitím citovaných pramenů. Souhlasím se zapůjčováním práce.
V Praze dne 7. 4. 2010
Michal Kaska
Obsah Obsah ............................................................................................................................................................. 3 1 Úvod ....................................................................................................................................................... 6 2 Analýza ................................................................................................................................................. 7 2.1 Parsování HTML stránek a získání dalších odkazů ................................................ 7 2.1.1 GNU Wget [2] .................................................................................................................... 8 2.1.2 HTTrack Website Copier [3] ....................................................................................... 8 2.1.3 Jeff Heatonův HTML parser pro C# [4] ................................................................... 9 2.2 Určení kódování HTML stránek a převedení na společné kódování před jejich porovnáním ................................................................................................................................. 9 2.2.1 Microsoft MLang API ................................................................................................... 10 2.2.2 Mozilla universal charset detection ....................................................................... 10 2.3 Rozpoznání formátu souboru ....................................................................................... 11 2.4 Porovnání textových a HTML souborů ..................................................................... 12 2.4.1 Porovnávání textů......................................................................................................... 12 2.4.2 Document Object Model (DOM) .............................................................................. 15 2.4.3 HTML->XML .................................................................................................................... 15 2.4.4 Porovnání XML............................................................................................................... 16 2.4.5 XML->DOM ...................................................................................................................... 17 2.5 Správa stažených souborů ............................................................................................. 17 2.6 Netiketa ................................................................................................................................. 18 3 Specifikace......................................................................................................................................... 19 3.1 Požadavky na jednotlivou úlohu ................................................................................. 19 3.2 Požadavky na porovnání souborů .............................................................................. 20 3.3 Naplnění požadavků vybranými stávajícími aplikacemi ................................... 21 4 Design.................................................................................................................................................. 22 4.1 Úloha (Watch) ..................................................................................................................... 23 4.2 Jednotlivé soubory (WatchFile) ................................................................................... 24 4.3 Datové úložiště ................................................................................................................... 24 4.4 Správa zásuvných modulů ............................................................................................. 24 4.5 Plugin pro zpracování HTML souborů ...................................................................... 25 4.5.1 Parsování HTML a získání odkazovaných URL ................................................. 25 4.5.2 Porovnávání HTML....................................................................................................... 26 4.6 Převedení na společné kódování ................................................................................. 26 5 Struktura aplikace .......................................................................................................................... 27 5.1 Základní třídy ...................................................................................................................... 27 5.1.1 Watch ................................................................................................................................. 29 5.1.2 WatchFile ......................................................................................................................... 34 5.1.3 IDataProvider ................................................................................................................. 35 3
5.1.4 MSSQLProvider .............................................................................................................. 37 5.1.5 PluginServices ................................................................................................................ 38 5.2 Html Plugin .......................................................................................................................... 39 5.2.1 NCharDet .......................................................................................................................... 40 5.2.2 Wget a Wgetwrap.......................................................................................................... 40 5.2.3 Jeff Heatonův C# HTML parser ................................................................................ 42 5.2.4 diff.dll ................................................................................................................................. 42 5.2.5 HtmlComparer ............................................................................................................... 43 5.3 Uživatelské rozhraní ........................................................................................................ 47 5.4 Přehled knihoven a zdrojových kódů ........................................................................ 47 6 Vývoj a testování ............................................................................................................................. 49 7 Další vývoj programu .................................................................................................................... 50 8 Závěr .................................................................................................................................................... 51 Citovaná literatura .................................................................................................................................. 52 Seznam Obrázků ...................................................................................................................................... 54 9 Uživatelská dokumentace ........................................................................................................... 55 9.1 Instalace Microsoft SQL Express ................................................................................. 55 9.2 Instalace programu WebPatrol .................................................................................... 57 9.3 Připojení................................................................................................................................ 57 9.4 Hlavní okno aplikace ........................................................................................................ 58 9.4.1 Definice úkolu a akcí nad ním .................................................................................. 59 9.4.2 Vytvoření/editace úkolu ............................................................................................ 60 9.4.3 Stahování úkolů ............................................................................................................. 61 9.4.4 Porovnávání dat úkolu ................................................................................................ 62 9.4.5 Logování ........................................................................................................................... 63 9.4.6 Menu aplikace................................................................................................................. 64 9.5 Seznam souborů úkolu – Watch Files ........................................................................ 65 9.5.1 Filtry nad seznamem souborů ................................................................................. 66 9.6 Porovnávání souborů....................................................................................................... 67 9.6.1 Příklady vyznačení změn ........................................................................................... 67 9.7 Ukončení aplikace ............................................................................................................. 69 9.8 Dodatky k uživatelskému rozhraní a práci aplikace ............................................ 69 9.9 Pokročilá nastavení programu ..................................................................................... 69
4
Název práce: Systém pro sledování a analýzu změn stránek vybraných webových serverů Autor: Michal Kaska Katedra (ústav): Katedra softwarového inženýrství Vedoucí diplomové práce: RNDr. Michal Kopecký, Ph.D. E-mail vedoucího:
[email protected] Abstrakt: Práce popisuje návrh a realizaci systému pro ukládání, sledování a analýzu změn stránek vybraných webových serverů v určité doméně na základě nastavených parametrů. Systém je schopen upozorňovat na změny nezávisle na jazyku stránek a vyhodnocovat významnost těchto změn. Systém je výkonnostně optimalizovaný s využitím paralelního zpracování dílčích operací zadaných akcí. Klíčová slova: Internet, stahování dat, sledování změn
Title: System for monitoring and change analysis of pages of chosen web servers Author: Michal Kaska Department: Department of Software Engineering Supervisor: RNDr. Michal Kopecký, Ph.D. Supervisor's e-mail address:
[email protected] Abstract: This thesis aims on the design and implementation of a system for harvesting, watching and change analysis of pages on chosen web servers in particular domain according to parameters setting. The system is able to recognize changes independently on the used language, as well as evaluate relevancy of the changes. The system is optimized for parallel processing of provided operations. Keywords: Internet, downloads, web harvesting, web changes watching
5
1
Úvod
Celosvětová síť Internet obsahuje každým okamžikem více dat a zároveň dochází ke změnám stávajících. Po internetu je možné sdílet a distribuovat například dokumenty, hudbu, filmy, software či fotografie. Tato data většinou podléhají autorskému zákonu [1] a měla by být šířena v jeho souladu. Vyšetřování pirátství v ČR provádí Policie ČR, nejčastěji na základě udání či dlouhodobého sledování. Po pirátech pak pátrají i soukromé detektivní agentury, které případy posléze předávají policii. Vzhledem k objemu dat a četnosti změn je nelehké tyto sledovat a tak vzniklo zadání této práce. Jejím cílem je vytvořit nástroj pro sledování a uchovávání změn vybrané části internetu, například webových serverů, či domén na základě dalších nastavitelných parametrů. Vzhledem k rozsahu, v jakém by měl být systém schopen vybrané servery sledovat, je spíše určen pro instituce – například policisty, zabývající se internetovou kriminalitou a sledující podezřelé servery. Další cílovou skupinou mohou být softwarové firmy, hlídající odkazy na svůj software na pirátských serverech a stejně tak filmová nebo hudební studia, či produkční firmy. Systém by však mohl být využíván i běžnými uživateli například pro archivaci vlastního webového serveru, stažení vybraných skupin stránek pro pozdější offline zpracování či zmíněné sledování změn – například znění zákonů, titulních stránek deníků a podobně. Následující kapitola analyzuje problematiku související se zadanou prací, identifikuje stěžejní úkoly a zkoumá aktuální nabídku programů, řešících podobnou problematiku či její části. Třetí kapitola na základě analýzy podrobněji specifikuje cíle vyvíjené aplikace a kapitola čtvrtá se poté věnuje návrhu této aplikace a výběru konkrétních řešení. Následují kapitoly popisující objektový model, přehled knihoven a zdrojových kódů. Součástí práce jsou i testy výkonnosti aplikace a návrhy možného dalšího vývoje.
6
2
Analýza
Ze zadání vyplývají následující dílčí úlohy a otázky pro zpracování: parsování HTML stránek a získávání dalších odkazů určení kódování HTML stránek a převedení na společné kódování před jejich porovnáním rozpoznávání formátu souboru porovnávání textových, HTML a dalších formátů souborů způsob ukládání a přístupu ke stahovaným souborům modulární architektura a vhodný objektový model pro docílení snadné rozšiřitelnosti aplikace vhodné uživatelské rozhraní pro obsluhu aplikace (GUI, příkazová řádka) výběr prostředí pro vývoj Některé z uvedených dílčích úkolů jsou již mnohokrát zpracované, a to v míře, které jde v rámci této práce jen těžko konkurovat. Bude-li to možné, je proto vhodné vybrat již fungující řešení a toto řešení využít jako modul programu. Modulární návrh programu umožní v budoucnosti využívat případné nové verze použitých softwarových řešení, ale i jejich snazší nahrazení jiným modulem se stejnou funkčností.
2.1
Parsování HTML stránek a získání dalších odkazů
HTML stránka může obsahovat několik druhů odkazů: odkazy na vnořené objekty, které jsou zobrazeny spolu s HTML stránkou (např. obrázky, videa, či vnořené HTML stránky) odkazy na sebe sama (navigace v rámci stránky) odkazy na další objekty, které jsou zobrazeny teprve po výběru daného odkazu Odkazy mohou být absolutní i relativní vzhledem k umístění zdrojové stránky. Pro procházení domén či jejích částí je třeba tyto odkazy ze souborů získat. Od HTML stránek přitom nelze očekávat, že budou zcela odpovídat standardům pro HTML, případně pro XHTML. Funkčnost programu není možné omezit jen na validní 7
stránky, neboť by pak pro správce stránek bylo snadné vyhnout se zpracování vytvářenou aplikací například vložením chyb, které běžný prohlížeč ignoruje. Pasování HTML stránek je často používaná funkce, která je již mnohokrát zpracována. Existují dva základní přístupy, jakým jsou stránky zpracovávány. Jednou z možností je projít HTML dokument coby textový soubor lineárně od začátku do konce jedním průchodem. Druhou možností je vytvořit z HTML dokumentu W3C DOM1, který umožňuje přístup k dokumentu jako ke stromu objektů, ve kterém lze k jednotlivým elementům snadno přistupovat v náhodném pořadí a opakovaně. Pro implementaci W3C DOM přístupu by bylo možné využít renderovací jádra jako například Mozilla Gecko, Trident, KHTML, či WebCore, která budou podrobněji zmíněna v kapitole 2.4.2 Document Object Model (DOM). 2.1.1
GNU Wget [2]
Pro parsování HTML stránky a získání odkazů by mohla být použita část kódu programu GNU Wget [2], šířeného pod licencí GNU GPL a vyvíjeného již od roku 1996. Wget podporuje rekurzivní stahování, konverzi odkazů pro offline prohlížení HTML, stahování přes proxy, navázání přerušeného stahování a další. Díky licenci GNU GPL je součástí téměř všech hlavních distribucí Linuxu. Wget může být nainstalován na jakémkoli UNIX-like systému a byl portován na mnoho dalších prostředí, včetně Mac OS X, Microsoft Windows a OpenVMS. Standardně jde o neinteraktivní aplikaci, ovládanou pouze přes příkazovou řádku. Existují ale i její grafické nadstavby, např. Gwget pro GNOME Desktop. Nevýhodou programu Wget je to, že nepodporuje paralelní stahování souborů. 2.1.2
HTTrack Website Copier [3]
Podobně jako Wget, i HTTrack je volně šiřitelným programem pod licencí GNU GPL pro vytvoření offline verze webových stránek. Také nabízí zmíněné rekurzivní stahování, relativní odkazy do lokální struktury adresářů a navázání přerušeného stahování. HTTrack nabízí verzi jak pro Windows 9x/NT/2000/XP, tak pro Linux/UNIX/BSD. Obsahuje propracovaný systém filtrů, pomocí kterých lze s využitím masek specifikovat, které soubory se mají, či naopak nemají, stahovat.
1
Document Object Model - standardizovaný objektový model HTML dokumentu
8
2.1.3
Jeff Heatonův HTML parser pro C# [4]
Jedná se o připravený zdrojový kód pro parsování HTML souboru, který by zjednodušil úlohu na procházení HTML značek a atributů. Pro použití tohoto parseru je potřeba zajistit seznam značek a atributů, které mohou nést odkaz na další soubory.
2.2
Určení kódování HTML stránek a převedení na společné kódování před jejich porovnáním
Od počátků počítačů bylo vytvořeno mnoho různých kódování, což se stalo problémem především při globalizaci a rozšíření Internetu, kde se rozdílná kódování stala bariérou. Proto bylo vytvořeno univerzální kódové schéma Unicode, které dokáže pokrýt všechny znaky všech světových jazyků. Unicode přiřazuje každému znaku jedinečné číslo, nezávisle na platformě, na programu a na jazyku. Unicode Standard byl přijat velkými společnostmi, jako jsou například Apple, HP, IBM, JustSystem, Microsoft, Oracle, SAP, Sun, Sybase, či Unisys. Je podporován v mnoha operačních systémech, všech moderních prohlížečích a mnoha dalších produktech. Nejčastěji je Unicode na Internetu využívané ve verzi UTF-8 [5], což je způsob kódování řetězců znaků Unicode/UCS do sekvencí bajtů s proměnnou délkou. Oproti tomu varianta UTF-16 kóduje řetězce do posloupností 16bitových slov a varianta UTF-32 do 32 bitových slov. Na Internetu je stále mnoho dokumentů v různých kódováních a tedy je potřeba před porovnáním stránek toto kódování rozpoznat a převést na kódování společné – v našem případě UTF-8. Způsobů, jak kódování stránky získat, je několik. Tuto informaci může zaslat přímo webový server v hlavičce HTTP odpovědi, nebo může být obsažena v hlavičce HTML souboru v atributu značky META. Nelze se však spolehnout ani na jednu z výše zmíněných metod. Mnoho webových serverů tuto informaci neposkytuje, či jí může poskytovat chybně a ani soubor nemusí informaci o kódování obsahovat, nebo i on ji může obsahovat chybně či může obsahovat směs několika různých kódování. Je proto žádoucí rozpoznat kódování přímo z obsahu souboru.
9
Algoritmus rozpoznávání kódování z obsahu souboru se může opřít o následující faktory: vstupní text se skládá ze slov a vět konkrétního jazyka – zřejmě nejde o neužitečnou informaci, změť znaků vstupní text je pravděpodobně typickou soudobou stránkou umístěnou na internetu – nejde tedy pravděpodobně o mrtvý či starověký jazyk vstupní text může obsahovat i jednotlivá slova či části textu v jiném jazyce než v jakém je primárně napsaný a soubor obsahuje další data, která nesouvisí s jeho jazykem (například HTML značky, HTML komentáře). Problém rozpoznání kódování řeší například MLang API od firmy Microsoft nebo modul, jenž je součástí projektů Mozilly. 2.2.1
Microsoft MLang API
Webový prohlížeč Windows Internet Explorer poskytuje mnoho API funkcí, které lze považovat za součást Windows API. Internet Explorer je součástí operačních systémů firmy Microsoft od Windows 95 a poskytuje doplňující webové funkce od Windows 98. Jednou z těchto funkcí je také podpora pro vícejazyčné a mezinárodní texty (mlang.dll) [6]. Primární rozhraní MLang je IMultiLanguage2 rozhraní, které poskytuje sadu konverzních metod kódových stránek, metody detekce kódových stránek, a řadu metod, které zjišťují informace o kódových stránkách, znakových sadách a národních prostředích. 2.2.2
Mozilla universal charset detection
Organizace Mozilla vytvořila vlastní detektor kódových stránek, který je možné využívat odděleně od ostatních modulů Mozilly [7]. Tento detektor využívá následující metody autodetekce (podrobnější informace lze nelézt v [8]): Vyhledávání multi-byte sekvencí V každém více bajtovém kódování jsou sekvence znaků, které pro něj není možné použít, a jsou-li tyto nalezeny, je pravděpodobné, že dané kódování nebylo užito. Naopak existují kódové sekvence specifické pro některá kódování a jejich užití může vést k pozitivnímu rozhodnutí pro dané kódování.
10
Metoda rozložení užitých znaků V každém jazyce jsou některé znaky používanější než jiné. Tento fakt je možné využít k vytvoření rozložení četnosti užití znaků v každém jazyce a následnému srovnání se zkoumaným textem. Tato metoda je účinnější v jazycích, které obsahují velké množství znaků, jako například čínština, japonština a korejština. Metoda rozložení sekvencí dvou znaků V jazycích, které obsahují malý počet různých znaků, je možné předchozí metodu rozšířit a sledovat užité sekvence například dvou znaků. Získané charakteristiky mohou být užity k rozpoznání užitého jazyka, což vede k lepšímu rozhodování při detekci kódování vstupního textu.
2.3
Rozpoznání formátu souboru
Formát souboru je možné odhadnout například na základě jeho přípony, což ale v případě URL často není směrodatné. Další možností je přečíst z hlavičky HTTP dotazu Content-type. Ten nabývá například hodnot „text/html“, „image/png“ - Jiří Hala uvádí v příkladu u svého článku [9] 187 různých variant Content-type. Ani tato informace nebývá vždy validní a tak je třeba použít nebo kombinovat další mechanismy. Vhodným se zdá být způsob rozpoznání podle typické sekvence znaků, která se vždy nachází na stejném místě od počátku souboru. Tímto způsobem lze popsat většinu datových formátů, se kterými se můžeme běžně setkat. Toho na linuxových distribucích využívá nástroj „file“, který používá definice uložené v souboru /usr/share/magic. Například definice formátu GIF vypadá následovně: # GIF 0 string >4 string >4 string >6 leshort >8 leshort [ zkráceno ]
GIF8 7a 9a >0 >0
GIF image data \b, version 8%s, \b, version 8%s, %hd x %hd,
Tato definice znamená, že formát GIF obsahuje na pozici 0 řetězec "GIF8", dále podle řetězce na pozici 4 rozlišíme, zda se jedná o verzi 87a nebo 89a a na offsetech 6 a 8 jsou uloženy rozměry obrázku.
11
2.4
Porovnání textových a HTML souborů
Při porovnávání textových či HTML souborů je žádoucí zjistit a označit chybějící části textu, nové části textu, případně indikovat přesunutí části textu. Autor se pokoušel prozkoumat nabídku programů řešících zadaný problém a porovnávajících přímo HTML soubory. Nepodařilo mu nalézt žádný volně šiřitelný program, ať už se zdrojovými kódy, či bez nich, ale pouze komerční produkty. Navíc se ukázalo, že nalezené produkty jsou nabízeny za poměrně vysokou cenu – ceny jsou pro srovnání uvedeny. Toto zjištění zvyšuje smysl vytvoření podobné práce, která, ve volně šiřitelné verzi, pravděpodobně ještě neexistuje. HTML Match – komerční produkt ($27.95 pro jednoho uživatele, $1500 neomezená licence) pro zobrazení změn HTML souborů [10] ComponentSoftware HTMLDiff Control – komerční produkt ($3,000 verze pro jednoho developera), který nabízí ActiveX kontrolu pro hledání změn v HTML souborech [11] Compare Two HTML Files or Websites & Find Differences Software 7.0 – komerční produkt ($19.99) pro srovnávání HTML souborů [12] K HTML souboru můžeme přistupovat buďto jako k textu nebo ke stromové struktuře vytvářené vnořujícími se HTML elementy (DOM zmíněný v kapitole 2.1 Parsování HTML stránek a získání dalších odkazů). 2.4.1
Porovnávání textů
Při přístupu k HTML dokumentu jako k textu a hledání změn v tomto textu by bylo možné rozlišovat řídící prvky od zobrazovaného obsahu a porovnávat tyto zvlášť či porovnávat pouze obsažený text bez řídících prvků. Pro porovnávání textu již existuje mnoho nástrojů. Přehled vybraných z nich: GNU Diffutils [13] Diffutils byl vyvinut již v roce 1970 na Unixovém operačním systému. Jsou z něj odvozeny mnohé další projekty, z nich některé budou následně zmíněny. Nabízí několik základních modulů: cmd – porovnání dvou souborů po bytech, diff – porovnání dvou souborů po řádcích, diff3 – porovnání tří souborů po řádcích a spojení změn dvou z nich vůči třetímu, patch – aplikování výsledku porovnání na originální soubor, sdiff – interaktivní spojení dvou souborů do jednoho. Zdrojové kódy jsou napsány v ANSI C a je možné je zkompilovat pro většinu systémů.
12
Diffutils je založen na algoritmu LCS2. Algoritmus LCS se snaží najít nejdelší sekvenci prvků obsažených v obou posloupnostech. Tedy nejdelší takovou, kterou je možné získat z první sekvence smazáním některých prvků a z druhé sekvence smazáním jiných. Například pro následující sekvence: a b c d f g h j q z a b c d e f g i j k r x y z
je výstup LCS následující: a b c d f g j z
Výstup Diffutils pak vypadá následovně: e +
h i - +
q -
k r x y + + + +
Pozor, výstup nemusí být jednoznačný, pouze jeho délka je jednoznačná. Například pro sekvence ABC a BACA dostaneme AC ale i BC. Nejčastěji se Diffutils používá na porovnávání textu po celých řádcích. Výsledek porovnání pak vypadá například následovně: 0a1,6 > This is an important > notice! It should > therefore be located at > the beginning of this > document! > 8,14c14 < compress the size of the < changes. < < This paragraph contains < text that is outdated. < It will be deleted in the < near future. --> compress anything. 17c17 < check this dokument. On --> check this document. On 24a25,28 >
2
longest common subsequence - nejdelší společný podřetězec
13
> This paragraph contains > important new additions > to this document.
V tomto textu jsou symbolem > uvedeny přidané řádky a symbolem < řádky odstraněné. Těmto řádků vždy předchází informace na jakých pozicích a jaká operace byla s textem provedena. ‘a’ značí přidáno, ‘d’ smazáno a ‘c’ změněno. Čísla před těmito znaky ukazují do originálního textu, čísla za těmito znaky do modifikovaného. LCS lze řešit pomocí dynamického programování a jeho časová složitost je v takovém případě Θ(mn). 3 KDiff3 [14] GPL multiplatformní (Linux s KDE3/4, UN*X s Qt, MS-Windows, Apple OSX) projekt pro porovnání, respektive spojování až 3 verzí textových souborů, či adresářů, založený na GNU Diffutils. Zatímco GNU Diffutils nabízí porovnávání řádků nebo znaků, KDiff3 rovnou nabízí porovnávání znaků v rámci rozdílných řádků. KDiff3 je naprogramován v jazyce C++ a pro svůj běh vyžaduje Qt [15]. Qt je multiplatformní aplikační a UI framework dostupný ve formě C++ knihovny, šířený pod licencí GPL, LGPL či licencí pro komerční využití. WinMerge [16] Další GNU Open Source projekt založený na GNU Diffutils. Je určen pro hledání změn ve dvou textových souborech a následné spojení těchto změn do výsledného souboru. Pro vyřešení konfliktních změn vyžaduje zásah uživatele. Podobně jako KDiff3 dokáže zvýraznit změněné řádky, přesunuté bloky textu i rozdíly částí textů v rámci rozdílných řádků. Tento program je často využíván programátory, pracujícími nad společným zdrojovým kódem. Je naprogramován v jazyce C++, ale pouze pro platformu Windows. Subversion (SVN) [17] Subversion je Open Source systém pro správu a verzování zdrojových kódů (náhrada za starší CVS). Je napsán v ANSI C a velmi dobře dokumentován. Pro účely této práce by bylo možné využít část kódu, která hledá rozdíly mezi dvěma textovými soubory (libsvn_diff).
3
V případě porovnávání celých řádků jsou m, n počty řádků.
14
2.4.2
Document Object Model (DOM)
Pro vytvoření DOM z HTML před porovnáním je možné využít některé z již existujících renderovacích jader – například: Gecko [18] – Open source renderovací jádro pro vykreslování webových stránek. Je vyvíjeno společností Mozilla Corporation a využíváno například v projektech Mozilla Firefox, Thunderbird, SeaMonkey, ale i v OpenOffice a dalších. Je napsáno v programovacím jazyce C++ a licencován pod trojlicencí MPL/GPL/LGPL. Jedná se o multiplatformní jádro a je k dispozici pro řadu platforem jako Microsoft Windows, Linux, Mac OS X a další. Neexistuje samostatná knihovna Gecko kvůli poměrně komplikovanému a ne zcela čistému kódu a návaznostem na další zdrojové soubory a knihovny. Trident – Renderovací jádro (též známé jako MSHTML), používané v prohlížeči Internet Explorer pro Microsoft Windows. Díky své integraci do operačního systému Windows je renderovací jádro využíváno v řadě komponent systému a využívá ho i řada instalovaných aplikací. Příkladem může být Windows Explorer, nápověda systému Windows či kancelářský balík Microsoft Office. KHTML (KDE's HTML library) – Renderovací jádro vyvíjené v rámci projektu KDE. Je napsáno v jazyce C++, licencováno pod LGPL a v KDE je od verze 2. Je postaveno na frameworku KPart. Využívá jej webový prohlížeč Konqueror, který je součástí KDE. KHTML je stále vyvíjeno, přestože z něj vyšlo jádro WebCore a jsou mimo jiné snahy změny WebCore přenášet zpět do KHTML. WebCore [19] – Renderovací jádro vyvíjené společnostmi Apple, Nokia, KDE, Google a dalšími. WebCore vychází z KHTML a je jednou z knihoven aplikačního frameworku WebKit, na kterém je postaven prohlížeč Safari. Zdrojový kód je šířen pod licencí LGPL, nativní verze je k dispozici pro Mac OS X, ale jsou napsány wrappery nebo porty pro mnoho systémů. Mimo jiné je součástí již zmíněného frameworku Qt od verze 4.4. Předností WebCore oproti ostatním jádrům je kompaktnost a jednoduchost – jedná se o jednu systémovou knihovnu o velikosti cca 4MB. 2.4.3
HTML->XML
Další možností je převést HTML na validní XML, respektive XHTML. V tomto případě je potřeba vyřešit např. – v HTML se objevující – neuzavřené značky (
→
), nesprávně vnořené značky (např.
..) atd.
15
Opět je možné inspirovat se, nebo využít existující nástroj a to open source utilitu HTML Tidy [20] nabízenou pod MIT-like licencí. Knihovna je napsána v jazyce C a je k ní vytvořeno mnoho wrapperů pro jazyky C++, Pascal, .NET, PHP, Perl a další. 2.4.4
Porovnání XML
Pokud by při vývoji aplikace bylo převedeno porovnávání HTML souborů na porovnávání XML souborů, nebo byl vyvíjen modul pro porovnávání souborů stažených ve formátu XML, bylo by za tímto účelem možné použít již existující knihovnu XMLUnit [21]. XMLUnit je k dispozici ve verzi pro programovací jazyk Java (JUnit) a C# (NUnit) a je primárně určen pro Programování řízené testy (Test-driven development). Jedná se o knihovnu, nabízející porovnání dvou částí XML, aplikování XSLT transformací, vyhodnocování XPath výrazů na částech XML, DOM traversal a validaci XML. XMLUnit pro Javu dokonce umí pracovat s HTML kódem (i nevalidním) a provádět nad ním stejné operace jako nad validním XML. Knihovní funkce dokážou v oblasti elementů rozpoznávat následující rozdíly: Dvě části XML obsahují elementy s různými jmény. Obě části XML obsahují stejný element, ale počet atributů se liší. Počet uzlů jedné část XML se liší od počtu uzlů druhé části XML. Obě částí XML obsahují stejné uzly, ale tyto se liší ve svém pořadí. Byl nalezen uzel v jedné části XML, který nelze spárovat s jiným uzlem v druhé části XML. Atributy elementu jedné části XML jsou uvedeny v jiném pořadí, než v druhé části XML. Příklad, pro který knihovna umí rozhodnout o shodě: <stuff-doc> <stuff> Stuff Stuff Stuff <more-stuff> Some More Stuff
=
<stuff-doc> <more-stuff> Some More Stuff <stuff>Stuff Stuff Stuff
16
2.4.5
XML->DOM
Po připravení validního XML (přesněji XHTML) je možné použít knihovny pro načtení do objektového modelu DOM. Některá vývojová prostředí ho již obsahují: .NET třída System.Xml.XmlDocument, Java třída javax.xml.parsers.DocumentBuilder, PHP třída DOMDocument apod., nebo je možné použít další knihovny, např. multiplatformní open source Apache Xerces XML Parser [22] (je možné si vybrat variantu v jazyce C, Java nebo Perl). Nevýhodou při práci s DOM je, že tento musí být celý najednou v paměti.
2.5
Správa stažených souborů
Vzhledem k tomu, že zvažujeme možnost distribuované realizace, je žádoucí, mít možnost přistupovat k datům z více počítačů zároveň. Bude potřeba nad daty vyhledávat (například podle URL) a ukládat více verzí stažených souborů. Pro ukládání souborů lze například využít existující souborový systém a soubory vhodně třídit do adresářové struktury. Hromadný přístup k těmto souborům by mohla řídit serverová část aplikace, která by řešila případný konfliktní přístup. Pro její implementaci by šlo využít .NET Remoting. Jinou variantou je použití databázového serveru. Databázové servery umožňují vkládat do tabulek i položky typu binární data. Microsoft SQL server má pro tento účel vyhrazen typ IMAGE a velikost vkládaných dat je omezena 2 GB, což je pro naše účely dostatečné. MySQL má pro ukládání binárních dat datový typ BLOB v několika variantách. Varianta LONGBLOB je limitována velikostí 4 GB. Využití databázového serveru by sice řešilo vyhledávání a vzdálený přístup k datům, ale i pro tuto variantu je potřeba vyřešit případný konfliktní zápis z více běžících instancí aplikace. V tomto případě by také bylo možné předsunout před databázový server serverovou část vyvíjené aplikace, která by prováděla řízený přístup k datům. Jinou možností řešení vícenásobného přístupu je použití transakcí. Ovšem stahování jedné úlohy jistě může trvat i mnoho hodin (například celé domény). Není proto vhodné použít transakci na celé stahování, ale spíše vytvořit další tabulku s vlastními zámky pro přístup k datům a časová razítka pro případné vypršení rezervace při spadnutí či odříznutí některé z instancí aplikace. Tyto tabulky by bylo možné v transakci číst a zapisovat atomicky.
17
2.6
Netiketa
Netiketa je slovo odvozené z anglického termínu netiquette. Tento je složeninou slov net a etiquette – tedy síť a etika. Tímto fenoménem se již zabývala řada lidí a na internetu je možné najít práce na toto téma i doporučená pravidla slušného chování na síti. Nás se tato oblast týká, neboť aplikace by mohla některá z těchto pravidel porušovat. Konkrétně by bylo vhodné zabývat se datovým tokem a četností dotazů na webové servery. I kdybychom nechtěli řešit morální stránku věci, je potřeba počítat s tím, že některé servery se mohou aktivně bránit například DoS útokům, za které by mohl být velký počet současných požadavků považován. Následkem toho by server mohl na naše dotazy přestat odpovídat. Řešením je postarat se o řízení datového toku a četnosti dotazů k jednotlivým dotazovaným serverům či nastavit pauzu mezi jednotlivými požadavky na stejný server. Dále by bylo možné inspirovat se programem Wget, který zavádí nastavitelný parametr random-wait. Tato volba způsobuje, že čas mezi požadavky se náhodně mění, neboť některé servery mohou provádět analýzu záznamů za účelem identifikace automatických stahovačů hledáním statisticky podobných časů mezi požadavky. V případě, že bude probíhat stahování z několika různých serverů (domén) zároveň, bylo by vhodné tyto servery postupně střídat. Tím by automaticky vznikaly prodlevy v dotazech na konkrétní server, aniž by zároveň vznikaly prodlevy ve využití zdrojů na naší straně.
18
3
Specifikace
Od aplikace požadujeme funkčnost pod operačním systémem MS Windows, neboť je u potenciálních uživatelů nejrozšířenější. Bylo by však vhodné věnovat při vývoji pozornost také možné budoucí portaci na Linux. Funkční požadavky: uživatelské rozhraní: GUI i CLI (command line interface) vytváření úloh, definujících množinu stránek, dokumentů či objektů, jenž budou v rámci jejího spuštění staženy (definice úlohy viz 3.1 Požadavky na jednotlivou úlohu) zahájení/zastavení stahování jednotlivých úloh paralelní stahování úloh i souborů v rámci každé jednotlivé úlohy ke každé úloze umožnit vytvoření alespoň dvou různých časových snímků, které bude posléze možné porovnávat porovnávání jednotlivých stránek, dokumentů či objektů z různých časových snímků na změny – ohodnocení a zobrazení těchto změn umožnit filtrování a prohlížení výsledků porovnání časových snímků úlohy v závislosti na významnosti změn (např. zjištění počtu změn, seřazení dle významnosti apod.) podpora protokolů: HTTP, HTTPS, FTP schopnost spravovat veliký objem dat – cca gigabyty k jedné úloze přístup k datům z více počítačů/běžících instancí aplikace – pokud možno, paralelně ke všem datům (definice, spouštění, zastavování, prohlížení úloh), případně alespoň paralelně k různým úlohám v rámci jedné instance aplikace paralelizovat akce nad úkoly – tedy nenechat uživatele čekat na stažení úlohy, ale umožnit mu práci s dalšími úlohami
3.1
Požadavky na jednotlivou úlohu
Ke každé úloze umožnit definovat startovní URL adresu
19
hloubku, do jaké se mají sledovat adresy odkazované staženým souborem filtry definující, které soubory se mají v rámci stahované úlohy procházet a které uchovat pro další zpracování/porovnávání (nastavitelné hodnoty: maximální velikost souborů pro zpracování, omezení stahování na doménu, podrobnější omezení stahovaných adres např. regulárními výrazy atd.)
3.2
Požadavky na porovnání souborů
porovnávání souborů implementovat pomocí pluginů a umožnit tak přidáním dalších pluginů rozšíření podpory porovnávaných formátů vytvořit podporu porovnávání pro soubory ve formátu HTML a plain textových souborů (porovnání, ohodnocení změn a zobrazení těchto změn) webové stránky a textové soubory porovnávat nezávisle na kódování v jakém jsou uloženy
20
3.3
Naplnění požadavků vybranými stávajícími aplikacemi
Tabulka ukazuje, do jaké míry naplňují zmíněné existující aplikace zadanou specifikaci. Název aplikace
Funkcionalita
GNU Wget
pouze command line multiplatformní rekurzivní stahování HTML stránek a vnořených objektů podpora protokolů HTTP, HTTPS, FTP
HTTrack Website Copier
GUI; command line multiplatformní rekurzivní stahování HTML stránek a vnořených objektů podpora protokolů HTTP, HTTPS, FTP
HTML Match
GUI; command line
(komerční)
porovnání dvou HTML souborů (lokálních či na internetu) na úrovni znaků, slov či řádků
ComponentSoftware ActiveX control HTMLDiff Control porovnání dvou textových, HTML či XML souborů (lokálních (komerční) či na internetu) Compare Two HTML pouze GUI Files or Websites & porovnání dvou HTML souborů (lokálních či na internetu) Find Differences Software 7.0 (komerční) GNU Diffutils
pouze command line multiplatformní porovnání dvou textových souborů
KDiff3
pouze GUI (command line pro nastavení parametrů spuštění) multiplatformní porovnání dvou textových souborů či adresářů
WinMerge
pouze GUI (command line pro nastavení parametrů spuštění)
Subversion
pouze command line multiplatformní porovnání textových souborů oproti repository
21
4
Design
Platformou pro vývoj byl zvolen Microsoft .NET Framework ve verzi 3.5 a programovací jazyk C#. Jedním z důvodů byla důvěra v budoucnost takového řešení a možná přenositelnost .NET kódu na operační systémy Unixového typu díky platformě Mono, implementující .NET runtime. Dalšími důvody byly vysoká produktivita vývoje v programovacím jazyce C# a zájem autora o získání hlubších zkušeností s tímto programovacím jazykem. Prostředím pro vývoj bylo zvoleno oficiální vývojové prostředí od společnosti Microsoft - Microsoft Visual Studio ve verzi 2008. Bylo vybráno vzhledem k podpoře jazyka C#, stejně jako pro zkušenosti autora s tímto prostředím. Aplikace je rozdělena na moduly, které zpřehledňují zdrojový kód aplikace, umožňují snazší zásahy do kódu a jeho změny. Parsování stažených souborů je navíc, dle požadavků, implementováno pomocí pluginů. Toto umožňuje snadné přidávání podpory dalších formátů bez nutností přímého zásahu do kódu aplikace a její rekompilace. V této kapitole jsou postupně diskutovány funkční celky vyplývající z dílčích úloh uvedených v kapitole „2 Analýza“ a z požadavků, uvedených v kapitole „3 Specifikace“. Tyto celky jsou řešeny odděleně pomocí modulů. Jejich vzájemný vztah a názvy tříd, případně rozhraní, je zobrazen v obrázku „Obrázek 1 Základní schéma propojení modulů“. V kapitole „5 Struktura aplikace“ následuje podrobný popis jednotlivých rozhraní a popis vzájemné komunikace modulů. Detailní struktura kódu je vygenerovaná pomocí programu Doxygen [23] a přiložena na CD v podobě HTML stránek v adresáři \documentation\HTML\index.html.
22
Datové uložiště IDataProv ider
GetList<Watch>()
MSSQLProv ider
MS SQL db
Jádro programu Watch
WatchFile 1
Actor
*
Compare() Update()
GetRefUri() Compare() Správa zásuvných modulů PluginServ ices
1 * IPlugin Wget
getUrls() ContentEncoding()
Diff
HtmlPlugin
NCharDet
Obrázek 1 Základní schéma propojení modulů
4.1
Úloha (Watch)
Úloha definuje množinu stránek, dokumentů či objektů, jenž budou v rámci jejího spuštění staženy (definice úlohy viz 3.1 Požadavky na jednotlivou úlohu). Modul obsahuje své nastavení a umožňuje spuštění, stažení či porovnání stránek s jinou verzí. Akce spuštěné na úloze probíhají nezávisle na zbytku aplikace. Proto je nutné moci zjišťovat stav, v jakém se úloha nachází. O těchto změnách úloha informuje událostmi. U souborů stažených v kontextu úlohy je požadavek na rozlišení a uložení dvou či více verzí, které bude posléze možné mezi sebou porovnávat. Vzhledem k tomu, že implementace podpory dvou verzí se oproti implementaci více verzí se liší pouze pracností a nepřináší žádnou další invenci, je řešení vypracováno pro dvě verze. Je však brán ohled na snadné budoucí rozšíření na více verzí.
23
4.2
Jednotlivé soubory (WatchFile)
K umožnění paralelní práce s jednotlivými soubory (respektive URL) je pro jejich zpracování vytvořen samostatný modul. Ten, podobně jako modul pro zpracování úloh, obsahuje své parametry, aktuální stav, poskytuje API pro aktualizace a o změnách informuje událostmi.
4.3
Datové úložiště
Od datového úložiště požadujeme rozhraní, které umožní ukládání a načítání úloh, jednotlivých souborů a také atomickou změnu verze celé uložené úlohy – tedy všech jejích souborů. Aby bylo možné modul datového úložiště snadno nahradit, bylo pro jeho použití navrženo rozhraní IDataProvider nezávislé na jeho konkrétní implementaci. Vzhledem k požadavku paralelního přístupu z různých míst v síti a atomickým změnám více záznamů, byl použit databázový server, který všechny tyto podmínky splňuje. Databázový server umožňuje vkládání souborů do záznamů, je možné přistupovat k datům z více počítačů zároveň, umožňuje transakce, čímž je možné zajistit atomicitu operací a konzistenci dat. Navíc řeší i rychlé vyhledávání nad záznamy. Vzhledem k tomu, že Microsoft SQL server je ve verzi Express možné používat zdarma, je součástí instalace Microsoft Visual Studia a je podporován platformou .NET, byl pro použití s programem WebPatrol zvolen právě tento server. Konkrétní implementací rozhraní IDataProvider pro tento server je třída MSSQLProvider.
4.4
Správa zásuvných modulů
Každý stažený soubor se zpracovává pomocí pluginu, od kterého je požadována následující funkcionalita: zjištění seznamu odkazovaných URL adres porovnání dvou verzí stejného souboru – výsledkem porovnání by mělo být ohodnocení změny a textová či grafická reprezentace změny plugin by měl sám rozhodnout, zda vstupní soubor dokáže zpracovat Pluginy implementují rozhraní IPlugin a jsou po startu aplikace dynamicky načteny pomocí modulu PluginServices. Stažené soubory se ke zpracování předávají tomuto modulu, který je dále předává ke zpracování načteným pluginům. 24
4.5
Plugin pro zpracování HTML souborů
Pro parsování HTML již existuje mnoho nástrojů a proto byly použity již existující implementace, zmíněné v kapitole 2.1 Parsování HTML stránek a získání dalších odkazů. 4.5.1
Parsování HTML a získání odkazovaných URL
Pro získání odkazovaných URL ze souboru ve formátu HTML musíme znát všechny HTML značky, které mohou takový odkaz obsahovat. V HTML souborech je možné tyto odkazy rozdělit na dvě skupiny podle toho, zda odkazovaný soubor je zobrazen spolu se stránkou, která jej odkazuje (například vnořený obrázek), nebo je tento zobrazen jako samostatný dokument až po jeho výběru. Následující tabulka obsahuje seznam HTML značek, které mohou odkazovat na další stránku, nebo vnořený objekt. Je převzata a upravena z kódu programu GNU Wget [2]. V prvním sloupci jsou názvy značek, v druhém název příslušného atributu a ve třetím, zda tato kombinace odkazuje na jiný dokument (HTML), vnořený objekt (INLINE) či jsou možné obě varianty (BOTH). Značka A APPLET AREA BASE BGSOUND BODY EMBED EMBED FIG FORM FRAME IFRAME IMG IMG IMG INPUT LAYER LINK META OBJECT OVERLAY SCRIPT TABLE
Atribut href code href href src background href src src action src src href lowsrc src src src href content data src src background
Odkaz HTML INLINE HTML HTML INLINE INLINE HTML BOTH INLINE HTML BOTH BOTH INLINE INLINE INLINE INLINE BOTH BOTH HTML4 INLINE BOTH INLINE INLINE
Některé ze značek musí být parsovány speciálním způsobem. Například META, kde je odkaz uveden pouze jako část hodnoty atributu. 4
25
Značka TD TH
Atribut background background
Odkaz INLINE INLINE
Zdrojový kód programu GNU Wget [2] obsahuje procedury, které se přímo starají o získání seznamu odkazovaných URL. Vzhledem k rozšířenosti projektu je možné očekávat prověřenost a dobrou úspěšnost daného kódu. K projektu Wget existuje projekt, připravený pro Visual Studio 2005: Wget Visual Studio 2005 projekt [24], který byl při implementaci využit. Jinou variantou je použít 2.1.3 Jeff Heatonův HTML parser pro C# [4] a doimplementovat hledání odkazů na základě tabulky uvedené v této kapitole. I tato varianta byla implementována, ale vzhledem k větší úspěšnosti kódu převzatého z projektu Wget není ve finální verzi využita. 4.5.2
Porovnávání HTML
V kapitole 2 Analýza byly navrženy dvě varianty porovnání HTML souborů. Jednou je lineární porovnání textu a druhou sestavení DOMu. Očekává se však porovnávání velkého množství dokumentů a vytváření DOM a porovnávání elementů v rámci stromu by pravděpodobně vedlo k větší časové složitosti, než algoritmus založený na LCS, byl proto vybrán algoritmus, založený porovnávání textu. Konkrétně byl využita již existující implementace .NET knihovny, založené na Gnu Diffutils: Diff/Merge/Patch Library for C#/.NET [25] Abychom dosáhli nezávislosti na kódování, je nutné text před porovnání nejprve převést na společné kódování, o což se stará samostatný modul, popsaný v následující kapitole.
4.6
Převedení na společné kódování
Pro platformu .NET existují hotové implementace pro obě řešení, zmíněná v kapitole 2.2 Určení kódování HTML stránek a převedení na společné kódování před jejich porovnáním: C# Wrapper na Microsoft MLang API [26] C# port of Mozilla universal charset detection [27] Vzhledem k tomu, že C# portace detekce kódování od Mozilly má zdrojové kódy kompletně přepsány pro platformu .NET, kdežto C# Wrapper na Microsoft MLang využívá systémovou knihovnu MLang.dll operačního systému Windows, bylo použito řešení od Mozilly. Toto lze nalézt v projektu s názvem NCharDet. 26
5
Struktura aplikace
Kapitola obsahuje podrobný rozbor jednotlivých modulů a tříd, popis rozhraní těchto tříd a použitých algoritmů.
5.1
Základní třídy
Základními třídami a rozhraními aplikace jsou: Watch – parametry a funkcionalita sdružená s úkolem WatchFile – parametry a funkcionalita sdružená s jednotlivou URL WatchInfo – informace o stavu stahování úkolu WatchConfig – parametry nastavení jednotlivého úkolu IDataProvider – rozhraní zapouzdřující práci s úložištěm PluginServices – zapouzdřuje práci s pluginy Watch i WatchFile jsou jednoznačně identifikovány pomocí GUID5. Watch si nedrží seznam k němu náležejících WatchFile objektů, ale ve chvíli, kdy je potřebuje, vyžádá si je od IDataProvideru. Obdobně si instance WatchFile standardně nedrží obsah souborů, ale pouze jejich hlavičky. Pokud je obsah souboru potřeba, může být rovněž vyžádán od IDataProvideru. Je-li na objektu Watch nebo WatchFile spuštěna akce, je její ukončení oznámeno událostí.
5
Globally Unique Identifier – globálně jednoznačný identifikátor
27
Na následujícím sekvenčním diagramu jsou zobrazena hlavní volání a události těchto objektů, která probíhají v rámci vytvoření a stažení úlohy:
Actor
IDataProvider PluginServices create(uri) : Watch Watch Save()
SaveWatch()
DownloadCurrent() create(uri, levels) : WatchFile WatchFile OnAddFile()
UpdateCurrent()
SaveWatchFile()
OnDownloadFinished()
OnDownloadFinished()
GetRefUri() : urls[]
OnDownloadFinished()
remove content()
Obrázek 2 Komunikace hlavních objektů
28
5.1.1
Watch
Diagram třídy Watch a s ní souvisejících tříd: Watch
WatchInfo -info
-
actionARE: volatile AutoResetEvent = null activeThreadsCount: volatile Int32 = 0 cmpDoneCount: volatile Int32 = 0 cmpQueueWaiting: volatile List<WatchFile> = null config: WatchConfig dataprovider: volatile IDataProvider description: String downloadQueues: volatile DownloadQueues = null guid: Guid info: WatchInfo isNew: Boolean name: String startUri: Uri watchMutex: volatile Mutex = new Mutex()
+ + + + + + + + + -
AddFileToDownload(Uri, UInt16) : Boolean CancelAction() : void Clear() : Boolean DownloadCurrent() : Boolean DownloadingThread(object) : void ForceStateToFinished() : Boolean RunWatchFileComparison(object) : void RunWatchFileDownload(object) : void Save() : Boolean SaveInfo() : Boolean UpdateComparison(Boolean) : Boolean UpdateComparisonThread(object) : void Watch(IDataProvider, Uri, String, String, WatchConfig) Watch(IDataProvider, Guid, Uri, String, String, WatchConfig, WatchInfo) wfile_OnComparisonFinished(object, ComparisonEventArgs) : void wfile_OnDownloadFinished(object, EventArgs) : void
-
created: DateTime = DateTime.Now currentFinished: DateTime = DateTime.MinValue dstate: ActionState = ActionState.Empty snapshotFinished: DateTime = DateTime.MinValue
+ +
XmlDeserialize(String) : WatchInfo XmlSerialize() : String
«property» + Created() : DateTime + CurrentFinished() : DateTime + DState() : ActionState + SnapshotFinished() : DateTime
-dstate «enumeration» ActionState
«property» + ActiveCount() : UInt32 + ActiveDownloadedBytes() : UInt32 + Config() : WatchConfig + DataProvider() : IDataProvider + Description() : String + DoneCount() : UInt32 + Guid() : Guid + Info() : WatchInfo + IsCanceled() : Boolean + IsComparing() : Boolean + IsDownloading() : Boolean + Name() : String + StartUri() : Uri + WaitingCount() : UInt32
Empty Downloading Comparing Canceled Finished Ignored Unchanged Error Locked
EventArgs WatchEv entArgs -
wfile: WatchFile
+
WatchEventArgs(WatchFile)
«property» + WatchFile() : WatchFile
EventArgs ComparisonEv entArgs -
result: WatchComparison
+
ComparisonEventArgs(WatchComparison)
«property» + Result() : WatchComparison
WatchConfig
«event» + OnAddFile() : EventHandler<WatchEventArgs> + OnComparisonFinished() : EventHandler<EventArgs> + OnDownloadFinished() : EventHandler<EventArgs>
-config
-downloadQueues Dow nloadQueues -
dqMutex: Mutex = new Mutex() queueActive: Hashtable = new Hashtable() queueDone: Hashtable = new Hashtable() queuesWaiting: FIFOHashtable = new FIFOHashtable() simultaneousDownloads: UInt16
+ + + + +
ActiveToDone(WatchFile) : Boolean AddWaiting(Uri, WatchFile) : Boolean AnyContains(Uri) : Boolean AnyContainsWithoutMutex(Uri) : Boolean DownloadQueues(UInt16) DropAllWaiting() : void
-
credential: NetworkCredential = null downloadAttempts: UInt16 = 5 justDomain: Boolean = true levels: UInt16 = 0 maximalSize: Int64 = 10000*1024 simultaneousDownloads: UInt16 = 20 uriRegexFollow: Regex = null uriRegexFollowStr: String = "" uriRegexKeep: Regex = null uriRegexKeepStr: String = ""
+ + + + +
UriRegexFollowAccept(Uri) : Boolean UriRegexKeepAccept(Uri) : Boolean WatchConfig() XmlDeserialize(String) : WatchConfig XmlSerialize() : String
«property» + Credential() : NetworkCredential + DownloadAttempts() : UInt16 + JustDomain() : Boolean + Levels() : UInt16 + MaximalSize() : Int64 + SimultaneousDownloads() : UInt16 + UriRegexFollow() : Regex + UriRegexFollowStr() : String + UriRegexKeep() : Regex + UriRegexKeepStr() : String
«property» + ActiveCount() : UInt32 + ActiveFromWaiting() : WatchFile + AllDone() : Boolean + AllEmpty() : Boolean + DoneCount() : UInt32 + DownloadedBytesInActive() : UInt32 + WaitingCount() : UInt32
Obrázek 3 Třída Watch
29
Třída Watch ani třída WatchFile nepracují, kromě stahování souboru, s jeho obsahem. Veškeré úkoly jako získání seznamu odkazů a porovnávání obsahu verzí jsou řešeny pomocí pluginů. Tím je systém snadno rozšiřitelný o další podporované formáty souborů, či umožňuje výměnu a náhradu stávajícího HTML parseru. Jak bylo rozhodnuto v kapitole „4 Design“, tak každá úloha může mít současně dvě stažené verze, které lze mezi sebou porovnávat. Pro snadnou čitelnost v kódu jsou tyto označeny jako Current a Snapshot. Do Current verze probíhá spuštěné stahování (případně aktualizace) a Snapshot verze je Current verze uložená v okamžiku určeném uživatelem. Veřejné metody třídy Watch: Zastavení aktuální akce (stahování, porovnávání): public void CancelAction()
Stažení/aktualizace Current verze všech souborů (WatchFile), které náležejí k danému úkolu: public Boolean DownloadCurrent()
Spočtení podobnosti u všech souborů náležejících k dané úloze: public Boolean UpdateComparison(Boolean forcedAll)
Veřejné metody komunikující s IDataProviderem: Vytvoření nebo aktualizace úlohy v databázi: public Boolean Save()
Uložení/aktualizace pouze proměnné WatchInfo info, což je vhodné například po změně stavu: public Boolean SaveInfo()
Změna aktuálního stavu na Finished (nedokončený stav nedovoluje porovnání, tak může být na žádost uživatele stav Finished vynucen): public Boolean ForceStateToFinished()
Stahování: Za účelem stahování dat Watch obsahuje objekt třídy DownloadQueues. Tento sdružuje práci s frontami queuesWaiting, queueActive a queueDone, mezi kterými se, 30
dle stavu v jakém se nacházejí, přesouvají stahované soubory. QueuesWaiting je fronta doménových front. Obsažené WatchFile jsou v ní, z důvodů uvedených v kapitole 2.6 Netiketa, dále rozděleny do front podle domény ve které jsou uloženy. Pro synchronizaci práce s těmito frontami třída DownloadQueues využívá mutex dqMutex. Stahování souborů a přesun objektů třídy WatchFile mezi frontami probíhá podle následujícího diagramu:
Watch
GetWatches() IDataProvider
MSSQLProv ider
MS SQL
Add OnDownloadFileFinished
SaveWatchFile() DownloadQueues
Waiting Queues
Active Queue
Domain Queue
Done Queue
WatchFile
Uri
WatchFile WatchFile WatchFile
WatchFile Domain Queue WatchFile WatchFile WatchFile
Domain Queue WatchFile WatchFile WatchFile
ActiveFromWaiting
ActiveToDone
Obrázek 4 Fronty stahování souborů
Pomocné vlastnosti a metody pro práci s frontami (většina využívá zmíněný mutex): Boolean AllEmpty Boolean AllDone WatchFile ActiveFromWaiting void DropAllWaiting Boolean AnyContains(Uri uri) Boolean ActiveToDone(WatchFile wfile)
31
Stav stahování je možné zjistit z následujících veřejných vlastností třídy Watch: public public public public
UInt32 UInt32 UInt32 UInt32
DownloadedBytesInActive ActiveCount WaitingCount DoneCount
Fronty jsou řešeny hashovací tabulkou, kde klíčem je Uri objektu WatchFile. Důvodem je časté vyhledávání ve frontách. Z každého staženého souboru může být vytvořen nový list odkazů ke stažení a ty jsou přidány do fronty pouze v případě, že ještě nebyly přidány. Ve frontě Done (dokončené) používáme pouze klíč objektu, neboť WatchFile byl uložen do databáze a není již v tuto chvíli potřebný. Je potřeba pouze adresa, aby soubor nebyl stahován opakovaně. Fronta queuesWaiting a v ní obsažené fronty jsou uloženy v upravené verzi hashovací tabulky implementované třídou FIFOHashtable, která nad rámec standardní hashovací tabulky nabízí nad uloženými prvky funkcionalitu FIFO 6 fronty. Tuto funkcionalitu potřebujeme, abychom mohli, dle požadavků uvedených dříve, doménové fronty pravidelně cyklicky střídat. Všechny objekty WatchFile, které jsou ve frontě queueActive, jsou stahovány v samostatném vlákně a po ukončení (ať úspěšném, či neúspěšném) toto oznámí událostí. Watch událost zpracuje, předá obsah souboru pluginům a vyžádá si seznam odkazů. Nové odkazy vloží do fronty a spustí maximální počet stahování dle nastavení (většinou to bude znamenat jedno místo právě ukončeného). Porovnání funguje podobně s tím, že soubory se přidají jednorázově do vlastní fronty čekajících souborů na porovnání a je hlídán počet aktivních vláken, který je doplněn po každém ukončeném porovnání. Aby nedocházelo k opakovanému vytváření mnoha vláken je využívána .NET třída ThreadPool, která se stará o zásobník vláken využívaných ke stahování a porovnávání. Watch nabízí následující události: Událost, která je vyvolána vždy, když je přidán nový soubor do front stahování – tedy pro první iniciální URL a pak pro každý, který vrátí pluginy v seznamu referencí, ale který ještě nebyl přidán: public event EventHandler<WatchEventArgs> OnAddFile;
6
FIFO = First In, First Out, tedy fronta, kde první vstupující prvek zároveň první z fronty vystupuje
32
Událost, která je vyvolána po dokončení stahování, když fronty queueWaiting a queueActive jsou prázdné. Je vyvolána i při zastavení, ale až po vyprázdnění queueActive. Toto může ještě chvíli (podle nastavení timeout) trvat, neboť vlákno může například čekat na odpověď ze serveru: public event EventHandler<EventArgs> OnDownloadFinished;
Podobně jako předchozí, jen je vyvolána po ukončení porovnání všech souborů objektu Watch: public event EventHandler<EventArgs> OnComparisonFinished;
Události třídy Watch jsou využívány z UI pro sledování stavu a kontrolní výpisy. Synchronizace: Třída Watch zpracovává události z více stahujících či porovnávacích vláken zároveň, proto jsou dotčené proměnné označeny klíčovým slovem volatile, které zajišťuje, že kompilátor nebude optimalizovat jejich užití. Dále je zajištěna atomicita některých operací – především se stavem objektu Watch – mutexem watchMutex.
33
5.1.2
WatchFile
Diagram třídy WatchFile a souvisejících tříd:
WatchFile
FileContent
-
current: FileContent downloadedBytes: Int32 = -1 dstate: ActionState = ActionState.Empty guid: Guid levelsUnder: UInt16 parent: Watch similarity: Double = -1 snapshot: FileContent uri: Uri
-current -snapshot -
+ + + +
AreHeadersIdentical(FileContent, FileContent) : Boolean RetrieveContent(FileContent, WebResponse) : Boolean RunComparison() : Boolean TryToGetLastModified(WebResponse) : DateTime UpdateCurrent() : Boolean WatchFile(Uri, UInt16, Watch) WatchFile(Guid, Uri, UInt16, Double, Watch)
content: Byte ([]) fileSize: Int32 header: FCHeader = new FCHeader() md5: String
«property» + Content() : Byte[] + FileSize() : Int32 + Header() : FCHeader + MD5() : String
-header FCHeader
«property» + ActionState() : ActionState + Current() : FileContent + DownloadedBytes() : Int32 + Guid() : Guid + IsCanceled() : Boolean + IsDownloading() : Boolean + LevelsUnder() : UInt16 + Parent() : Watch + Similarity() : Double + Snapshot() : FileContent + Uri() : Uri
-
contentType: String datetime: DateTime eTag: String
+ +
XmlDeserialize(String) : FCHeader XmlSerialize() : String
«property» + ContentType() : String + DateTime() : DateTime + ETag() : String
«event» + OnComparisonFinished() : EventHandler
+ OnDownloadFileFinished() : EventHandler<EventArgs>
Obrázek 5 třída WatchFile
Veřejné funkce třídy WatchFile: Spuštění stahování souboru: public Boolean UpdateCurrent()
Před stahováním nové verze úkolu (Watch) je Current verze označena příznakem isUpdating (tento požadavek provádí IDataProvider). Jestliže je soubor po stažení hlavičky označen jako nezměněný, stačí příznak odstranit. V případě že byly některé soubory odstraněny, zůstanou po stahování ve stavu isUpdating a budou odstraněny. V případě, že se soubor neshoduje s verzí Current, nebo tato neexistuje, ale shoduje se s verzí Snapshot, pouze se toto oznámí na IDataProvider a stahování obsahu souboru se neprovede. Pouze pokud soubor není shodný s žádnou z obou existujících verzí, bude provedeno jeho reálné stažení z Internetu. Může se stát, že shodu zjistíme až po stažení souboru. Například pokud server nepošle v hlavičce žádoucí parametry (viz
34
níže). I pak není soubor po stažení posílán na server, ale je pouze IDataProvideru oznámena shoda. Při jakémkoli updatu je resetován stav isUpdating. Porovnávané hlavičky souborů jsou testovány na shodu velikosti souboru, MD5, data, času a ETag v uvedeném pořadí. Je potřeba počítat s tím, že ze serveru mohou být poslány jen některé nebo i žádné z těchto údajů. Je-li rozdíl v libovolném údaji, je rozhodnuto o stahování celého souboru. Nejsou-li v údajích rozdíly, a je-li serverem zaslán údaj MD5 či ETag, je rozhodnuto o shodě. Jinak je pro shodu vyžadován alespoň stejný datum, čas a velikost souboru. Spuštění porovnání Current a Snapshot verzí souborů: public Boolean RunComparison()
Porovnání předá řízení objektu PluginServices, kde se provede vlastní porovnání prostřednictvím pluginů. WatchFile nabízí následující události: public event EventHandler OnComparisonFinished; public event EventHandler<EventArgs> OnDownloadFileFinished;
5.1.3
IDataProvider
Datové rozhraní, prostřednictvím kterého jsou řešeny všechny přístupy k datovému úložišti. public interface IDataProvider { Boolean Connect(); void Disconnect(); Boolean IsConnected { get; } List<Watch> GetWatches(Guid lockingGuid); Boolean CreateWatch(Watch watch); Boolean SaveWatch(Watch watch); Boolean SaveWatchInfo(Watch watch); Boolean MakeSnapshotFromCurrent(Watch watch); Boolean ClearWatch(Watch watch); Boolean RemoveWatch(Watch watch); Boolean LockWatch(Watch watch, Guid lockingGuid, Boolean update); Boolean ReleaseWatch(Watch watch, Guid lockingGuid); Boolean SaveWatchFile(WatchFile wfile); List<WatchFile> GetWatchFiles(Watch watch);
35
Int32 GetWatchFilesCount(Watch watch, Boolean current); Byte[] GetWatchFileContent(WatchFile wfile, Boolean current); Boolean SetCurrentSameAsSnapshot(WatchFile wfile); Boolean SetSimilarity(WatchFile wfile, Double similarity); Boolean SetCurrentToUpdating(Watch watch); WatchFile GetUpdatingWatchFile(Watch watch, Uri uri); Boolean UnsetUpdating(WatchFile wfile); Boolean RemoveUnusedCurrentUpdating(Watch watch); }
První odsazená skupina metod rozhraní se stará o připojení a odpojení data provideru – v případě implementace nad databázovým serverem, to může být například přihlášení na server. Druhá odsazená skupina metod pracuje s objektem Watch. Provádí načtení seznamu všech úkolů, vytvoření, uložení úkolu či změnu jeho stavu, převedení aktuální verze na verzi uloženou pro porovnání, případně vyčištění nebo odstranění úkolu. Poslední dvě metody zamykají a odemykají Watch. Toho je využito k umožnění práce z více klientů zároveň, jak bylo navrženo v kapitole „2.5 Správa stažených souborů“. Každý klient se identifikuje svým id a případný zámek musí obnovovat (parametr update), jinak je za 3 minuty prohlášen za neplatný a uvolněn. Stahovaný úkol bude posléze převeden do stavu Error, neboť není jasné, zda bylo stahování dokončeno. Třetí skupina pracuje s objekty třídy WatchFile. Nabízí uložení objektu WatchFile, nebo načtení seznamu souborů patřícího k danému objektu Watch. Jak již bylo zmiňováno, načtené objekty neobsahují obsahy souborů, ale pouze hlavičky. Obsah souboru je možné získat metodou GetWatchFileContent, kde jedním z parametrů určení verze (Current/Snapshot). Porovnání používá poslední metodu z této skupiny: SetSimilarity. Poslední skupina je určena pro aktualizace existující Current verze souborů. Nastavení příznaku isUpdating všem souborům daného objektu Watch: Boolean SetCurrentToUpdating(Watch watch);
Nalezení objektu WatchFile, který je ve stavu isUpdating a má shodnou Uri s parametrem: WatchFile GetUpdatingWatchFile(Watch watch, Uri uri);
36
Zrušení příznaku isUpdating – používá se, pokud soubor nebyl změněn (tzn. soubor je akceptován jako aktuální verze): Boolean UnsetUpdating(WatchFile wfile);
Vyčištění databáze od všech souborů náležících k objektu Watch, které zůstali s příznakem isUpdating – používá se po dokončení stahování: Boolean RemoveUnusedCurrentUpdating(Watch watch);
5.1.4
MSSQLProvider
MSSQLProvider je implementace rozhraní IDataProvider nad Microsoft SQL serverem. Data uchovává v následujících tabulkách:
Obrázek 6 MSSQLProvider databázové tabulky
Třída MSSQLProvider oproti rozhraní IDataProvider obsahuje navíc následující veřejné vlastnosti: String DbName String ServerName Authentication Auth
37
String UserName String Password Boolean ExistDatabase
Také obsahuje metodu Boolean CreateEmptyDatabase()
která vytvoří novou databázi včetně všech požadovaných tabulek. Pokud vytvářená databáze již existuje, je tato nejprve odstraněna. 5.1.5
PluginServices
Třída PluginServices je určena na přístup k pluginům, které jsou při spuštění aplikace automaticky vyhledány v podadresáři \Plugins. Načteny jsou DLL soubory, které implementují rozhraní WebPatrol.Plugin odvozené od rozhraní IPlugin: namespace WebPatrol { public interface IPlugin { List GetRefUri(ContentParam content); WatchComparison Compare(ContentParam snapshot, ContentParam current); PluginConfig Config { get; set; } } public class ContentParam { public Uri uri; public String contentType; public Byte[] content; } public class WatchComparison { Double similarity; String htmlReport; Bitmap bitmapReport; public Double Similarity { get { return similarity; } set { similarity = value; } }
38
public String HtmlReport { get { return htmlReport; } set { htmlReport = value; } } public Bitmap BitmapReport { get { return bitmapReport; } set { bitmapReport = value; } } } }
Plugin musí implementovat zmíněné rozhraní, kde metoda GetRefUri by měla vracet seznamu odkazů, nebo hodnotu null, pakliže plugin neumí zpracovat vstupní soubor. Metoda Compare by měla vracet výsledek porovnání obsahů dvou souborů, nebo hodnotu null, pakliže plugin neumí zpracovat vstupní soubor. Vlastnost Config umožňuje nastavení parametrů ovlivňujících vyznačení změn v HTML reportu apod. (více v přiložené vygenerované dokumentaci). Po pluginu je požadováno, aby mohl být spuštěn v několika vláknech zároveň. PluginServices je statická třída implementující následující metody: static public void LoadPlugins() static public List GetRefUri(ContentParam param) static public WatchComparison Compare(ContentParam snapshot, ContentParam current)
LoadPlugins načte z adresáře \Plugins všechny knihovny, které splňují podmínky zmíněné na začátku kapitoly a zpravidla jej stačí zavolat jedenkrát při spuštění programu. Metody GetRefUri a Compare volají postupně tuto metodu na všechny nalezené pluginy a vrátí první úspěšný výsledek.
5.2
Html Plugin
Projekt Parse.Html obsahuje implementaci pluginu, která je určena především pro práci s HTML soubory. Přestože je to samostatný plugin, je jako projekt vložen do společné Visual Studio solution, což umožňuje snazší ladění kódu. Plugin je možné snadno oddělit.
39
HtmlPlugin.cs obsahuje implementaci třídy Plugin, která se stará o porovnávání především HTML souborů a vrácení referencí ze zadaného HTML souboru. Tento plugin je napojen na další 3 projekty a jedno externí DLL viz Obrázek 7 HTML Plugin.
IPlugin Wget
getUrls() ContentEncoding()
Diff
HtmlPlugin
NCharDet
Obrázek 7 HTML Plugin
5.2.1
NCharDet
Jedna ze dvou nalezených možností detekce kódování dokumentu, která je založena na Mozilla universal charset detection a byla beze změny převzata z [27]. Pro její volání je vytvořena privátní metoda ve třídě Plugin private Encoding ContentEncoding(Byte[] content)
která vytvoří objekt typu nsDetector. Samotná detekce proběhne ve třech fázích. Nejprve se testuje, zda text není čisté ASCII, poté se pokusí určit kódování a když se toto nepodaří, vybere se nejvíce pravděpodobné. Není-li ani toto určeno, je vrácena hodnota Encoding.Default, která je odvislá od jazykového prostředí na kterém program běží. 5.2.2
Wget a Wgetwrap
Program Wget [2] byl, kromě využití kódu parsování HTML stránky na seznam odkazů, využit i jako inspirace při vytváření vlastního stahování. Autor například řešil otázku názvu souboru v případě, kdy URL obsahuje pouze cestu. Wget v takovém případě doplní automaticky za název souboru „index.html“. Wget je napsán v programovacím jazyce C a je možno jej přeložit pro operační systém Linux i pro operační systém Windows. Po přepsání systémově závislých zdrojových souborů je možné program zkompilovat jako samostatný C++ projekt. Aby mohl být používaný ze C# projektů, musel být vytvořen další projekt v Mixed módu, který
40
převádí volání mezi managovaným C# kódem a nemanagovaným Wget projektem. Tento projekt se jmenuje Wgetwrap. Kód programu Wget byl částečně upraven pro odstranění varování při jeho kompilaci. Dále bylo potřeba z jeho kódu exportovat požadované funkce. Pro tento účel byl vytvořen soubor wget_export.h, který je obsažen v projektu Wget. Struktury, které jsou používány exportovanými funkcemi, do něj byly přesunuty. Zároveň byla vytvořena funkce v souboru html-url.c struct urlpos * parse_urls(const char *parent_base, const char *content, int len)
založena na existující funkci struct urlpos * get_urls_html (const char *file, const char *url, bool *meta_disallow_follow)
ale upravena pro naše potřeby – viz parametry funkce. V projektu Wgetwrap jsou vytvořeny funkce Boolean Wget::getUrls(String ^baseurl, char *html, int len, List ^list_urls) Boolean Wget::getUrls(String ^baseurl, String ^filename, List ^list_urls)
které jsou volány ze C# kódu. Tyto funkce převedou parametry z platformy .NET do typů, jenž je možno poslat do nemanagovaného C kódu a po návratu provedou opačný převod. V těchto funkcích bylo proto potřeba převést .NET String na char*. Pro projekt využívající knihovnu MFC, by bylo toto snadné pomocí třídy CString. Aby nebylo nutné kvůli jednomu převodu přidávat podporu robustního MFC, bylo toto vyřešeno bez MFC: char* baseurlchar = (char*)(void*)Marshal::StringToHGlobalAnsi(baseurl); struct urlpos *urls = parse_urls(baseurlchar, html, len); Marshal::FreeHGlobal((IntPtr)baseurlchar);
Dalším problémem se ukázalo být převedení pole Byte[] na char* v .NET kódu. Řešením je použití klíčového slova unsafe, které nám umožní práci s ukazateli, a následně klíčovým slovem fixed zakázat .NET Frameworku přesunutí objektu. Ukazatel tak zůstane po celou dobu platný (jeho použití je možné pouze v unsafe bloku). 41
try { unsafe { fixed (byte* bp = ¶m.content[0]) { Wgetwrap.Wget wget = new Wgetwrap.Wget(); wget.getUrls(param.uri.ToString(), (sbyte*)bp, param.content.Length, references); } } }
Na začátku vývoje nebylo zřejmé, jak velká část kódu bude z projektu Wget využita. Nyní je to pouze funkce pro získání odkazů a tím je použití projektu Wget zbytečně robustní řešení. Proto byl již vytvořen vlastní parser HTML odkazů. Z kódu projektu Wget byl vytvořen seznam elementů a atributů. Pro parsování značek a atributů HTML souboru byl použit Jeff Heatonův C# HTML parser. Tento kód je uložen v souboru HtmlRefUri.cs. Testy ovšem ukázaly, že Wget dosahuje lepších výsledků. Nová funkce z HtmlRefUri.cs vrací například i odkazy umístěné ve skriptech, kterých může být i poměrně hodně a které neobsahují korektní URL (jsou v nich použity proměnné apod.) Pokusy o jejich stažení pak zbytečně blokují stahující vlákna. Z toho důvodu je zatím využíváno řešení postavené na zdrojových kódech programu Wget a toto bude vyměněno až po vylepšení nově vznikajícího řešení. 5.2.3
Jeff Heatonův C# HTML parser
V souboru jeffheatonHtmlParser.cs je umístěn převzatý kód Jeff Heatonova C# HTML parseru [4]. Jak již bylo zmíněno v předchozí kapitole, kód je využit pro vývoj nového parseru HTML odkazů a také je využit třídou HtmlComparer. 5.2.4
diff.dll
Do referencí projektu je vložen odkaz na soubor diff.dll [25], který poskytuje implementaci Diffutils pro platformu .NET. Nachází se ve jmenném prostoru Algorithm.Diff. Knihovna nabízí rozhraní: namespace Algorithm.Diff { public class Diff : IDiff, IEnumerable { public Diff(IList left, IList right,
42
IComparer comparer, IHashCodeProvider hashcoder); public Diff(string leftFile, string rightFile, bool caseSensitive, bool compareWhitespace); public Diff(string[] left, string[] right, bool caseSensitive, bool compareWhitespace); public IList Left { get; } public IList Right { get; } public Patch CreatePatch(); public override string ToString(); public class Hunk : Hunk { public override bool Conflict { get; } public override int ChangedLists { get; } public Range Left { get; } public Range Right { get; } public override bool Same { get; } public public public public public public public
string DiffString(); override bool Equals(object o); override int GetHashCode(); override Range Changes(int index); override bool IsSame(int index); override Range Original(); override string ToString();
} } }
5.2.5
HtmlComparer
HtmlComparer je vlastní třída, která provádí porovnání souborů a využívá k tomu zmíněnou knihovnu diff.dll. Diagram třídy HtmlComparer a přináležejících tříd je zobrazen na obrázku „Obrázek 8 Třída HtmlComparer“. Vlastnosti třídy OldPage a NewPage obsahují dvě různé verze stránek. Je možné je naplnit samostatně přes property, nebo přímo při volání metody Compare. Stránka je při jejím nastavení zpracována. Nastavení stránky přes property by mohlo být 43
užitečné tehdy, kdyby se jedna stránka porovnávala s větším množstvím jiných. V tom případě by tato nemusela být parsována opakovaně. Pro zpracování stránky při jejím nastavení je zavolána metoda: private ComparerPage readPage(string htmlpage, bool needSync)
Tato metoda využívá Jeff Heatonův C# HTML parser pro průchod stránkou přes její elementy. Vytvoří její textovou verzi bez HTML značek a je-li nastaven příznak needSync na true, vytvoří mapování textového souboru na původní HTML. Místo každé HTML značky je vložena mezera. Důvodem je význam mezer pro algoritmus Diff, který se snaží respektovat strukturu slov a při spojení slov dohromady by zbytečně označoval více textu.
TextChanges
HtmlComparer -
htmlResult: string = null changes: TextChanges ignoredTags: List<string> = new List<string... MAX_ALLOWED_CHANGES: int = 15000 newPage: ComparerPage oldPage: ComparerPage similarity: double = -1 STYLEADDED: string = "<span style=\"... STYLEEND: string = "" STYLEREMOVED: string = "<span style=\"...
+ + + + + -
Compare(string, string) : void Compare() : void GetHtmlResult() : string joinRange(string[], Algorithm.Diff.Range) : string readPage(string, bool) : ComparerPage ResetResult() : void Similarity() : double textdiff(string, string, int) : void
«property» + NewPage() : string + OldPage() : string
-newPage
-changes
-
nodes: List
+ + +
addedText(int, int) : void Compare(ChangeNode, ChangeNode) : int removedText(int, string) : void TextChanges()
«property» + Nodes() : List
«struct» SyncNode + + +
count: int idx_original: int idx_plaintext: int
«struct» TextChanges:: ChangeNode + + +
countAdded: int idx: int strRemoved: string
-oldPage TextPageSync
ComparerPage + + +
htmlPage: string sync: TextPageSync textPage: string
+
ComparerPage(string)
+sync
-
pageSync: List<SyncNode> pageSyncIndex: int = -1
+ + +
addNextTextChange(TextChanges*, int, int, string) : Boolean addNextTextPart(int, int, int) : void TextPageSync()
Obrázek 8 Třída HtmlComparer
44
Pro mapování textové s HTML verzí souboru je určena třída TextPageSync. Při prvotním parsování stránky se naplní List pageSync opakovaným voláním metody: public void addNextTextPart(int idx_original, int idx_plaintext, int count);
Metoda dostává v parametrech pozici v HTML souboru, pozici v textové verzi souboru a počet znaků textu. Po získání výsledků porovnání se použije metoda: public Boolean addNextTextChange(ref TextChanges changes, int idx_plaintext, int addedCount, string removedStr);
která z pozice v textové verzi souboru a z druhu změny (přidaný počet znaků, či odstraněný text) vytvoří jednu či více změn do objektu changes. Na obrázku „Obrázek 9 Hledání změn v HTML stránce“ je vidět, jak z jedné změny v textové verzi mohou vzniknout dvě změny v původním HTML souboru.
HTML verze
textová verze
označení změny
přenesení změny zpět do HTML
Obrázek 9 Hledání změn v HTML stránce
Značka na obrázku může označovat jednu či více HTML značek, pokud mezi nimi není umístěn žádný text. Seznam mapování textu na HTML souboru je vytvářen postupně a od nejnižší k nejvyšší pozici v souboru. Víme tedy, že je seřazen vzestupně. Při mapování změny zpět na HTML soubor je potřeba nejprve najít konkrétní mapování, do kterého se změna strefila. K dispozici je seznam, který vypadá například takto: (0,15,5),(6,50,4),(11,53,1),(13,120,8),(22,200,20),(45,222,5)… 45
První číslo každé trojice označuje pozici v textovém souboru, druhé pozici v HTML souboru a třetí počet textových znaků. Na příkladu je také vidět, že v textové verzi je mezi každou skupinou jeden nikam nenamapovaný znak. Tímto je mezera vložená místo HTML značky. Vyhledání konkrétního mapování (zmíněné trojice čísel) probíhá pomocí metody půlení intervalu a obsahuje optimalizaci, kdy si za pomoci členské proměnné zapamatuje poslední použitý prvek. Následující vyhledávání pokračuje od něj, případně od příštího v řadě. Vzhledem k tomu, že i změny v textovém souboru přicházejí na řadu postupně od začátku souboru, je pravděpodobnější že se trefíme takto, než kdybychom začínali v polovině seznamu. Je třeba dát si v kódu pozor na vložené mezery s tím, že změna může na této mezeře i začínat. Samotné porovnání probíhající v metodě Compare má dvě úrovně. Nejdříve jsou soubory porovnány po celých řádcích. Změněné řádky jsou poté spojeny do jednoho řetězce, které jsou porovnány na změny v jednotlivých znacích. Tento přístup s sebou přináší riziko větší náročnosti při velkém počtu změněných řádků a bylo by vhodné jej v budoucnu optimalizovat. Nyní jsou obsaženy optimalizace typu převedení na jednotný typ ukončení řádků (pouze CR) a přidáno odřádkování za každou tečku či čárku v textu, která je následována bílým znakem. Tato optimalizace byla inspirována generovanými soubory ze serveru seznam.cz, který obsahuje velmi dlouhé řádky s pár změnami uprostřed. Tím docházelo ke spojení celého textu do jednoho dlouhého řádku, který byl porovnáván po jednotlivých znacích, což prodloužilo dobu porovnání. Po dokončení metody Compare lze zavolat metodu GetHtmlResult, která sestaví ze seznamu změn upravený HTML soubor. Okolo přidaných částí textu doplní značku <span> měnící formát textu na oranžové pozadí, případně doplní odebrané kusy textu o styl s přeškrtnutím a červeným pozadím. Při sestavování nového HTML souboru je sečten počet přidaných a odstraněných znaků z textu. Na základě těchto čísel je spočtena podobnost verzí. Výpočet podobnosti: L = délka nového textu A = počet přidaných znaků D = počet odebraných znaků Similarity = (L - A)/(L + D) Výpočet vrací číslo v intervalu <0,1> a po vynásobení stem vyjadřuje procento neoznačených znaků ve vráceném textu (A i D jsou označené znaky). 46
5.3
Uživatelské rozhraní
Uživatelské rozhraní je popsáno v přiložené uživatelské dokumentaci na konci práce. Jeho kód je umístěn v samostatném projektu WPApp, který je s výkonným kódem provázán co nejmenším počtem metod. Díky nezávislosti funkční části jde tento modul snadno nahradit. Tak je možné například vytvořit www rozhraní či rozhraní ovládané pouze pomocí příkazového řádku. Byl kladen velký důraz na vytvoření praktického, funkčního a zároveň esteticky příjemného uživatelské prostředí, které odolá nevhodným zásahům ze strany uživatele.
5.4
Přehled knihoven a zdrojových kódů
Zdrojové kódy jsou sdruženy do společné solution Microsoft Visual Studia 2008 a rozděleny do následujících projektů: NCharDet -
převzatý C# projekt na detekci kódování [8]
Parse.Html -
vlastní C# projekt implementující plugin pro rozpoznávání změn v HTML dokumentech a vracející seznam odkazů ze zadaného HTML souboru
-
projekt obsahuje jeden cizí soubor: jeffheatonHtmlParser.cs, určení pro parsování HTML stránek
-
odkazuje se na projekt NCharDet, cizí knihovnu diff.dll a vlastní projekt Wgetwrap
WebPatrol -
vlastní C# projekt, který obsahuje jádro celé aplikace
-
odkazuje se na projekt WPPlugin
Wget -
převzatý C projekt doplněný o soubory wget_export.h a wget_export.cpp a o změny které umožnili používání projektu z této aplikace
Wgetwrap -
vlastní C++ projekt použitý na zpřístupnění vyexportovaných funkcí z projektu Wget v C# projektech
-
odkazuje se na projekt Wget
47
WPApp -
vlastní projekt generující spustitelný soubor a implementující uživatelské rozhraní aplikace WebPatrol
-
odkazuje se na projekt WebPatrol a WPPlugin
WPPlugin -
vlastní projekt obsahující rozhraní pro vytváření pluginů
48
6
Vývoj a testování
Program byl vyvíjen a testován na počítači s Windows 7 64bit, 8GB RAM a čtyřjádrovým procesorem. Aplikace byla testována i na virtuálním počítači s Windows Vista 32bit a Windows XP. K dispozici bylo internetové připojení s maximální rychlostí 2Mbps pro příjem dat a 2Mbps pro vysílání dat. Na stejném počítači byl nainstalován rovněž MS SQL server 2005 ve verzi EXPRESS. Tomuto serveru bylo třeba ručně nastavit omezení paměti, neboť pravděpodobně vzhledem k velikému počtu vyměňovaných dat docházelo k vyčerpání paměti. Program byl testován v průběhu celého vývoje. Největší stažený objem dat pro jeden úkol byl 10GB v 370ti tisících souborech. Zajímavé je, že pro tento výsledek stačilo vytvořit úkol s počáteční URL http://seznam.cz/, bez omezení hostname, maximální hloubkou stahování 3 a maximální velikostí jednotlivého souboru 10MB. Detailní informace o výsledku aktualizace této úlohy z logu: 4.4.2010 10:04:46 Watch download finished. (http://seznam.cz/) * new downloaded: 218397, unchanged: 37871, ignored7: 15, errors: 18523, new bytes: 6293,17M, in: 09:06:24
Ke zmíněné úloze bylo provedeno porovnání změn a porovnáno 50 tisíc souborů o celkové velikosti 1,7GB, které byly staženy v obou verzích. Porovnání trvalo 90 minut, tedy rychlostí 550 souborů o průměrné velikosti 34KB za minutu. Detailní informace o výsledku porovnání této úlohy z logu: 4.4.2010 22:03:53 Watch comparison finished. (http://seznam.cz/) * changed: 25155, unchanged: 23829, ignored8: 965, errors: 0, processed bytes: 1690,93M, in: 01:30:31
Ukázky porovnání změn z této úlohy je možné nalézt v kapitole 9.6 Porovnávání souborů. Při vývoji byl využit nástroj SVN pro správu verzí což pomohlo udržovat kvalitnější kód sjednocováním změn do logických celků a rekapitulacím změn před uložením (check-in) na server. Zároveň tento systém umožňuje nebát se dramatičtějších změn, neboť je kdykoli možné vrátit se k předchozí verzi. Veškeré komentáře v kódu a názvy objektů jsou autorem vedeny v anglickém jazyce.
7 8
soubory, které nevyhověly filtru maximální velikosti 10MB soubory, které HTML plugin nedokázal porovnat – nepodporovaný formát
49
7
Další vývoj programu
Vytvořená aplikace, je otevřená dalšímu vývoji. Pro tento účel využívá přehledná a srozumitelná rozhraní. Kód byl psán s ohledem na čitelnost, snadnou orientaci a rozšiřitelnost. Rozšiřitelnosti napomáhá i struktura aplikace v podobě relativně malého jádra, doplněného o jednotlivé pluginy. V tomto směru by aplikaci bylo vhodné rozšířit např. o další pluginy, specializované na různé formáty souborů. Tato a podobná rozšíření sebou nesou další dodatečné požadavky na potřebu řízení těchto pluginů, např. určení pořadí jejich spuštění, a jejich detailnějšího nastavení, odstavení, či naopak nastartování. Rychlosti porovnávání by prospěla podpora rozpoznávání typů souborů z jejich obsahu, díky které by mohl být více restriktivně prováděn výběr souborů pro porovnání. Řešení bylo navrženo v kapitole „2.3 Rozpoznání formátu souboru“, ale nebylo z časových důvodů implementováno. Další vylepšení by mohlo představovat vytvoření souhrnného HTML reportu o výsledcích porovnání úkolu či zavedení složek do seznamu souborů úkolu. Data by mohla být ze serverů stahována automaticky v zadaný čas, aby uživatel nemusel jednotlivá stažení iniciovat manuálně. Efektivitě ukládání stažených dat by pomohlo jejich ukládání až v případě první zjištěné změny (například porovnáním MD5 k předchozímu neuloženému stažení). Toto opatření by snížilo nároky na objem uložených souborů, neboť lze předpokládat, že se řada objektů pravděpodobně nikdy nemění, ale přišli bychom tak o první změnu.
50
8
Závěr
I bez implementace bodů, zmíněných v předchozí kapitole, se podařilo vytvořit produkt, který vyhovuje zamýšlenému účelu stahování webových serverů, jejich offline ukládání a porovnávání změn stránek v průběhu času. Byla vyřešena a dosažena většina cílů, které byly navrženy v kapitole 2, a pro zbytek bylo navrženo vhodné řešení. Bylo vytvořeno 370 KB autorského kódu a využito dalších čtyř cizích knihoven pro vytvoření komplexní aplikace. V současné době není k dispozici žádný volně šiřitelný produkt, hledající či zvýrazňující změny HTML souborech a žádný produkt provádějící porovnání změn webových serverů v takovém rozsahu jako navržené řešení. Ve srovnání s komerčními aplikacemi zmíněnými v analytické části práce nabízí kromě volně dostupného kódu také možnost vytváření vlastních pluginů pro zpracování vstupních souborů. Díky využití SQL databáze pro správu dat je schopen lépe pracovat s velkými objemy dat v řádech GB a v neposlední řadě se aplikace pokouší o nový přístup, který neimplementuje žádný z nalezených programů, a to zavedení časových řezů a jejich vzájemné porovnání. Na aplikace, které jsou již roky ve vývoji sice ztrácí počtem drobných a specifických nastavení, ty ovšem budou vznikat průběžně s potřebami konkrétních uživatelů.
51
Citovaná literatura [1] Zákon č. 121/2000 Sb., o právu autorském a jeho úpravy [Online] http://www.mkcr.cz/cz/autorske-pravo/zakon/predpisy-zakonu-7611 [2] GNU Wget. [Online] http://www.gnu.org/software/wget/ [3] HTTrack [Online] http://www.httrack.com [4] Heaton, Jeff. Parsing HTML in Microsoft C#. [Online] http://www.developer.com/net/csharp/article.php/2230091 [5] UTF8. ISO 10646-1:2000 Annex D, v RFC 3629 a v Unicode 4.0. [6] Microsoft MLang API. [Online] http://msdn.microsoft.com/en-us/library/aa741220(vs.85).aspx [7] How to build standalone universal charset detector from Mozilla source. [Online] http://www.mozilla.org/projects/intl/detectorsrc.html [8] Li, Shanjian a Momoi, Katsuhiko. A composite approach to language/encoding detection. [Online] http://mxr.mozilla.org/mozilla/source/extensions/universalchardet/doc/Universal CharsetDetection.doc [9] Hala, Jiří. Download se správným Content Type v ASP.NET. [Online] http://interval.cz/clanky/download-se-spravnym-content-type-v-asp-net/ [10] HTML Match. [Online] http://www.htmlmatch.com/ [11] ComponentSoftware HTMLDiff Control. [Online] http://www.componentsoftware.com/products/DiffControl/index.htm [12] Compare Two HTML Files or Websites & Find Differences Software 7.0. [Online] http://www.sobolsoft.com/comparehtml/ [13] GNU Diffutils. [Online] http://www.gnu.org/software/diffutils/diffutils.html [14] KDiff3. [Online] http://kdiff3.sourceforge.net/ [15] Qt – A cross-platform application and UI framework [Online] http://www.qtsoftware.com [16] WinMerge. [Online] http://winmerge.org/ [17] Subversion - an open source version control system [Online] http://subversion.tigris.org [18] Mozilla Gecko. [Online] http://developer.mozilla.org/en/docs/Gecko_SDK
52
[19] The WebKit Open Source Project [Online] http://webkit.org/ [20] HTML Tidy Library Project [Online] http://tidy.sourceforge.net/ [21] XMLUnit - JUnit and NUnit testing for XML [Online] http://xmlunit.sourceforge.net/ [22] The Apache Xerces XML Parser Project [Online] http://xerces.apache.org/xerces-c/ [23] Doxygen [Online] http://www.stack.nl/~dimitri/doxygen/ [24] Wget Visual Studio 2005 projekt. [Online] http://www.christopherlewis.com/WGet/WGetFiles.htm [25] Diff/Merge/Patch Library for C#/.NET. [Online] http://occams.info/code/diff/ [26] C# Wrapper na Microsoft MLang API. [Online] http://www.codeproject.com/KB/recipes/DetectEncoding.aspx [27] C# port of Mozilla universal charset detection. [Online] http://www.conceptdevelopment.net/Localization/NCharDet/
53
Seznam Obrázků Obrázek 1 Základní schéma propojení modulů ........................................................................... 23 Obrázek 2 Komunikace hlavních objektů ...................................................................................... 28 Obrázek 3 Třída Watch ......................................................................................................................... 29 Obrázek 4 Fronty stahování souborů .............................................................................................. 31 Obrázek 5 třída WatchFile ................................................................................................................... 34 Obrázek 6 MSSQLProvider databázové tabulky.......................................................................... 37 Obrázek 7 HTML Plugin ........................................................................................................................ 40 Obrázek 8 Třída HtmlComparer ........................................................................................................ 44 Obrázek 9 Hledání změn v HTML stránce ..................................................................................... 45 Obrázek 10 Připojení na databázový server................................................................................. 57 Obrázek 11 Vytvoření nové databáze ............................................................................................. 58 Obrázek 12 Hlavní okno aplikace ..................................................................................................... 58 Obrázek 13 Vytvoření/editace úkolu .............................................................................................. 60 Obrázek 14 Menu hlavního okna aplikace .................................................................................... 64 Obrázek 15 Kontextové menu úkolu ............................................................................................... 64 Obrázek 16 Dialogové okno se seznamem souborů .................................................................. 65 Obrázek 17 Uživatelský filtr nad seznamem souborů .............................................................. 66
54
9
Uživatelská dokumentace
9.1
Instalace Microsoft SQL Express
Současná verze pracuje pouze nad databázovým serverem Microsoft SQL, který je možné zdarma získat ve verzi EXPRESS9. Verze EXPRESS má ovšem následující omezení: Velikost jedné databáze (MDF soubor) je omezena na 4 GB. Do této velikosti se nezapočítává velikost transakčního logu (LDF soubor). Je využíván pouze jeden procesor. Je využíván maximálně 1 GB operační paměti. Neobsahuje službu SQL Server Agent (pro spouštění úloh a správu plánů). Neobsahuje žádnou "enterprise feature", jako například: OLAP, Integration Services (SSIS), Notification Services, Report Builder, Log shipping, Database Mirroring, Fail-over Clustering apod. Instalace vyžaduje Microsoft .NET Framework 3.5 a pro správu databáze je možné volně stáhnout grafický nástroj Microsoft SQL Server Management Studio Express10. Všechny zmíněné programy jsou přiloženy na CD v podadresáři 3rdParty. dotnetfx35sp1.exe
Microsoft .NET Framework 3.5 SP1
MSSQL\SQLEXPR32_SP3.EXE
SQL Server 2005 Express Edition SP3
MSSQL\SQLServer2005_SSMSEE.msi Microsoft SQL Server Management Studio Express MSSQL\SQLEXPR_ADV_SP3.EXE
SQL Server 2005 Express Edition with Advanced Services SP3 – instalátor spojující SQL Server 2005 Express Edition SP3, Microsoft SQL Server Management Studio Express a další utility jako
9
http://www.microsoft.com/Sqlserver/2005/en/us/express-down.aspx
10http://www.microsoft.com/downloads/details.aspx?familyid=C243A5AE-4BD1-4E3D-94B8-
5A0F62BF7796&displaylang=en
55
Reporting Services a Full-Text Search do jednoho balíčku
Při instalaci serveru na localhost stačí zachovat přednastavené parametry. Server tak bude nainstalován v módu Windows Authentication pod jménem SQLEXPRESS. Následné připojení tedy proběhne na server „localhost\SQLEXPRESS“. Pro vytvoření nové databáze jsou potřeba práva, která nejsou uživateli přiřazena automaticky. Nejjednodušší je přidat aktuálního uživatele do role administrátora databázového serveru. Toto je možné při instalaci zvolením volby „Add user to the SQL Server Administrator role“, nebo posléze spuštěním „SQL Server Surface Area Configuration“ (je přidáno do Start menu Windows), kliknutím na „Add New Administrator“ a přidáním role aktuálnímu uživateli. Express Edice SQL serveru nemá implicitně povolen přístup z jiného počítače. Pro vzdálený přístup je ještě potřeba provést následující úkony11 (předpokládáme, že instance SQL serveru je nazvána SQLEXPRESS): -
povolit vzdálené připojení o spustit SQL Server 2550 Surface Area Configuration o vybrat Surface Area Configration for Services and Connections o nastavit Local and remote connections pod SQLEXPRESS\Database Engine\Remote Connections
-
povolit TCP/IP adresy rozhraní, ze kterého mají být přijímána spojení o spustit SQL Server Configuration Manager o otevřít vlastnosti položky TCP/IP pod SQL Server 2005 Network Configuration\Protocols for SQLEXPRESS o přepnout na záložku IP Adresses o nastavit Enabled na Yes pro žádané adresy
-
pokud není server ve společné doméně, kde by bylo možné využít Windows autentikaci je potřeba povolit Server authentikaci a vytvořit uživatele či povolit uživatele sa
pouze náznak v základních krocích – bližší informace lze nalézt v dokumentaci k Microsoft SQL serveru 11
56
o spustit SQL Server Management Studio Express a přihlásit se o otevřít vlastnosti SQL serveru o pod položkou Security nastavit Server authentication na SQL Server and Windows Authentication mode o v hlavním okně pod SQLEXPRESS\Security\Logins otevřít vlastnosti uživatele sa (případně jiného) a toho na stránce Status povolit – nastavit Login na Enabled -
9.2
restartovat databázový server
Instalace programu WebPatrol
Samotný program WebPatrol nevyžaduje instalaci. Stačí zkopírovat z CD adresář WebPatrol a spustit v něm umístěný soubor WPApp.exe.
9.3
Připojení
Po spuštění aplikace musí nejprve dojít k úspěšnému přihlášení na databázový server, kde jsou uložena a ukládána veškerá data zpracovávaná aplikací. Aplikace podporuje dva druhy autentizace: „Windows Authentication“ a „SQL Server Authentication“.
Obrázek 10 Připojení na databázový server
Dialog nabízí pro zefektivnění častého spouštění aplikace možnost uložení hesla automatické přihlášení s posledními nastavenými parametry. Pokud se automatické 57
přihlášení nepodaří, zobrazí se přihlašovací dialog. Pokud si uživatel přeje změnit server po automatickém přihlášení stačí v hlavní aplikaci zvolit z hlavního menu Database položku Disconnect viz. 9.4.6 Menu aplikace. Neexistuje-li po připojení na server databáze programu WebPatrol, nabídne program její vytvoření.
Obrázek 11 Vytvoření nové databáze
9.4
Hlavní okno aplikace
Obrázek 12 Hlavní okno aplikace
58
Po přihlášení je k dispozici hlavní okno aplikace, které sdružuje seznam úkolů (Watch), což je konkrétní nastavení stahované a kontrolované části internetového serveru. V dolní části aplikace je logován výstup běhu aplikace. Log je možné zavřít, vymazat, či z menu nastavit podrobnost logování v několika úrovních. Pravá část tohoto logu, zvýrazněná jinou barvou, zobrazuje stav právě probíhající aktivity vybraného úkolu – stahování dat z Internetu nebo srovnávání změn. Akce nad jednotlivými úkoly lze vyvolat z menu či z kontextového menu aplikace, případně lišty s ikonami. Zvolená akce se vztahuje, pokud je toto možné, k aktuálně vybranému úkolu v seznamu úkolů. 9.4.1
Definice úkolu a akcí nad ním
Úkol je definován: -
počáteční URL
-
požadovanou hloubkou stahování
-
maximální velikost stahovaných souborů
-
nastavením, zda mají být stahovány i odkazy vedoucí mimo rámec domény výchozího požadavku
-
popis úkolu (libovolná poznámka pro uživatele programu)
-
URL filtry a dalšími podrobnějšími parametry stahování (tyto jsou rozebrány v kapitole 9.4.2 Vytvoření/editace úkolu)
Ke každému úkolu mohou existovat dvě stažené, které lze porovnávat. Nejprve je nutné vytvořit a stáhnout12 verzi aktuální (Current) a tu ve zvoleném okamžiku převést na neměnnou verzi (Snapshot) vůči které budou probíhat budoucí srovnání. Po převedení na Snapshot lze opět vytvořit aktuální otisk sledované části Internetu, který je možné kdykoli aktualizovat, či opět zafixovat převedením na Snapshot. Úkoly jdou vytvářet, editovat, mazat, lze spustit nebo zastavit stahování jejich aktuální verze. Je možné vytvořit Snapshot z aktuální verze (viz výše), provádět porovnání a zobrazit seznam souborů, které jsou pro daný úkol uloženy.
Soubory, u kterých nedošlo k žádné změněny, jsou v databázi drženy pouze v jedné kopii a pokud je toto možné rozpoznat předem, nejsou ani znovu stahovány z internetu. 12
59
9.4.2
Vytvoření/editace úkolu
Vytvoření a editace nového úkolu probíhá ve společném dialogu. Jméno úkolu, popis úkolu a parametry stahování je možné upravovat kdykoli, aniž by to mělo vliv na výsledky porovnávání. Parametry, které mohou výsledky porovnání ovlivnit, lze měnit pouze na výslovné přání uživatele, po zatržení checkboxu v dolní části dialogu (Enable to edit all values – changes will probably cause different downloads). Tento checkbox je viditelný pouze v případě editace již vytvořeného úkolu – při vytváření nového je automaticky možné editovat všechna pole.
Obrázek 13 Vytvoření/editace úkolu
Následuje podrobnější rozbor některých položek nastavení: Nastavení položky Follow just references to the starting server znamená, že stahování nebude pokračovat žádným odkazem, který vede mimo tento server z počátečního URL. Není-li toto dostatečné, je možné daleko přesnějšího nastavení pomocí regulárních výrazů13. Prostřednictvím Regular expressions - Match URL to follow a Match URL to keep lze definovat přesné filtry nad procházenými URL. Každý odkaz je nejprve
13
řetězec popisující celou množinu řetězců, konkrétně regulární jazyk
60
testován na shodu se zadaným regulárním výrazem a podle výsledku testování pak může být stažen pro získání dalších odkazů, případně uložen do databáze pro následující srovnání. Například lze definovat stahování a procházení všech souborů z domény seznam.cz nastavením regulárního výrazu „to follow“ na hodnotu „http://([^/]*\.)*seznam\.cz“ a v databázi uchovat pro pozdější porovnání pouze stránky, které v URL obsahují text „warez“ (nastavením hodnoty „Match URL to keep“ na „warez“). Nebo do databáze stáhnout stránky z celé domény cz, které v URL obsahují libovolné slovo ze zadaného seznamu „(slovo1|slovo2|slovo3)” atd. viz široké možnosti regulární výrazů. Dále je možné nastavit Credential – pro servery, které vyžadují ověření (nejsou-li tyto definovány, pak je pro odkaz vedoucí na FTP server automaticky použit user anonymous) Maximal file size (in Kbytes) – není-li předem známa velikost stahovaného souboru, je toto stahování ukončeno při dosažení zvolené velikosti Maximal level to download – maximální hloubka odkazů, která bude sledována Simultaneous downloads – počet zároveň stahovaných souborů – čím větší je toto číslo, je zapotřebí více systémových prostředků a tedy záleží na stoji, na kterém aplikace běží, jaké možnosti v tomto směru nabízí Number of retries – počet pokusů o stažení každého souboru (v případě specifických chyb, jako neexistence souboru či neautorizovaný přístup na toto není brán ohled) 9.4.3
Stahování úkolů
Stahování úkolů je jedna ze dvou akcí, které mohou nad vytvořeným úkolem probíhat. Akce běží po spuštění na pozadí a je možno během ní prohlížet a editovat veškeré úkoly. Editace probíhajícího úkolu nemá již na běh stahování vliv – je stahován podle parametrů platných při spuštění akce. Probíhající akci lze zrušit (viz níže), či spouštět akce na ostatních úkolech. Průběh akce je možné sledovat, po vybrání úkolu z listu úkolů, v pravé části logu, nebo, podle nastavení způsobu logování, i kontrolními výpisy v levé části logu (viz kapitola 9.4.5 Logování). Stav úkolu je zobrazen v seznamu úkolů a může nabývat následujících hodnot: Empty – nově vytvořený nebo prázdný úkol (po akci Clear) 61
Downloading – probíhající akce stahování aktuální verze úkolu Comparing – probíhající akce porovnávání úkolu Canceled – úkol po zrušení stahování Finished – úspěšně stažený úkol Error – tento stav je nastaven po pádu aplikace v případě, že právě probíhalo stahování úkolu Locked – na úkolu právě probíhá akce (stahování či porovnávání) z jiného klienta V okně se seznamem souborů úkolu lze průběžně sledovat seznam stažených souborů – načtený seznam je aktuální vzhledem k průběhu stahování. Jak již bylo zmíněno, stahování probíhá vždy do aktuální verze, kterou je posléze možné převést (např. z menu Watch - Make Snapshot from Current) na speciální Snapshot verzi vůči které probíhá porovnávání aktuálně stažené verze (Current). Probíhající akci je možné zastavit (např. z menu Watch – Stop) s tím že je vyprázdněna fronta stránek čekajících na stažení/porovnání. Aktuální stahování jsou stornována, ale může chvíli trvat, než se vyprázdní fronta aktivních souborů – například pokud některá vlákna čekají na odpověď od internetového serveru, nebo než dokončí práci právě porovnávající plugin. 9.4.4
Porovnávání dat úkolu
Po vytvoření Snapshot a aktuální (Current) verze je možné porovnávat stažené soubory. Jednotlivá porovnání včetně případného výstupu konkrétního porovnání jdou provést z dialogu se seznamem souborů úkolu. Z hlavního menu lze nechat hromadně spočítat podobnost (Similarity) stažených souborů a to dvěma způsoby. Update Comparison – dopočítá podobnost pouze u souborů, u nichž ještě nebyla ještě spočítána Full Comparison – přepočítá podobnost u všech souborů zadaného úkolu Není možné porovnávat úkoly, které jsou ve stavu Canceled nebo Error – ty by měly být opětovně staženy, aby nedocházelo k nesprávnému zobrazení seznamu nových, respektive smazaných souborů. Pro uživatele může být někdy žádoucí akceptovat i takovýto neúplný stav a proto je v kontextovém menu (ale pouze tam) umístěna položka Accept state as finished, která převede takovýto stav na Finished a umožní spuštění hromadného porovnání souborů i u nedokončeného úkolu. 62
Akce porovnání stejně jako akce stažení probíhá na pozadí, a to v několika současných vláknech, aby se urychlilo zpracování na počítačích, které toho umějí využít. Pro její zastavení je možno použít příkazu Stop Activity a zastavit průběh zpracování. Kdykoli může být porovnání dokončeno pomocí Update Comparison, u kterého dochází k dopočítání pouze neporovnaných souborů. 9.4.5
Logování
V dolní části hlavního okna aplikace je prostor pro zobrazování stavu probíhajících akcí. Tato část (log) může být z menu View schována, zobrazena či vymazána, nebo může být vybrána podrobnost logovaných výpisů ve čtyřech krocích z comboboxu: None – žádné kontrolní výpisy Basic – pouze zahájení a ukončení akcí More – Basic + výpis neúspěšně stažených stránek Detailed – More + výpis všech stránek přidaných do fronty na stažení, úspěšně stažených, ignorovaných (neuložených do databáze), nezměněných, zrušených (po zastavení akce) Detailní logování provádí opravdu mnoho výpisů a není proto doporučeno zapínat ho na úkoly, jejichž stahování probíhá v mnoha vláknech a u kterých se očekává velké množství stahovaných souborů. Může dojít k velkému zatížení počítače a aplikace pak nemusí být schopna reagovat na uživatelské vstupy. V pravé části logovacího prostoru je zobrazován stav akce aktuálně vybraného úkolu v několika atributech: waiting files – počet souborů čekajících na zpracování (stahování nebo porovnávání) active files – počet právě zpracovávaných souborů (stahování nebo porovnávání) unchanged files – počet zpracovaných souborů, které nebyly změněny ignored files – počet ignorovaných souborů (na základě parametrů úkolu – například soubor nevyhovuje „URL to keep“), nebo souborů, které pluginy pro porovnání nebyly sto porovnat errors – počet souborů, které se nepodařilo stáhnout processed files – počet stažených souborů
63
processed bytes – velikost dat stažených/porovnaných souborů Do processed bytes je přičítána i velikost dat aktuálně probíhajících stahování, aby byla zároveň kontrola aktivního průběhu. 9.4.6
Menu aplikace
Obrázek 14 Menu hlavního okna aplikace
Většina položek menu je intuitivní či popsaná v předcházejícím textu. Doplníme tedy pouze položky z menu Database: Disconnect – odpojí program od aktuální databáze a nabídne nové přihlášení. V případě, že právě probíhají akce nad některými úkoly, nabídne jejich zastavení Drop and create new – smaže celou databázi programu WebPatrol a vytvoří novou včetně všech potřebných tabulek
Obrázek 15 Kontextové menu úkolu
64
Na obrázku „Obrázek 15 Kontextové menu úkolu“ jsou zachyceny dvě různé varianty nabídky kontextového menu nad úkolem. Je zde vidět kontextové menu ke stavu, kdy úkol není správně dokončen a kontextové menu k dokončenému či akceptovanému úkolu.
9.5
Seznam souborů úkolu – Watch Files
Obrázek 16 Dialogové okno se seznamem souborů
Položky seznamu tohoto dialogového okna obsahují URL, velikost, čas a datum Snapshot i Current verze, míru podobnosti verzí a sloupec extras, kde [s] označuje existenci verze Snapshot, [c] existenci verze Current v případě, že se soubory jeví identické (mají stejnou MD5), je mezi těmito vloženo „=“. Není-li v extras uvedeno [s] znamená to, že byl soubor nově vytvořen a naopak, není-li uvedeno [c] byl soubor pravděpodobně odstraněn. V dolní části okna je opět logovací část, kterou je možno skrýt a ve které se zobrazuje informace o zahájení/ukončení porovnání položky a jeho výsledek. Míra podobnosti je číslo v rozsahu <0,1> kde 0 je nejméně, 1 nejvíce, ale záleží na konkrétním pluginu jak přesně dojde k jeho výpočtu. 65
Na liště ve spodní části okna je zobrazen počet zobrazených souborů (tedy souborů vybraných filtrem)/celkový počet souborů úkolu. V závorce je počet zobrazených souborů rozdělen do skupin equal, updated, deleted a new. Equal jsou soubory se stejnou MD5. Na konci řádku je spočtena celková velikost v bytech verze Snapshot a Current zobrazených souborů. Aktuálně zobrazené soubory se odvíjí od filtru vybraného z comboboxu nad seznamem souborů. Z menu či kontextového menu lze, kromě Refresh, Show/hide log a Compare, vyvolat akce Save Current as… Save Snapshot as… pomocí kterých lze uvedené verze souborů uložit a zpracovat libovolnou další aplikací. 9.5.1
Filtry nad seznamem souborů Show all Show equal [s]=[c] Show different (Similarity<1) Show delete Show new Custom
Seznam obsahuje rychlé filtry, nebo uživatelské nastavení v Custom dialogu.
Obrázek 17 Uživatelský filtr nad seznamem souborů
Výhodou spojitého intervalu pro podobnost (Similarity) je možnost používání otevřeného/uzavřeného intervalu. Tak je například řešen rychlý filtr „Show 66
different“, který vybere pouze soubory z jednostranně otevřeného intervalu <0, 1) Similarity.
9.6
Porovnávání souborů
S programem je vytvořen plugin, který slouží primárně k porovnávání HTML souborů, ale protože zatím nejsou k dispozici další pluginy je nyní využíván pro veškerý vstup, který dokáže zpracovat. Jeho výstupem je soubor doplněný o HTML značky, které označují změny – červeně a přeškrtnutím (v černobílém textu tmavší zvýraznění podkladu) jsou místa, která byla z textu odstraněna a oranžovým podkladem místa, která byla do textu přidána (v černobílém textu světlejší zvýraznění podkladu). Více k porovnání v implementační části. Pro zobrazení porovnání slouží položka Compare z menu nebo kontextového menu. 9.6.1
Příklady vyznačení změn
V diskuzi je 413 příspěvkyů | přidat další příspěvek14
14
text „4 příspěvky“ se změnil na „13 příspěvků“
67
68
9.7
Ukončení aplikace
Aplikaci je možné ukončit uzavřením hlavního okna nebo z menu File – Exit. Jestliže jsou při ukončení aplikace aktivní úkoly, program nabídne jejich zastavení a následně je nutné počkat na dokončení všech aktivních vláken. V případě stahování je možné čekat na timeout neúspěšného požadavku na vyžádané URL, v případě srovnávání na dokončení akce externího pluginu.
9.8
Dodatky k uživatelskému rozhraní a práci aplikace
U obou seznamů je možné řazení podle sloupců. Provede se kliknutím na sloupec a opakované kliknutí mění směr řazení. Hlavní dialog aplikace a dialog se seznamem souborů mohou být otevřeny zároveň. Dialog se seznamem souborů není modální, a tudíž lze pracovat s oběma najednou. Seznam souborů je aktualizován pouze příkazem Refresh, respektive požadavkem na zobrazení seznamu jiného úkolu, neboť při velikém počtu souborů může načtení z databáze chvíli trvat. Akce nad úkoly – stahování či porovnávání – probíhají paralelně a ve více vláknech zároveň. Porovnávání každého úkolu probíhá standardně v 16ti vláknech a stahování dle nastavení úkolu. Počet vláken je vhodné volit střízlivě vzhledem ke konfiguraci počítače. Je-li na stejném počítači nainstalován i MS SQL server je vhodné v nastavení tohoto serveru omezit maximální využívanou paměť. Díky množství dat vyměňovaných s databázovým serverem, dochází k alokování velkého množství paměti a snadno může dojít k jejímu vyčerpání.
9.9
Pokročilá nastavení programu
Program ve svém adresáři obsahuje XML soubor, který je možné editovat a nastavit parametry, které jinak nejsou přístupné přímo z uživatelského rozhraní. Tyto hodnoty je doporučeno měnit pouze zkušeným uživatelům. Soubor se jmenuje WPApp.ini a nastavení, která nejsou přístupná z UI jsou:
Pokud obsahuje název souboru, je do tohoto zapisováno logování dle nastavení. Na rozdíl od logovacího panelu aplikace není omezeno počtem řádků – viz následující parametr.
69
<WPMaxLogLines>
Maximální počet řádků logovacího panelu programu. Standardně přednastaveno na hodnotu 200, neboť při velké podrobnosti logování je generováno velké množství textu, což posléze vede ke zpomalení programu a vyčerpání paměti.
<UserAgentString>
Řetězec, kterým se program identifikuje vůči webovým serverům při stahování dat.
Maximální počet vláken použitých k porovnání jedné úlohy.
Doba v milisekundách za kterou vyprší požadavek na stažení souboru z internetového serveru.
Velikost zásobníku pro stahování dat z internetového serveru v bytech. pod položkou : <UseAbsoluteUri>
Booleovská hodnota zapínající převod všech relativních adres v porovnaném výsledku na absolutní.
<MaxAllowedChanges>
Maximální počet změn, po jehož dosažení bude soubor při porovnávání ignorován.
<StyleRemoved>
Kód v HTML formátu, odstraněný text.
<StyleAdded>
Kód v HTML formátu, který bude vložen před přidaný text.
<StyleEnd>
Kód v HTML formátu, který bude vložen za přidaný nebo odstraněný text.
70
který
bude
vložen
před