This commit is contained in:
siulkilulki 2018-06-16 16:34:53 +02:00
parent c7160d1f6b
commit ae41d0ccb7
11 changed files with 512 additions and 216 deletions

View File

@ -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},

View File

@ -1 +1 @@
<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36" version="8.6.5" editor="www.draw.io" type="device"><diagram id="cb6c6256-43c7-094e-4ab5-cf55f2e6a3c1" name="Page-1">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</diagram></mxfile>
<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" version="8.7.10" editor="www.draw.io" type="device"><diagram id="cb6c6256-43c7-094e-4ab5-cf55f2e6a3c1" name="Page-1">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</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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

View File

@ -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}\;
\nl\uIf{\File puste {\bf or} \File dekodowalne jako unikod}{
\nl \Return{\False}\;
}\ElseIf{znak \Null \bf in \File}{
\nl \Return{\True}\;
}
\Return{\False}\;
\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[]dek.(liturgi|mszy)| (rozk[]ad|plan|godziny|uk[]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