diff --git a/bibliografia.bib b/bibliografia.bib index 255d476..61eafa8 100644 --- a/bibliografia.bib +++ b/bibliografia.bib @@ -33,4 +33,82 @@ Fourteenth International Conference on Computational Linguistics, Nantes, France pages={87--112}, year={1994}, publisher={Springer} +} + + +@article{gus, + title={Rocznik statystyczny Rzeczypospolitej Polskiej 2017}, + author={Dominik Rozkrut i in}, + journal={GUS}, + volume={T. LXXVII}, + pages={194--195}, + year={2016} + @Comment publisher={} +} + +@misc{beautiful_soup, + title = {BeautifulSoup}, + note = {Crummy.org}, + key = {BeautifulSoup}, + howpublished={\url{https://www.crummy.com/software/BeautifulSoup/}} +} +@misc{expotential_backoff} +@misc{google_api} +@misc{text_search} +@misc{place_detail} +@misc{jsonline} +@misc{binaryornot} +@misc{html2text} +@misc{markdown} +@article{parallel, + title = {GNU Parallel - The Command-Line Power Tool}, + author = {O. Tange}, + address = {Frederiksberg, Denmark}, + journal = {;login: The USENIX Magazine}, + month = {Feb}, + number = {1}, + volume = {36}, + url = {http://www.gnu.org/s/parallel}, + year = {2011}, + pages = {42-47} +} +@techreport{RFC2045, + author = {Ned Freed and Nathaniel S. Borenstein}, + title = {Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies}, + howpublished = {Internet Requests for Comments}, + type = {RFC}, + number = {2045}, + year = {1996}, + month = {November}, + issn = {2070-1721}, + publisher = {RFC Editor}, + institution = {RFC Editor}, + url = {http://www.rfc-editor.org/rfc/rfc2045.txt}, + note = {\url{http://www.rfc-editor.org/rfc/rfc2045.txt}}, +} +@techreport{RFC7231, + author = {R. Fielding and J. Reschke}, + title = {Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content}, + howpublished = {Internet Requests for Comments}, + type = {RFC}, + number = {7231}, + year = {2014}, + month = {June}, + issn = {2070-1721}, + publisher = {RFC Editor}, + institution = {RFC Editor}, + url = {http://www.rfc-editor.org/rfc/rfc7231.txt}, + note = {\url{http://www.rfc-editor.org/rfc/rfc7231.txt}}, +} +@techreport{RFC6266, + author = {J. Reschke}, + title = {Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)}, + howpublished = {Internet Requests for Comments}, + type = {RFC}, + number = {6266}, + year = {2011}, + month = {June}, + issn = {2070-1721}, + publisher = {RFC Editor}, + institution = {RFC Editor}, } \ No newline at end of file diff --git a/img/crawler_adresow.png b/img/crawler_adresow.png index fd6026e..ec1d0c3 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 7d4c15b..2145b9a 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 c70550f..cf86fff 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 c18ccc8..a646a14 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 de67930..5e2fe50 100644 Binary files a/img/crawler_url_trans.png and b/img/crawler_url_trans.png differ diff --git a/rozdzial_3.tex b/rozdzial_3.tex index afee95f..7470900 100644 --- a/rozdzial_3.tex +++ b/rozdzial_3.tex @@ -1,15 +1,18 @@ +\chapter{Podstawy teoretyczne} \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 +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. 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. -Każda godzina wraz z kontekstem w jakim się znajduje trafia do \textit{systemu - crowdsourcing'owego}, gdzie jest annotowana jako poprawna lub niepoprawna godzina mszy świętej. +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 @@ -21,18 +24,16 @@ Finalny ekstraktor godzin mszy świętych utworzony zostaje z połączenia ekstraktora regułowego z ekstraktorem opartym na uczeniu maszynowym. % \bigskip -% \newpage \begin{figure}[tbh!] \center \includegraphics[width=1\hsize]{struktura_wyszukiwarki.png} -\caption{Struktura ekstraktora godzin mszy świętych.} +\caption{Architektura ekstraktora godzin mszy świętych.} \label{struktura_pic} \end{figure} \newpage \section{Zbieranie informacji o parafiach} - \begin{figure}[tbh!] \center \includegraphics[width=0.7\hsize]{crawler_adresow_trans.png} @@ -40,7 +41,7 @@ ekstraktora regułowego z ekstraktorem opartym na uczeniu maszynowym. \end{figure} 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 - danych statystycznych GUS z 2016 roku w Polsce było + danych statystycznych GUS\cite{gus} z 2016 roku w Polsce było 10255 parafii. Dla każdej parafii zebrano: @@ -52,12 +53,12 @@ Dla każdej parafii zebrano: \item nazwę dekanatu do którego należy, \item nazwę diecezji do której przynależy. \end{itemize} - Do wydobycia danych został użyty skrypt w pythonie, który korzystał z parsera - html z biblioteki BeautifulSoup. Przy wysyłaniu zapytań do serwisu deon.pl zastosowano - algorym \textit{Expotential Backoff} REF, który prezentuje się następująco: + 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 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 @@ -67,7 +68,7 @@ Dla każdej parafii zebrano: zapobiega zbyt częstemu odpytywaniu serwisu kiedy ten nie daje sobie rady ze zbyt dużą liczbą zapytań. -\begin{table} +\begin{table}[H] \centering \def\arraystretch{1.1} \begin{tabular}{ l l l l l l } @@ -94,17 +95,17 @@ nazwy parafii, jej miejscowości i ulicy na której się znajduje. Wyszukiwarka zadowalające wyniki, jednak po kilkunastu zapytaniach blokowała adres ip. W dodatku w warunkach użytkowania serwisu i w robots.txt Google zabrania korzystania z pająków na ich wyszukiwarce. -DuckDuckGo nie blokowało adresu ip, ale zabraniało \textit{crawlowania} w robots.txt i słabo radziło sobie z polskimi +DuckDuckGo nie blokowało adresu ip, ale zabraniało crawlowania w robots.txt i słabo radziło 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ł +rozwiązania -- z wielu wyników wyszukiwania trzeba było wybrać ten, który zawierał 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} REF. Serwis \textit{Text Search} REF pozwala na wyszukanie miejsca +\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} REF, aby wyciągnąć więcej +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. Jedynym minusem jest ograniczenie liczby zapytań do 1000 na 24 godziny. W @@ -135,11 +136,11 @@ Powyższą metodą udało się zebrać adresy url dla ok. 5600 parafii. -\section{\textit{Crawlowanie} stron parafialnych} +\section{Crawlowanie stron parafialnych} \begin{figure}[tbh] \center -\includegraphics[width=0.7\hsize]{crawler_parafii_general.png} +\includegraphics[width=0.7\hsize]{crawler_parafii_general_trans.png} \label{crawler_parafii_general_pic} \end{figure} Crawler został napisany przy użyciu biblioteki Scrapy. @@ -151,21 +152,21 @@ asynchronicznie wysłać wiele zapytań do serwera i odbierać wiele odpowiedzi \subsection{Komponenty pająka} \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 + \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] -- jego zadniem jest ściąganie stron parafialnych i przekazywanie ich silnikowi. - \item [Przetwarzacz danych] - zajmuje się końcową obróbką i zapisem danych. + \item [Przetwarzacz 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 linkami podążać. - \item [Spider middleware] - programy pośredniczące między silnkiem, 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 [Downloader middleware] - programy pośredniczące między silnikiem, 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. @@ -174,7 +175,8 @@ asynchronicznie wysłać wiele zapytań do serwera i odbierać wiele odpowiedzi \subsection{Przepływ danych} Przepływ danych kontrolowany jest przez -silnik i prezentuje się następująco: +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}: \begin{figure}[tbh] \center @@ -201,7 +203,7 @@ silnik i prezentuje się następująco: 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 REF. Następnie przekazuje nowe żądania do zakolejkowania + pliku jsonline\cite{jsonline}. Następnie przekazuje nowe żądania do zakolejkowania dyspozytorowi. \end{enumerate} % \vspace*{-20mm} @@ -210,13 +212,13 @@ silnik i prezentuje się następująco: \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 -zatem zadbać o to aby nie pobierać danych binarnych takich jak np. video, audio +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 następujących kryteriach: \begin{itemize} -\item wartościach \mintinline{bash}{Content-type}, \mintinline{bash}{Content-Encoding} i \mintinline{bash}{Content-Disposition} w nagłówku odpowiedzi, +\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ę @@ -224,11 +226,10 @@ następujących kryteriach: \end{itemize} 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 -https://tools.ietf.org/html/rfc7231 section-3.1.1.5. -UZU Dla przykładu potrafi zwórcić \mintinline{bash}{Content-Type: text/html}, a w \mintinline{bash}{body} binarną -zawartość np. film. -Ze względu na tego rodzaju anomalie zastosowano następujący algorytm REF. +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ą +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{4\baselineskip} @@ -282,8 +283,8 @@ regulować częstość zapytań w zależności od obciążenia crawler'a i stron \begin{enumerate} \item Przyjmijmy, że: - \subitem {\makebox[4.55cm][l]{\mintinline{python}{download_delay}\footnote{Czasy oczekiwania i - opóźnienia liczone są w sekudnach.}}} to opóźnienie wysłania + \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. @@ -298,10 +299,11 @@ regulować częstość zapytań w zależności od obciążenia crawler'a i stron \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} + \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ż i większy niż . + \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ę. \end{enumerate} @@ -316,30 +318,103 @@ regulować częstość zapytań w zależności od obciążenia crawler'a i stron \subsection{Crawlowanie wieloprocesorowe} -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 crawlowane jest jednocześnie 100 parafii. - -\begin{figure}[tbh] +\begin{figure}[tbh!] \center -\includegraphics[width=0.7\hsize]{crawler.png} +\includegraphics[width=0.72\hsize]{crawler.png} \caption{100 crawlerów pracujących jednocześnie.} \label{crawler_pic} \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 +maksymalnie wykorzystać łącze internetowe, które było wąskim gardłem w procesie +crawlowania stron parafialnych. + + +\subsection{Organizacja danych} +Mały podrozdział do zrobienia lub pominięcia. \subsection{Konwersja html na tekst.} +\begin{figure}[tbh] +\center +\includegraphics[width=0.6\hsize]{html2text_trans.png} +\label{hmlt2text_pic} +\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 +konwersji i jest bardzo łatwa w modyfikacji. + +\smallskip +\noindent Zastosowano następujące opcje i modyfikacje przy konwersji: +\vspace{-2mm} +\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. +\end{itemize} + +\section{Ekstraktor godzin} +\begin{figure}[tbh!] +\center +\includegraphics[width=0.6\hsize]{general_ekstraktor.png} +\label{general_ekstraktor_pic} +\end{figure} +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ę. + 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. + + 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: +\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 + \mintinline{python}{{',', '('}}; + \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}{')'}. +\end{enumerate} + \section{System crowdsourcingowy} -\section{Ekstraktor regułowy} -\section{Ekstraktor oparty na uczeniu maszynowym} +\begin{figure}[tbh!] +\center +\includegraphics[width=0.6\hsize]{annotator.png} +\label{annotator_pic} +\end{figure} +System crowdsourcingowy 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. +Do dokończenia + +\section{Regułowy ekstraktor godzin mszy} +Do napisania +\section{Ekstraktor godzin mszy oparty na uczeniu maszynowym} +Do napisania +\subsection{Model teoretyczny} +\subsection{FastText} \chapter{Rezultaty} +Do napisania % \section{Organizacja danych} % może zbyt inżynierskieby \chapter{Perspektywy na przyszłość} +Do napisania + \chapter{Podsumowanie} +Do napisania % \subsection{Ewaluacja wewnętrzna} %F1 score % \subsection{Ewaluacja zewnętrzna} % w systemie webowym, użytkownicy