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: