diff --git a/bibliografia.bib b/bibliografia.bib index 61eafa8..dcbcc6b 100644 --- a/bibliografia.bib +++ b/bibliografia.bib @@ -60,6 +60,7 @@ Fourteenth International Conference on Computational Linguistics, Nantes, France @misc{binaryornot} @misc{html2text} @misc{markdown} +@misc{scrapy} @article{parallel, title = {GNU Parallel - The Command-Line Power Tool}, author = {O. Tange}, diff --git a/diagramy/struktura_programu.xml b/diagramy/struktura_programu.xml index 10c7018..0af012b 100644 --- a/diagramy/struktura_programu.xml +++ b/diagramy/struktura_programu.xml @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/img/amb_text_search.png b/img/amb_text_search.png index 97b19a5..0f466eb 100644 Binary files a/img/amb_text_search.png and b/img/amb_text_search.png differ diff --git a/img/crawler.png b/img/crawler.png index 2626026..d88e852 100644 Binary files a/img/crawler.png and b/img/crawler.png differ diff --git a/img/crawler_adresow.png b/img/crawler_adresow.png index ec1d0c3..3a2b20b 100644 Binary files a/img/crawler_adresow.png and b/img/crawler_adresow.png differ diff --git a/img/crawler_adresow_trans.png b/img/crawler_adresow_trans.png index 2145b9a..81764fc 100644 Binary files a/img/crawler_adresow_trans.png and b/img/crawler_adresow_trans.png differ diff --git a/img/crawler_parafii_general.png b/img/crawler_parafii_general.png index cf86fff..175073e 100644 Binary files a/img/crawler_parafii_general.png and b/img/crawler_parafii_general.png differ diff --git a/img/crawler_url.png b/img/crawler_url.png index a646a14..b480e38 100644 Binary files a/img/crawler_url.png and b/img/crawler_url.png differ diff --git a/img/crawler_url_trans.png b/img/crawler_url_trans.png index 5e2fe50..742229a 100644 Binary files a/img/crawler_url_trans.png and b/img/crawler_url_trans.png differ diff --git a/pakiety.tex b/pakiety.tex index 4ad5ba7..ddaed02 100644 --- a/pakiety.tex +++ b/pakiety.tex @@ -1,5 +1,7 @@ -\usepackage[OT4]{polski} % tryb pelnej polonizacji \usepackage[utf8]{inputenc} % kodowanie +\usepackage{lmodern} %latin modern fonts +\usepackage[T1]{fontenc} % ulepszona wersja czcionek dla polski, OT4 jest stare +\usepackage{polski} \usepackage{makeidx} % indeks \usepackage[pdftex]{graphicx} % zalaczanie grafiki \usepackage{tikz} % grafika wektorowa @@ -23,6 +25,7 @@ \usepackage{url} % url w bibliografii \usepackage{amsmath} \usepackage{amsthm} +\usepackage[section]{placeins} %wymusza by obrazek był w obrębie sekacji a nie poza nią \usepackage{tabularx} %lepsze tabele nie uzywane \usepackage{makecell} % do formatowania cell w tabelach diff --git a/rozdzial_3.tex b/rozdzial_3.tex index 7470900..9ae0be9 100644 --- a/rozdzial_3.tex +++ b/rozdzial_3.tex @@ -1,72 +1,84 @@ -\chapter{Podstawy teoretyczne} +\chapter{Podstawy teoretyczne/spis pojęć} \chapter{Ekstrakcja godzin rozpoczęcia mszy świętych} \section{Ogólny zarys systemu} -System zaczyna działanie od zebrania jak największej ilości danych (nazwa parafii, adres, diecezja -itd.) o polskich parafiach ze strony deon.pl. Następnie odpytuje api Google'a w -celu znalezienia adresów internetowych parafii. -Dla każdej parafii, dla której udało się znaleźć adres url, pobierane są wszystkie -podstrony w odległości (sieć to graf) conajwyżej 3 od strony startowej. +Architektura systemu ekstrakcji godzin rozpoczęcia mszy świętych została +przedstawiona na rysunku \ref{pic:architektura}. W tym podrozdziale zostanie ona +krótko opisana. Szczegółowy opis poszczególnych komponentów znajduje się w +kolejnych podrozdziałach. -Z dużej liczby stron parafialnych, za pomocą prostych reguł wyodrębnione zostają -te, na których z dużym prawdopodbieństwem znajdują się godziny mszy świętych. -Ciągi znaków przypominające godziny mszy świętych zostają wydobyte ekstraktorem -o bardzo niskiej precyzji i bardzo wysokim \textit{recall}. -Każda godzina wraz z kontekstem w jakim się znajduje trafia do systemu - crowdsourcingowego, gdzie jest annotowana jako poprawna lub niepoprawna godzina mszy świętej. -Do zannotowanych danych zostają dołączone poprawne godziny mszy świętych -znalezione przez -regułowy ekstraktor mszy świętych o bardzo wysokiej precyzji. Dodatkowo w celu wyrównania +System zaczyna działanie od zebrania jak największej ilości danych (nazwa parafii, adres, diecezja +itd.) o polskich parafiach ze strony deon.pl. Następnie wysyła zapytania do interfejsu API +Google w +celu znalezienia adresów internetowych parafii. +Dla każdej parafii, dla której udało się znaleźć adres URL, pobierane są wszystkie +podstrony w odległości\footnote{Zakładamy, że sieć jest grafem, zatem odległość + definiujemy tak jak w teorii grafów.} co najwyżej 3 od strony startowej. + +Z dużej liczby stron parafialnych, za pomocą reguł wyodrębnione zostają +te, na których z dużym prawdopodobieństwem znajdują się godziny mszy świętych. +Następnie godziny zostają wydobyte ekstraktorem +o bardzo niskiej precyzji i bardzo wysokiej wartości pokrycia. +Każda godzina wraz z kontekstem, w jakim się znajduje, trafia do anotatora. +Tam jest oznaczana jako poprawna lub niepoprawna godzina mszy +świętej\footnote{\label{hour_note}Przez „niepoprawne + godziny mszy świętych” rozumiemy godziny, które nie są + godzinami rozpoczęcia mszy świętych.}. +Regułowy ekstraktor mszy świętych o bardzo wysokiej precyzji znajduje poprawne +godziny mszy świętych i dołącza je do zanotowanych danych. +Dodatkowo w celu wyrównania klas z nieodfiltrowanego zbioru stron parafialnych wylosowane zostają niepoprawne godziny mszy świętych. Zebrane dane zostają użyte do wytrenowania klasyfikatora godzin opartego na płytkich sieciach neuronowych. -Finalny ekstraktor godzin mszy świętych utworzony zostaje z połączenia -ekstraktora regułowego z ekstraktorem opartym na uczeniu maszynowym. -% \bigskip +Klasyfikator używany jest do klasyfikacji godzin +znalezionych przez ekstraktor godzin do następujących klas: +\begin{itemize} +\item poprawne godziny mszy świętych, +\item niepoprawne godziny mszy świętych. +\end{itemize} -\begin{figure}[tbh!] +\noindent Docelowe godziny rozpoczęcia mszy świętych otrzymujemy z: +\begin{itemize} +\item ekstraktora godzin mszy świętych, +\item klasyfikatora godzin. +\end{itemize} + +\begin{figure}[!htb] \center -\includegraphics[width=1\hsize]{struktura_wyszukiwarki.png} -\caption{Architektura ekstraktora godzin mszy świętych.} -\label{struktura_pic} +\includegraphics[width=1\hsize]{struktura_programu.png} +\caption{Architektura systemu do ekstrakcji godzin mszy świętych.} +\label{pic:architektura} \end{figure} +\clearpage -\newpage \section{Zbieranie informacji o parafiach} -\begin{figure}[tbh!] + +\begin{figure}[htb] \center \includegraphics[width=0.7\hsize]{crawler_adresow_trans.png} -\label{crawler_adresow_pic} +\caption{Fragment architektury systemu przedstawiający komponent odpowiedzialny za zbieranie informacji o parafiach.} +\label{pic:pajak_nazw_parafii} \end{figure} +Na rysunku \ref{pic:pajak_nazw_parafii} został przedstawiony fragment architektury +systemu z rysunku \ref{pic:architektura}, który zostanie omówiony w tym podrozdziale. + Dane zostały zebrane z serwisu internetowego deon.pl, który zawiera 10130 parafii. - Warto zauważyć, że deon.pl posiada większość polskich parafii, ponieważ według + Jest to większość polskich parafii, ponieważ według danych statystycznych GUS\cite{gus} z 2016 roku w Polsce było 10255 parafii. Dla każdej parafii zebrano: \begin{itemize} \item nazwę parafii, -\item miejscowość w której się znajduje, -\item województwo w którym się znajduje, +\item miejscowość, w której się znajduje, \item dokładny adres, -\item nazwę dekanatu do którego należy, -\item nazwę diecezji do której przynależy. +\item nazwę dekanatu, do którego należy, +\item nazwę diecezji, do której przynależy, +\item województwo, w którym się znajduje. \end{itemize} - Do wydobycia danych użyto skryptu w pythonie, który korzystał z parsera - html z biblioteki \textit{BeautifulSoup}\cite{beautiful_soup}. Przy wysyłaniu zapytań do serwisu deon.pl zastosowano - algorytm \textit{Expotential Backoff}\cite{expotential_backoff}, który prezentuje się następująco: -\begin{enumerate} - \item Wyślij zapytanie do serwisu; - \item Jeśli zapytanie się powiodło wróć do punktu nr 1, jeśli nie poczekaj 1.5s i wyślij kolejne zapytanie; - \item Jeśli zapytanie znów się nie powiodło odczekaj 2.25s i wyślij kolejne - zapytanie - \item W ogólności czekaj $1.5^t$ sekund zanim wyślesz kolejne zapytanie, gdzie - $t$ to liczba następujących po sobie nieudanych zapytań. - \end{enumerate} - Powyższy algorytm uodparnia skrypt na przejściowe problemy z połączeniem i - zapobiega zbyt częstemu odpytywaniu serwisu kiedy ten nie daje sobie rady ze - zbyt dużą liczbą zapytań. + +\noindent Fragment zebranych danych został przedstawiony w tabeli \ref{dane_tab}. \begin{table}[H] \centering @@ -80,163 +92,235 @@ Dla każdej parafii zebrano: \\ [-1.5ex] \end{tabular} \caption{Fragment zebranych danych.} +\label{dane_tab} \end{table} -\section{Wyszukiwanie stron internetowych parafii} + Do wydobycia danych użyto skryptu w języku Python, który korzystał z parsera + HTML z biblioteki \textit{BeautifulSoup}\cite{beautiful_soup}. Przy wysyłaniu zapytań do serwisu deon.pl zastosowano + algorytm \textit{Expotential Backoff}\cite{expotential_backoff}, który + przedstawia się następująco: + +\begin{algorithm} +\setstretch{1.2} +\SetAlgorithmName{Algorytm}{algorithm}{List of Algorithms} +\caption{\textit{Expotential Backoff}} +\label{alg:backoff} +\SetAlgoLined +\SetKwFunction{Request}{send\_request} +\SetKwData{MaxWait}{max\_wait\_time} +\SetKwData{MaxRepeat}{repeat\_limit} +\SetKwInput{kwInput}{Stałe} +\SetKwInput{kwAlg}{Algorytm} +\SetKwInput{kwWhere}{gdzie} +\kwInput{\\ + \Indp{\makebox[2.8cm][l]{\MaxWait }} $-$ maksymalny czas oczekiwania.\\ + {\makebox[2.8cm][l]{\MaxRepeat }} $-$ limit liczby powtórnych zapytań pod rząd. +} +\bigskip +\kwAlg{ +\begin{enumerate}[rightmargin=5mm] + \item Wyślij zapytanie do serwisu; + \item Jeśli zapytanie się nie powiodło, poczekaj 2s i wyślij kolejne zapytanie, + \item Jeśli zapytanie się nie powiodło, poczekaj 4s i wyślij kolejne zapytanie, + \item Jeśli zapytanie się nie powiodło, poczekaj 8s i wyślij kolejne zapytanie, + \item Powtarzaj do czasu aż zapytanie się powiedzie lub liczba ponownych + zapytań pod rząd wyniesie \MaxRepeat. +\end{enumerate} +} +\kwWhere{ +\begin{itemize} + \setlength\itemsep{0.3em} + \item Czas oczekiwania to $2^t$, gdzie $t$ to liczba nieudanych zapytań. + \item Czas oczekiwania nie może być większy niż \MaxWait. +\end{itemize} +} +\end{algorithm} + + Algorytm \ref{alg:backoff} uodparnia skrypt na przejściowe problemy z połączeniem i + zapobiega zbyt częstemu wysyłaniu zapytań do serwisu. Dla przykładu załóżmy, + że dany serwis jest obciążony i nie daje sobie rady z przetwarzaniem zapytań. + Wtedy algorytm \textit{Expotential Backoff} przy każdym kolejnym niepowodzeniu + będzie czekał coraz dłużej zanim wyśle kolejne zapytanie. W ten sposób nie + będzie niepotrzebnie obciążał serwisu. + +\section{Wyszukiwanie adresów URL parafii} \begin{figure}[tbh!] \center \includegraphics[width=0.7\hsize]{crawler_url_trans.png} -\label{crawler_url_pic} +\caption{Fragment architektury systemu przedstawiający komponent odpowiedzialny + za wyszukiwanie adresów URL parafii.} +\label{pic:pajak_url} \end{figure} + +Na rysunku \ref{pic:pajak_url} został przedstawiony fragment architektury +systemu z rysunku \ref{pic:architektura}, który zostanie omówiony w tym podrozdziale. + \subsubsection{Pierwsze próby} -Do wyszukiwania adresów url parafii próbowano wykorzystać wyszukiwarki takie jak +Do wyszukiwania adresów URL parafii próbowano wykorzystać wyszukiwarki takie jak Google i DuckDuckGo. Automatycznie wysyłano zapytanie złożone z konkatenacji -nazwy parafii, jej miejscowości i ulicy na której się znajduje. Wyszukiwarka Google dawała -zadowalające wyniki, jednak po kilkunastu zapytaniach blokowała adres ip. W -dodatku w warunkach użytkowania serwisu i w robots.txt Google zabrania +nazwy parafii, jej miejscowości i ulicy, na której się znajduje. Wyszukiwarka Google dawała +zadowalające wyniki, jednak po kilkunastu zapytaniach blokowała adres IP. W +dodatku w warunkach użytkowania serwisu i w pliku robots.txt Google zabrania korzystania z pająków na ich wyszukiwarce. -DuckDuckGo nie blokowało adresu ip, ale zabraniało crawlowania w robots.txt i słabo radziło sobie z polskimi +Wyszukiwarka DuckDuckGo nie blokowała adresu IP, ale zabraniała indeksowania w pliku robots.txt i słaba radziła sobie z polskimi zapytaniami. W obu przypadkach powyższa metoda stwarzała kolejny problem do rozwiązania -- z wielu wyników wyszukiwania trzeba było wybrać ten, który zawierał -adres url parafii. +adres URL parafii. \subsubsection{Rozwiązanie} -Po wieleokrotnych próbach poszukiwań znaleziono klucz do rozwiązania problemu -wyszukiwania adresów url jakim jest -\textit{Google Places Api}\cite{google_api}. Serwis \textit{Text Search}\cite{text_search} pozwala na wyszukanie miejsca +Po wielokrotnych próbach poszukiwań znaleziono klucz do rozwiązania problemu +wyszukiwania adresów URL, jakim jest +\textit{Google Places API}\cite{google_api}. Serwis \textit{Text Search}\cite{text_search} pozwala na wyszukanie miejsca danego obiektu na podstawie jego nazwy. Ponadto mając już wyszukany dany obiekt i jego identyfikator można odpytać serwis \textit{Place Detail}\cite{place_detail}, aby wyciągnąć więcej -szczegółów o danym miejscu. Między innymi można otrzymać adres url danego obiektu. +szczegółów o danym miejscu. Między innymi można otrzymać adres URL danego obiektu. Jedynym minusem jest ograniczenie liczby zapytań do 1000 na 24 godziny. W dodatku każde zapytanie do serwisu \textit{Text Search} traktowane jest jak 10 -zapytań. Podając swoją kartę płatniczą można zwiększyć limit -zapytań do 150 000 na 24 godziny. Karta płatnicza jest potrzebna Google'owi do -identyfikacji osoby. Żadna opłata nie jest pobierana za korzystanie z api. +zapytań. Podając swoją kartę płatniczą, można zwiększyć limit +zapytań do 150 000 na 24 godziny. Karta płatnicza jest potrzebna Google do +identyfikacji osoby. Żadna opłata nie jest pobierana za korzystanie z interfejsu +API. Dla każdej parafii wykonywane jest zapytanie do serwisu \textit{Text Search} -składające się z konkatenacji nazwy, parafii, jej miejscowości i ulicy na której -się znajduje. Jeśli nie zostanie znaleziony żaden obiekt wysyłane jest powtórne +składające się z konkatenacji nazwy, parafii, jej miejscowości i ulicy, na której +się znajduje. Jeśli nie zostanie znaleziony żaden obiekt, wysyłane jest powtórne zapytanie, lecz tym razem składające się tylko z nazwy parafii i jej -miejscowości. Zdarza się, że \textit{Text Search} zwraca kilka obiektów. W takim -przypadku brany jest adres url pierwszego obiektu z listy wyników. +miejscowości. Zdarza się, że serwis \textit{Text Search} zwraca kilka obiektów. W takim +przypadku brany jest adres URL pierwszego obiektu z listy wyników. Najczęściej jednak oba obiekty należą do tej samej parafii, więc mają taki sam -adres internetowy. - -Powyższą metodą udało się zebrać adresy url dla ok. 5600 parafii. +adres internetowy. Taki przypadek przedstawia rysunek \ref{pic:text_search}. +Serwis \textit{Text Search} zwraca dużo danych w formacie \textit{json}, które +ciężko przedstawić w przejrzystej postaci. +Dla +czytelności na rysunku \ref{pic:text_search} pokazano zrzuty z wyszukiwarki \textit{Google Maps}, +które odpowiadają rezultatowi jaki otrzymanoby korzystając z serwisu +\textit{Text Search}. +\noindent Powyższą metodą udało się zebrać adresy URL dla ok. 5600 parafii. \begin{figure}[tbh] \center \includegraphics[width=1\hsize]{amb_text_search.png} -\caption{Przykład dwóch obiektów zwróconych przez \textit{Text Search}, które +\caption{Przykład dwóch obiektów zwróconych przez wyszukiwarkę Google, które mają ten sam adres internetowy.} -\label{text_search_pic} +\label{pic:text_search} \end{figure} - -\section{Crawlowanie stron parafialnych} - -\begin{figure}[tbh] +\section{Indeksowanie stron parafialnych} +\enlargethispage{1\baselineskip} +\begin{figure}[htb!] \center \includegraphics[width=0.7\hsize]{crawler_parafii_general_trans.png} -\label{crawler_parafii_general_pic} +\caption{Fragment architektury systemu przedstawiający komponent odpowiedzialny + za indeksowanie stron parafialnych.} +\label{pic:pajak_parafii_general} \end{figure} -Crawler został napisany przy użyciu biblioteki Scrapy. -Punktem startowym jest pojedynczy adres url parafii podawany na wejście -programu. Z początkowego adresu url wydobywana jest domena w obrębie której -porusza się pająk. Oznacza to, że jedna instancja pająka zajmuje się ściąganiem -tylko jedenej parafii. W ramach jednej parafii pająk jest w stanie + + +Na rysunku \ref{pic:pajak_parafii_general} został przedstawiony fragment architektury +systemu z rysunku \ref{pic:architektura}, który zostanie omówiony w tym podrozdziale. + +Pająk został napisany przy użyciu biblioteki \textit{Scrapy}\cite{scrapy}. +Punktem startowym jest pojedynczy adres URL parafii podawany na wejście +programu. Z początkowego adresu URL wydobywana jest domena, w której obrębie +porusza się pająk. Oznacza to, że jedna instancja pająka zajmuje się pobieraniem +tylko jednej parafii. W ramach jednej parafii pająk jest w stanie asynchronicznie wysłać wiele zapytań do serwera i odbierać wiele odpowiedzi od serwera. \subsection{Komponenty pająka} +Pająk składa się z następujących komponentów: \begin{description} \item [Silnik] -- odpowiada za kontrolę przepływu danych i komunikację między komponentami. \item [Dyspozytor] -- otrzymuje żądania od silnika, kolejkuje je i na prośbę silnika odsyła z powrotem. - \item [Downloader] -- jego zadniem jest ściąganie stron parafialnych i + \item [Downloader] -- odpowiada za pobieranie stron parafialnych i przekazywanie ich silnikowi. - \item [Przetwarzacz danych] -- zajmuje się końcową obróbką i zapisem danych. + \item [Procesor danych] -- zajmuje się końcową obróbką i zapisem danych. \item [Spider]\footnote{Użyto angielskiej nazwy, aby rozróżnić \textit{spider'a} (komponent pająka), od pająka (cały program - odpowiedzialny za crawlowanie stron parafialnych).} - - definuje sposób w jaki ściągać dane, między innymi jak parsować stronę i za jakimi + odpowiedzialny za indeksowanie stron parafialnych).} + - definiuje sposób, w jaki pobierać dane, między innymi jak parsować stronę i za jakimi linkami podążać. - \item [Spider middleware] -- programy pośredniczące między silnkiem, a - spider'em. Odpowiedzialne są za dodatkowe przetwarzanie danych wyjściowych - (dane parafialne i żądania) i wejściowych (odpowiedzi) spider'a. + \item [Spider middleware] -- programy pośredniczące między silnikiem, a + \textit{spider'em}. Odpowiedzialne są za dodatkowe przetwarzanie danych wyjściowych + (dane parafialne i żądania) i wejściowych (odpowiedzi) \textit{spider'a}. \item [Downloader middleware] -- programy pośredniczące między silnikiem, a - downloader'em. Zajmują się dodatkowym przetwarzaniem danych wejściowych - (żądań) i wyjściowych (odpowiedzi) downloader'a. + \textit{downloader'em}. Zajmują się dodatkowym przetwarzaniem danych wejściowych + (żądań) i wyjściowych (odpowiedzi) \textit{downloader'a}. \end{description} -\newpage \subsection{Przepływ danych} Przepływ danych kontrolowany jest przez -silnik i prezentuje się następująco\footnote{Diagram i opis wzorowany jest na - dokumentacji znajdującej się pod linkiem https://doc.scrapy.org/en/latest/topics/architecture.html}: +silnik i wygląda następująco\footnote{Diagram i opis wzorowany jest na + dokumentacji znajdującej się pod linkiem https://doc.scrapy.org/en/latest/topics/architecture.html.}: \begin{figure}[tbh] \center \includegraphics[width=0.85\hsize]{scrapy_data_flow.png} -% \caption{100 crawlerów pracujących jednocześnie} -\label{scrapy_data_flow_pic} +\caption{Silnik kontrolujący przepływ danych przez komponenty pająka.} +\label{pic:scrapy_data_flow} \end{figure} \begin{enumerate} - \item Silnik otrzymuje od spider'a żądanie pobrania początkowej strony danej + \item Silnik otrzymuje od \textit{spider'a} żądanie pobrania początkowej strony danej parafii (najczęściej jest to strona główna parafii). \item Silnik oddaje żądania dyspozytorowi, który kolejkuje je do dalszego - przetwarzania oraz pyta dyspozytora o żądania gotowe do przekazania downloader'owi. + przetwarzania oraz pyta dyspozytora o żądania gotowe do przekazania \textit{downloader'owi}. \item Dyspozytor zwraca silnikowi następne żądania. - \item Silnik wysyła żądania do downloader'a. Zanim żądania dotrą do - downloader'a przetwarzane są przez downloader middleware. - \item Downloader ściąga stronę parafialną i umieszcza ją w odpowiedzi, którą - przesyła silnikowi. Zanim odpowiedź dotrze do silnka przetwarzana jest przez - downloader middleware. - \item Silnik otrzymuje odpowiedź od downloader'a i przekazuje ją spider'owi do - dalszego przetwarzania. Zanim odpowiedź trafi do spider'a przetwarzana jest - przez spider middleware. - \item Spider przerabia odpowiedź i zwraca dane strony parafialnej silnikowi. Zanim dane - trafią do silnika przechodzą przez spider middleware. Dodatkowo spider - wysła żądania z nowymi stronami parafialnymi do pobrania. - \item Silnik wysyła zebrane dane do przetwarzacza danych, który zapisuje je w - pliku jsonline\cite{jsonline}. Następnie przekazuje nowe żądania do zakolejkowania + \item Silnik wysyła żądania do \textit{downloader'a}. Zanim żądania dotrą do + \textit{downloader'a}, przetwarzane są przez \textit{downloader middleware}. + \item \textit{Downloader} pobiera stronę parafialną i umieszcza ją w odpowiedzi, którą + przesyła silnikowi. Zanim odpowiedź dotrze do silnika, przetwarzana jest przez + \textit{downloader middleware}. + \item Silnik otrzymuje odpowiedź od \textit{downloader'a}i przekazuje ją \textit{spider'owi} do + dalszego przetwarzania. Zanim odpowiedź trafi, do \textit{spider'a} przetwarzana jest + przez \textit{spider middleware}. + \item \textit{Spider} przerabia odpowiedź i zwraca dane strony parafialnej silnikowi. Zanim dane + trafią, do silnika przechodzą przez \textit{spider middleware}. Dodatkowo \textit{spider} + wysyła żądania z nowymi stronami parafialnymi do pobrania. + \item Silnik wysyła zebrane dane do procesora danych, który zapisuje je do + pliku.. Następnie przekazuje nowe żądania do zakolejkowania dyspozytorowi. \end{enumerate} % \vspace*{-20mm} Cały proces trwa dopóty, dopóki są nowe żądania do przetworzenia. \subsection{Sprawdzanie typu odpowiedzi} -Podczas crawlowania ważne jest rozpoznawanie typu ściąganych danych. W przypadku -crawlowania stron parafialnych interesują nas wyłącznie dane tekstowe. Należy +Podczas indeksowania ważne jest rozpoznawanie typu pobieranych danych. W przypadku +indeksowania stron parafialnych interesują nas wyłącznie dane tekstowe. Należy zatem zadbać o to, aby nie pobierać danych binarnych takich jak np. video, audio i obrazy. -Scrapy obsługuje rozpoznawanie typu zawartości odpowiedzi bazując na +Biblioteka \textit{Scrapy} obsługuje rozpoznawanie typu zawartości odpowiedzi, bazując na następujących kryteriach: \begin{itemize} -\item wartościach \mintinline{bash}{Content-type}\cite{RFC2045}, \mintinline{bash}{Content-Encoding}\cite{RFC7231} i \mintinline{bash}{Content-Disposition}\cite{RFC6266} w nagłówku odpowiedzi, -\item nazwie pliku lub adresie url (jeśli nie udało się rozpoznać po nagłówku), -\item analizując pierwsze 5000 bajtów zawartości odpowiedzi w poszukiwaniu - znaków znajdującyh się wyłącznie w plikach binarnych (jeśli nie udało się - rozpoznać po nazwie pliku lub adresie url). +\item wartości \mintinline{bash}{Content-type}\cite{RFC2045}, \mintinline{bash}{Content-Encoding}\cite{RFC7231} i \mintinline{bash}{Content-Disposition}\cite{RFC6266} w nagłówku odpowiedzi, +\item nazwie pliku lub adresie URL (jeśli nie udało się rozpoznać po nagłówku), +\item obecności znaków kontrolnych w pierwszych 5000 bajtów odpowiedzi + (jeśli nie udało się + rozpoznać po nazwie pliku lub adresie URL). \end{itemize} -Powyższy schemat postępowania jest skuteczny jeśli serwisy internetowe zwracają +Powyższy schemat postępowania jest skuteczny, jeśli serwisy internetowe zwracają poprawne odpowiedzi. Niestety niektóre strony parafialne potrafią zwracać -odpowiedzi, które są niezgodne z rozdziałem 3.1 z RFC7231\cite{RFC7231}. -Dla przykładu, strona potrafi zwrócić \mintinline{bash}{Content-Type: text/html}, a w \mintinline{bash}{body} binarną +odpowiedzi, które nie są zgodne z rozdziałem 3.1 z RFC7231\cite{RFC7231}. +Dla przykładu strona potrafi zwrócić \mintinline{bash}{Content-Type: text/html} +w nagłówku, a w ciele binarną zawartość np. film. Tego rodzaju anomalie są wykrywane i eliminowane. -Stosując następujący algorytm\cite{binaryornot} można określić typ zawartości \mintinline{bash}{body}: +\enlargethispage{2\baselineskip} +Stosując algorytm \ref{alg:binaryornot}, można określić typ zawartości +ciała odpowiedzi. - -\enlargethispage{4\baselineskip} -\begin{algorithm} +\begin{algorithm}[tbh!] \setstretch{1.2} \SetAlgorithmName{Algorytm}{algorithm}{List of Algorithms} \caption{Rozpoznawanie plików binarnych} +\label{alg:binaryornot} +\SetKwIF{IfM}{ElseIfM}{ElseM}{if~(\endgraf}{\endgraf\nl)~then}{else + if}{else}{\nl end if}% +\SetKwIF{If}{ElseIf}{Else}{if}{then}{else if}{else}{\nl end if}% \SetAlgoLined \SetKwData{File}{bytes} \SetKwData{True}{True} @@ -248,105 +332,220 @@ Stosując następujący algorytm\cite{binaryornot} można określić typ zawarto \SetKwData{ControlCount}{control\_char\_count} \SetKwData{ControlRatio}{control\_char\_ratio} -\SetKwData{AsciiCount}{extended\_ascii\_count} -\SetKwData{AsciiRatio}{extended\_ascii\_ratio} - \If{\File puste}{ - \Return{\False}\; - } -\If{\File dekodowalne jako unikod}{ -\Return{\False}\; -} -\ControlCount $\leftarrow$ liczba znaków kontrolnych w \File\; -\AsciiCount $\leftarrow$ liczba znaków ascii o kodach od 128 do 255 w \File\; -\ControlRatio $\leftarrow \frac{\ControlCount}{1024}$\; -\AsciiRatio $\leftarrow \frac{\AsciiCount}{1024}$\; - -\SetKwIF{IfM}{ElseIfM}{ElseM}{if~(\endgraf}{\endgraf)~then}{else if}{else}{end if}% -\IfM{\begin{tabular}{@{\hspace*{1.5em}}l@{}} - $($\ControlRatio $> 0.3$ {\bf and} \AsciiRatio $< 0.05)$ {\bf or}\\ - $($\ControlRatio $> 0.8$ {\bf and} \AsciiRatio $> 0.80)$ - \end{tabular}}{ - \Return{\True}\; - } - +\SetKwData{AsciiCount}{high\_ascii\_count} +\SetKwData{AsciiRatio}{high\_ascii\_ratio} \SetKwData{Null}{null} -\If{znak \Null w \File}{ - \Return{\True}\; - } - \Return{\False}\; +\nl\uIf{\File puste {\bf or} \File dekodowalne jako unikod}{ +\nl \Return{\False}\; +}\ElseIf{znak \Null \bf in \File}{ +\nl \Return{\True}\; +} +\nl \tcc{Za znaki kontrolne uznajemy znaki o kodach EASCII od 0 do 7, 11, od 14 + do 32 i od 127 do 159.} +\nl\ControlCount $\leftarrow$ liczba znaków kontrolnych w \File\; +\nl\AsciiCount $\leftarrow$ liczba znaków EASCII o kodach od 160 do 255 w \File\; +\nl\ControlRatio $\leftarrow \frac{\ControlCount}{1024}$\; +\nl\AsciiRatio $\leftarrow \frac{\AsciiCount}{1024}$\; +\nl \If{$($\ControlRatio $> 0.3$ {\bf or} \AsciiRatio $> 0.7)$}{ +\nl \Return{\True}\; +} +\nl \Return{\False}\; \end{algorithm} -\subsection{Automatyczna regulacja częstości zapytań} -Biblioteka scrapy zawiera przydatne rozszerzenie, które potrafi automatycznie -regulować częstość zapytań w zależności od obciążenia crawler'a i strony internetowej. -\noindent Algorytym regulacji częstości zapytań prezentuje się następująco: +Algorytm \ref{alg:binaryornot} analizuje zawartość ciała odpowiedzi w celu +stwierdzenia czy jest ona binarna czy nie. +W linii 6 za znaki kontrolne uznano +wszystkie znaki kontrolne ze zbioru C0\footnote{C0 to znaki kontrolne z kodu + ASCII o kodach od 0 do 32 i o kodzie 127.} i C1\footnote{C1 to znaki kontrolne + o kodach od 128 do 159. Zostały zdefiniowane w standardzie ISO/IEC 2022. + Wiele +innych systemów kodowań rezerwuje sobie kody od 128 do 159 na znaki kontrolne.} z wyłączeniem +następujących znaków: +\begin{itemize} +\item znak nowej linii (oznaczany przez \mintinline{python}{\n}), +\item znak powrotu karetki (oznaczany przez \mintinline{python}{\r}), +\item znak tab (oznaczany przez \mintinline{python}{\t}), +\item znak backspace (oznaczany przez \mintinline{python}{\b}), +\item znak nowej linii (oznaczany przez \mintinline{python}{\n}), +\item znak końca strony (oznaczany przez \mintinline{python}{\f}), +\end{itemize} +Powyższe znaki zostały wykluczone, ponieważ często występują w plikach tekstowych. + +Warto zwrócić uwagę na linię 10. Współczynnik +\mintinline{python}{control_char_ratio} +oznacza procent znaków kontrolnych w pierszych 1024 bajtach pliku. +Jeśli współczynnik \mintinline{python}{control_char_ratio} jest większy niż +$0.3$ to plik jest uznawany za binarny. Wartość $0.3$ została wzięta z +kodu\footnote{Kod znajduje się pod linkiem \url{https://github.com/Perl/perl5/blob/v5.27.11/pp\_sys.c\#L3605-L3665}. Wartość 0.3 występuje w linii 3661.} +źródłowego języka Perl, który między innymi zajmuje się rozpoznawaniem plików +binarnych. Natomiast współczynnik \mintinline{python}{high_ascii_ratio} oznacza +procent znaków EASCII\footnote{EASCII + oznacza rozszerzone kodowanie ASCII. Przykładowe rozszrzenia to systemy + kodowania ISO 8859 lub UTF-8.} + o kodach od 160 do 255. +Reprezentacja tych znaków zależy od rozszerzenia ASCII. Najczęściej jednak są to +znaki drukowalne, które rzadko występują w tekście. +Jeśli współczynnik \mintinline{python}{high_ascii_ratio} jest większy niż $0.7$ +to plik jest uznawany za binarny. +Wartośc $0.7$ została dobrana na podstawie następujących obserwacji: \begin{enumerate} -\item Przyjmijmy, że: - - \subitem {\makebox[4.55cm][l]{\mintinline{python}{download_delay}}} to opóźnienie\footnote{Czasy oczekiwania i - opóźnienia liczone są w sekudnach.} wysłania - zapytania. - \subitem \mintinline{python}{target_download_delay} to docelowe - opóźnienie zapytania. - \subitem {\makebox[4.55cm][l]{\mintinline{python}{init_download_delay}}} to początkowe opóźnienie wysłania - zapytania. - \subitem {\makebox[4.55cm][l]{\mintinline{python}{min_download_delay}}} to minimalne opóźnienie wysyłania. - \subitem {\makebox[4.55cm][l]{\mintinline{python}{max_download_delay}}} to maksymalne opóźnienie wysyłania. - \subitem {\makebox[4.55cm][l]{\mintinline{python}{latency}}} to czas od - ustanowienia połączenia \\ - {\makebox[5.22cm][l]{}} do otrzymania nagłówków odpowiedzi. - \subitem {\makebox[4.55cm][l]{\mintinline{python}{target_concurrency}}} to zaplanowana liczba zapytań na sekundę. - -\item Zacznij z \mintinline{python}{download_delay} równym \mintinline{python}{init_download_delay}. -\item Kiedy odpowiedź jest odebrana, \\ustaw - \mintinline{python}{target_download_delay = latency / target_concurrency}. - \item Następne \mintinline{python}{download_delay} ustaw jako średnią z - aktualnego \mintinline{python}{download_delay} i \mintinline{python}{target_download_delay}. - \item \mintinline{python}{download_delay} nie może być mniejszy niż - \mintinline{python}{min_download_delay} i większy niż \mintinline{python}{max_download_delay}. - \item Czasy oczekiwania na odpowiedzi z kodem http różnym od 2xx nie są brane - pod uwagę. +\item Zdarzają się pliki binarne, które mają dużo znaków + \mintinline{python}{high_ascii}. Przykładem jest plik z katalogu + \mintinline{text}{data.tar.gz/spec/resources/pixelstream.rgb} + z archiwum \url{https://rubygems.org/downloads/chunky\_png-1.2.8.gem}. Plik + zawiera bardzo dużo znaków o kodzie 255 w początkowych bajtach. +\item Mało prawdopodobne jest, aby plik tekstowy miał w pierwszych 1024 bajtach + więcej niż 70\% znaków \mintinline{python}{high_ascii}. Nawet jeśli pająk + natrafiłby na taki plik to z dużym prawdopodbieństwem nie zawierałby on + informacji parafialnych. \end{enumerate} -\noindent W crawlerze stron parafialnych stałe ustawiono następująco: +\subsection{Automatyczna regulacja częstości zapytań} +Biblioteka \textit{Scrapy} zawiera przydatne rozszerzenie, które potrafi automatycznie +regulować częstość zapytań w zależności od obciążenia pająka i strony internetowej. + +Algorytm \ref{alg:throttling} przedstawia sposób postępowania w jaki pająk +automatycznie reguluje częstość zapytań. Idea algorytmu jest następująca. +Załóżmy, że serwer potrzebuje +\mintinline{python}{latency}\footnote{Zmienna \mintinline{python}{latency} + została + zdefiniowana w algorytmie \ref{alg:throttling}.} sekund, aby odpowiedzieć pająkowi. Jeśli pająk chce +mieć przetworzone równolegle +\mintinline{python}{target_concurrency}\footnote{Stała + \mintinline{python}{target_concurrency} została zdefiniowana w algorytmie \ref{alg:throttling}.}zapytań to powinnien +wysyłać każde zapytanie co \mintinline{python}{latency/target_concurrency} +sekund. + +\begin{algorithm}[tbh!] +\setstretch{1.2} +\SetAlgorithmName{Algorytm}{algorithm}{List of Algorithms} +\caption{Algorytm regulacji częstości zapytań} +\label{alg:throttling} +\SetAlgoLined +\SetKwFunction{Request}{send\_request} +\SetKwData{Delay}{download\_delay} +\SetKwData{tDelay}{target\_download\_delay} +\SetKwData{iDelay}{init\_download\_delay} +\SetKwData{minDelay}{min\_download\_delay} +\SetKwData{maxDelay}{max\_download\_delay} +\SetKwData{latency}{latency} +\SetKwData{targetConcurrency}{target\_concurrency} +\SetKwInput{kwConst}{Stałe} +\SetKwInput{kwVar}{Zmienne} +\SetKwInput{kwWhere}{gdzie} +\SetKwInput{kwAlg}{Algorytm} +\kwConst{\\ + \Indp{\makebox[4.1cm][l]{\iDelay}} $-$ początkowe opóźnienie wysłania zapytania. \\ + {\makebox[4.1cm][l]{\minDelay}} $-$ minimalne opóźnienie wysłania zapytania. \\ + {\makebox[4.1cm][l]{\maxDelay}} $-$ maksymalne opóźnienie wysłania zapytania.\\ + {\makebox[4.1cm][l]{\targetConcurrency}} $-$ średnia wartość równoległych + zapytań do + \phantom{{\makebox[4.1cm][l]{\targetConcurrency}} $-$} wysłania. +} +\kwVar{\\ + \Indp{\makebox[4.1cm][l]{\tDelay}} $-$ docelowe opóźnienie wysyłania zapytania.\\ + {\makebox[4.1cm][l]{\Delay}} $-$ opóźnienie wysłania zapytania. \\ + {\makebox[4.1cm][l]{\latency}} $-$ czas od ustanowienia połączenia do + \phantom{{\makebox[4.1cm][l]{\latency}} $-$} otrzymania nagłówków odpowiedzi. +} +\bigskip +\kwAlg{ +\begin{enumerate}[rightmargin=5mm] + \item Wyślij zapytanie do serwisu; + \item Ustaw $\Delay \leftarrow \iDelay$. +\item Gdy odebrano odpowiedź, ustaw + $\tDelay \leftarrow \frac{\latency}{\targetConcurrency}$. + \item Ustaw $\Delay \leftarrow \frac{\Delay\ +\ \tDelay}{2}$ + \item Czekaj \Delay sekund. + \item Wyślij kolejne zapytanie do serwisu; + \item Wróć do kroku nr 3. +\end{enumerate} +} +\kwWhere{ +\begin{itemize} + \item Opóźnienia liczone są w sekundach. + \item \Delay nie może być mniejszy niż \minDelay i większy niż \maxDelay. + \item Czasy oczekiwania na odpowiedzi z kodem http różnym od 2xx nie są brane + pod uwagę. + \item Algorytm kończy się, gdy nie ma więcej zapytań do wysłania. +\end{itemize} +} +\end{algorithm} + +\clearpage +\noindent W pająku stron parafialnych stałe z algorytmu \ref{alg:throttling} ustawiono następująco: \begin{itemize} \item \mintinline{python}{min_download_delay = 0} + \item \mintinline{python}{max_download_delay = 300} \item \mintinline{python}{init_download_delay = 5} \item \mintinline{python}{target_concurrency = 1} \end{itemize} +Stałe \mintinline{python}{min_download_delay} i +\mintinline{python}{max_download_delay} zostały ustawione w taki sposób, aby nie +ograniczać zbyt mocno +pająka co do doboru wartości \mintinline{python}{download_delay}. Celem jest +przecież automatyczna regulacja wartości \mintinline{python}{download_delay}. +Niska wartość stałej \mintinline{python}{target_concurrency} umotywowana jest +dużą liczbą równolegle pracujących pająków (patrz podrozdział \ref{subsec:multiprocess}). - -\subsection{Crawlowanie wieloprocesorowe} +\subsection{Indeksowanie wieloprocesorowe} +\label{subsec:multiprocess} \begin{figure}[tbh!] \center \includegraphics[width=0.72\hsize]{crawler.png} -\caption{100 crawlerów pracujących jednocześnie.} -\label{crawler_pic} +\caption{100 pająków pracujących jednocześnie.} +\label{pic:pajaki} \end{figure} Pająk został zaprojektowany w ten sposób, aby bardzo łatwo można było -urównoleglić ściąganie stron parafialnych. -Z pomocą GNU parallel\cite{parallel} crawlowane jest jednocześnie 100 parafii. Gdy jedna ze stu -parafii zostanie ściągnięta, zastępuje ją kolejna parafia. Tym sposobem przez -prawie cały czas równolegle pracuje 100 crawlerów. Takie podejście pozwoliło +urównoleglić pobieranie stron parafialnych. +Z pomocą programu \textit{GNU parallel}\cite{parallel} indeksowane jest +jednocześnie 100 parafii (patrz rys. \ref{pic:pajaki}). Gdy jedna ze stu +parafii zostanie pobrana, zastępuje ją kolejna parafia. Tym sposobem przez +prawie cały czas równolegle pracuje 100 pająków. Takie podejście pozwoliło maksymalnie wykorzystać łącze internetowe, które było wąskim gardłem w procesie -crawlowania stron parafialnych. - +indeksowania stron parafialnych. \subsection{Organizacja danych} -Mały podrozdział do zrobienia lub pominięcia. +Dane zbierane przez pająka zapisywane są do pliku w formacie \textit{JSON + Lines}. Format \textit{JSON Lines} charakteryzuje się tym, że w każdej linii pliku +znajduje się poprawny obiekt \textit{json}. +Dla +każdej parafii pobrane dane zapisywane są w oddzielnym pliku. W każdej linii +pliku znajduje się strona parafialna zapisana w formacie \textit{json}. +Zapis w formacie \textit{JSON Lines} i traktowanie każdej linii jako strony parafialnej niesie szereg korzyści takich jak: +\begin{enumerate} +\item wygodne przetwarzanie równoległe, +\item łatwa obróbka danych za pomocą narzędzi Unixowych, +\item mniejszy rozmiar pliku w porównaniu do zwykłego formatu \textit{json}. +\end{enumerate} -\subsection{Konwersja html na tekst.} -\begin{figure}[tbh] +\noindent Dla każdej strony parafialnej zapisywane są następujące informacje: +\begin{enumerate} + \item adres URL strony, + \item adres URL poprzedniej strony, + \item adres URL strony początkowej, + \item domena parafii, + \item strona parafii w formacie HTML, + \item tekst z odnośnika (linku), który doprowadził do bieżącej strony. +\end{enumerate} + +\section{Konwersja HTML na tekst.} +\begin{figure}[tbh!] \center -\includegraphics[width=0.6\hsize]{html2text_trans.png} -\label{hmlt2text_pic} +\includegraphics[width=0.53\hsize]{html2text_trans.png} +\caption{Fragment architektury systemu przedstawiający komponent odpowiedzialny + za konwersje HTML na tekst.} +\label{pic:html2text} \end{figure} -Do konwersji z formatu html na format tekstowy wykorzystano bibliotekę \mintinline{bash}{html2text}\cite{html2text} -pierwotnie rozwijaną przez słynnego programistę Aarona Schwartza. -\mintinline{bash}{html2text} konwertuje html na czysty, czytelny tekst w -formacie Markdown\cite{markdown}. Biblioteka oferuje wiele opcji do kontroli +Na rysunku \ref{pic:html2text} został przedstawiony fragment architektury +systemu z rysunku \ref{pic:architektura}, który zostanie omówiony w tym podrozdziale. + +Do konwersji z formatu HTML na format tekstowy wykorzystano bibliotekę \mintinline{bash}{html2text}\cite{html2text} +pierwotnie rozwijaną przez Aarona Schwartza. +\mintinline{bash}{html2text} konwertuje HTML na czysty, czytelny tekst w +formacie \textit{Markdown}\cite{markdown}. Biblioteka oferuje wiele opcji do kontroli konwersji i jest bardzo łatwa w modyfikacji. \smallskip @@ -355,26 +554,32 @@ konwersji i jest bardzo łatwa w modyfikacji. \begin{itemize} % \setlength{\itemsep}{1pt} \item ignorowanie linków, tabel i obrazków, -\item usunięto znaki odpowiedzialne za pogrubienie i kurysywę tekstu, -\item usunięto znaki odpowiedzialne za tworzenie list. +\item usuwanie znaków odpowiedzialne za pogrubienie i kursywę tekstu, +\item usuwanie znaków odpowiedzialne za tworzenie list. \end{itemize} -\section{Ekstraktor godzin} +\section{Ekstrakcja godzin} \begin{figure}[tbh!] \center -\includegraphics[width=0.6\hsize]{general_ekstraktor.png} -\label{general_ekstraktor_pic} +\includegraphics[width=0.65\hsize]{general_ekstraktor.png} +\caption{Fragment architektury systemu przedstawiający komponent odpowiedzialny + za ekstrakcję godzin ze stron parafialnych.} +\label{pic:general_ekstraktor} \end{figure} +Na rysunku \ref{pic:html2text} został przedstawiony fragment architektury +systemu z rysunku \ref{pic:architektura}, który zostanie omówiony w tym podrozdziale. + Ekstraktor godzin służy do znajdowania bardzo ogólnych ciągów znaków mogących być godzinami rozpoczęcia mszy świętych. Został napisany z myślą, aby miał - bardzo wysoki recall, ale już niekoniecznie wysoką precyzję. + bardzo wysoką wartość pokrycia, ale już niekoniecznie wysoką precyzję. Celem jest, - aby w zbiorze wykestrahowanych godzin znalazło się jak najwięcej godzin - rozpoczęcia mszy, bez względu na to jak duży jest ten zbiór. + aby w zbiorze wyekstrahowanych godzin znalazło się jak najwięcej godzin + rozpoczęcia mszy, bez względu na to, jak duży jest ten zbiór. Ekstraktor wraz + ze znalezioną godziną zapisuje kontekst w jakim ta godzina się znalazła. Do osiągnięcia tego celu zastosowano następujące reguły. Ciąg znaków oznaczony jako \mintinline{bash}{hour} zostanie wyekstrahowany, jeśli -zajdzie każdy z poniżych warunków: +zajdzie każdy z poniższych warunków: \begin{enumerate} \item \mintinline{bash}{hour} pasuje do wyrażenia regularnego \\ \mintinline{text}{(0?[6-9]|1\d|2[0-2])[:.](oo|[0-5]\d)|6|7|8|9|1\d|2[0-2]}; \item Znak przed \mintinline{bash}{hour} zawiera się w @@ -382,19 +587,109 @@ zajdzie każdy z poniżych warunków: \item Znak po \mintinline{bash}{hour} zawiera się w \mintinline{python}{{',', ')', ';'}}; \item Jeśli znak przed \mintinline{bash}{hour} równa się - \mintinline{python}{'('} to znak po \mintinline{bash}{hour} jest różny od \mintinline{bash}{')'}. + \mintinline{python}{'('}, to znak po \mintinline{bash}{hour} jest różny od \mintinline{bash}{')'}. \end{enumerate} +\section{Filtrowanie stron} +\begin{figure}[tbh!] +\center +\includegraphics[width=0.5\hsize]{filtrowanie.png} +\caption{Fragment architektury systemu przedstawiający komponent odpowiedzialny + za filtrowanie stron parafialnych.} +\label{pic:filtrowanie} +\end{figure} +Na rysunku \ref{pic:filtrowanie} został przedstawiony fragment architektury +systemu z rysunku \ref{pic:architektura}, który zostanie omówiony w tym podrozdziale. -\section{System crowdsourcingowy} +Filtr stron parafialnych ma za zadanie odnaleźć strony parafialne na których z +dużym prawdopodobieństwem znajdują się godziny mszy świętych. Taki zabieg jest +potrzebny, aby ograniczyć liczbę godzin, które trafią do anotatora. Gdyby nie zastosowano +filtru stron parafialnych ekstraktor godzin wśród wszystkich stron parafialnych +znalazłby ponad 3 miliony godzin. Po zaaplikowaniu filtru stron i przetworzeniu +ich przez ekstraktor godzin otrzymano 10920 godzin. Później godziny wraz z +kontekstami poddawane są anotacji. Etap ten będzie dokładniej opisany w kolejnym podrozdziale. + +Reguły zastosowane do zadecydowania czy dana strona zawiera godziny mszy +świętych zostały przedstawione w +algorytmie \ref{alg:has_mass}. +\begin{algorithm} +\setstretch{1.2} +\SetAlgorithmName{Algorytm}{algorithm}{List of Algorithms} +\caption{Rozpoznawanie stron z godzinami mszy świętych.} +\label{alg:has_mass} +\SetKwIF{IfM}{ElseIfM}{ElseM}{if~(\endgraf}{\endgraf\nl)~then}{else + if}{\nl else}{\nl end if}% +\SetKwIF{If}{ElseIf}{Else}{if}{then}{else if}{else}{\nl end if}% +\SetAlgoLined +\SetKwData{url}{url} +\SetKwData{bText}{btn\_text} +\SetKwData{False}{False} +\SetKwData{True}{True} +\SetKwInput{kwInput}{Wejście} +\SetKwInput{kwOutput}{Wyjście} +\kwInput{\\ + \vspace{-0.5mm} + \Indp\url $\leftarrow$ adres internetowy analizowanej strony,\\ + \bText $\leftarrow$ tekst na przycisku, który doprowadził do + analizowanej \phantom{\bText $\leftarrow$} strony. +} + +\kwOutput{ + \vspace{-2mm} + \begin{itemize}[rightmargin=5mm] + \setlength\itemsep{-1mm} + \item \True jeśli jest wysokie prawdopodbieństwo, że strona zawiera godziny mszy + \item \False jeśli jest niskie prawdopodbieństwo, że strona zawiera godziny mszy + \end{itemize} +} + +\SetKwData{suf}{url\_suf} +\SetKwData{slash}{'/'} +\SetKwData{goodreg}{ok\_regex} +\SetKwData{badreg}{bad\_regex} + +\nl\tcc{Wyrażenia regularne \goodreg i \badreg ignorują wielkość liter.} +\nl $\goodreg \leftarrow$ +\mintinline[breaklines]{python}{'msze|nabo[żz]e[ńn]stw(a|(?=\W\d)|$)| + porz[ąa]dek($|\.htm)|porz[aą]dek.(liturgi|mszy)| (rozk[lł]ad|plan|godziny|uk[lł]ad|harmonogram|grafik|rozpiska).mszy'} + +\medskip \vspace{-1mm} +\nl $\badreg \leftarrow$ +\mintinline[breaklines]{python}{'nabo[zż]e[nń]stwa.(majowe|wielk|czerwcowe |maryjne|pasyjne|pokutne|fatimskie|do|ro[żz]a|czterdzie|w.wielk)'} + +\nl$\suf \leftarrow$ ciąg znaków w \url po ostatnim wystąpieniu \slash\; + +\nl\uIfM{\begin{tabular}{@{\hspace*{-3.8pt}}l@{}} +\nl \hspace*{1.2em} + $($ \suf pasuje do $\goodreg$ {\bf and} \suf nie pasuje do \badreg $)$ {\bf or}\\ +\nl \hspace*{1.2em} + $($ \bText pasuje do $\goodreg$ {\bf and} \bText nie pasuje do \badreg $)$ + \end{tabular}}{ +\nl \Return{\True};\ +}\ElseM{ +\Return{\False};\ +} +\end{algorithm} + +W algorytmie \ref{alg:has_mass} warto zwórcić uwagę na wyrażenia regularne + \mintinline{text}{ok_regex} i \mintinline{text}{bad_regex}. Wyrażenie + regularne \mintinline{text}{ok_regex} ma za zadanie dopasować się do słów, + które są powiązane z porządkiem mszy świętych. Stąd też pojawiają się tam + wyrażenia takiej jak rozkład mszy lub porządek liturgii. + + Wyrażenie regularne \mintinline{text}{bad_regex} ma za zadanie dopasować się do + słów, które są powiązane z innymi nabożeństami niż msze święte. Stąd pojawiają + się tam wyrażenia takie jak nabożeństwa czerwcowe czy nabożeństwa maryjne. + +\section{Anotator danych} \begin{figure}[tbh!] \center \includegraphics[width=0.6\hsize]{annotator.png} -\label{annotator_pic} +\label{anotator_pic} \end{figure} -System crowdsourcingowy został stworzony w celu zebrania jak największej ilości +Anotator danych został stworzony w celu zebrania jak największej ilości danych dla klasyfikatora przewidującego czy zaznaczony fragment jest godziną -rozpoczęcia mszy świętej czy nie. +rozpoczęcia mszy świętej, czy nie. Do dokończenia @@ -410,9 +705,6 @@ Do napisania Do napisania % \section{Organizacja danych} % może zbyt inżynierskieby -\chapter{Perspektywy na przyszłość} -Do napisania - \chapter{Podsumowanie} Do napisania @@ -421,4 +713,4 @@ Do napisania % \chapter{Wnioski} %%% Local Variables: %%% LaTeX-command: "latex -shell-escape" -%%% End: \ No newline at end of file +%%% End: