Zanurkuj w Pythonie/Wprowadzenie do sgmllib.py

Wprowadzenie do sgmllib.py edytuj

Przetwarzanie HTML-a jest podzielone na trzy etapy: podzielenie dokumentu na elementy składowe, manipulowanie tymi elementami i ponowna rekonstrukcja tych kawałków do HTML-a. Pierwszy krok jest wykonywany przez sgmllib.py, który jest częścią standardowej biblioteki Pythona.

Kluczem do zrozumienia tego rozdziału jest uświadomienie sobie, że HTML to nie tylko tekst, jest to tekst z pewną strukturą. Struktura ta powstaje z mniej lub bardziej hierarchicznych sekwencji znaczników początkowych i znaczników końcowych. Zazwyczaj nie pracujemy z HTML-em w sposób strukturalny, raczej tekstowo w edytorze tekstu lub wizualnie w przeglądarce internetowej, czy innym narzędziu. sgmllib.py prezentuje HTML strukturalnie.

sgmllib.py zawiera jedną ważną klasę: SGMLParser. SGMLParser rozbiera HTML na użyteczne kawałki takie jak znaczniki początkowe i znaczniki końcowe. Jak tylko udaje mu się rozebrać jakieś dane na przydatne kawałki, wywołuję odpowiednią metodę, w zależności co zostało znalezione. Żeby wykorzystać parser, tworzymy podklasę SGMLParser-a i nadpisujemy te metody. Mówiąc, że sgmllib.py prezentuje HTML strukturalnie, mieliśmy na myśli to, że struktura dokumentu HTML jest określana poprzez wywoływane metody, a także argumenty przekazywane do tych metod.

SGMLParser parsuje HTML na 8 rodzajów danych i wykonuje odpowiednie metody dla każdego z nich:

Znacznik początkowy
Znacznik HTML, który rozpoczyna blok np. <html>, <head>, <body> lub <pre> lub samodzielne znaczniki jak <br> lub <img>. Kiedy odnajdzie znacznik tagname, to SGMLParser będzie szukał metod o nazwie start_tagname lub do_tagname. Na przykład, jeśli odnajdzie znacznik <pre>, to będzie szukał metod start_pre lub do_pre . Jeśli je znajdzie, SGMLParser wywoła te metody z listą atrybutów tego znacznika. W przeciwnym wypadku wywoła unknown_starttag z nazwą znacznika i listą atrybutów.
Znacznik końcowy
Znacznik HTML, który kończy blok np. </html>, </head>, </body> lub </pre>. Kiedy odnajdzie znacznik końcowy, SGMLParser będzie szukał metody o nazwie end_tagname. Jeśli ją znajdzie, wywoła tę metodę, jeśli nie, wywoła metodę unknown_endtag z nazwą znacznika.
Odwołania znakowe
Znak specjalny, do którego dowołujemy się podając jego dziesiętny lub szesnastkowy odpowiednik np. &#160;. Kiedy odwołanie znakowe zostanie odnalezione, SGMLParser wywoła handle_charref z tekstem dziesiętnego lub szesnastkowego odpowiednika znaku.
Odwołanie do encji
Encja HTML to np. &copy;. Kiedy zostanie znaleziona, SGMLParser wywołuje handle_entityref z nazwą encji.
Komentarz
Element HTML, który jest ograniczony przez <!-- ... -->. Kiedy zostanie znaleziony, SGMLParser wywołuje handle_comment z zawartością komentarza.
Instrukcje przetwarzania
Instrukcje przetwarzania HTML są ograniczone przez <? ... >. Kiedy zostaną odnalezione, SGMLParser wywołuje handle_pi z zawartością instrukcji przetwarzania.
Deklaracja
Deklaracja HTML np. typu dokumentu (DOCTYPE), jest ograniczona przez <! ... >. Kiedy zostanie znaleziona, SGMLParser wywołuje handle_decl z zawartością deklaracji.
Dane tekstowe
Bloki tekstu. Wszystko inne, co się nie mieści w innych 7 kategoriach. Kiedy zostaną one znalezione, SGMLParser wywoła handle_data z tekstem.

sgmllib.py posiada zestaw testów, które to ilustrują. Możemy uruchomić sgmllib.py, podając w linii poleceń nazwę pliku, a będzie on wyświetlał znaczniki i inne elementy podczas parsowania. Zrobione jest to poprzez utworzenie podklasy SGMLParser i zdefiniowanie metod unknown_starttag, unknown_endtag, handle_data i innych metod, które będą po prostu wyświetlać swoje argumenty.

Przykład. Test sgmllib.py
c:\python23\lib> type "c:\downloads\diveintopython\html\toc\index.html"
<!DOCTYPE html
   PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <html lang="en">
    <head>
       <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    
       <title>Dive Into Python</title>
       <link rel="stylesheet" href="diveintopython.css" type="text/css">
 
 [...ciach...]

Tutaj jest kawałek spisu treści angielskiej wersji tej książki, w HTML-u. Oczywiście ścieżki do plików możesz mieć trochę inne. (Angielską wersję tej książki, w formacie HTML, możesz znaleźć na http://diveintopython.org/.)

Uruchomiając to za pomocą zestawu testów sgmllib.py, zobaczymy:

c:\python23\lib> python sgmllib.py "c:\downloads\diveintopython\html\toc\index.html"

data: '\n\n' start tag: <html lang="en" > data: '\n ' start tag: <head> data: '\n ' start tag: <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" > data: '\n \n ' start tag: <title> data: 'Dive Into Python' end tag: </title> data: '\n ' start tag: <link rel="stylesheet" href="diveintopython.css" type="text/css" > data: '\n ' [...ciach...]

Taki jest plan reszty tego rozdziału:

  • Dziedziczymy po SGMLParser, aby stworzyć klasy, które wydobywają interesujące dane z dokumentu HTML.
  • Dziedziczymy po SGMLParser, aby stworzyć podklasę BaseHTMLProcessor, która nadpisuje wszystkie 8 metod obsługi i wykorzystujemy je, aby zrekonstruować oryginalny dokument HTML z otrzymywanych kawałków.
  • Dziedziczymy po BaseHTMLProcessor, aby utworzyć Dialectizer, który dodaje kilka metod w celu specjalnego przetworzenia określonych znaczników HTML. Ponadto nadpisuje metodę handle_data, aby zapewnić możliwość przetwarzania bloków tekstowych pomiędzy znacznikami HTML.
  • Dziedziczymy po Dialectizer, aby stworzyć klasy, które definiują zasady przetwarzania tekstu wykorzystane w Dialectizer.handle_data.
  • Piszemy zestaw testów, które korzystają z prawdziwej strony internetowej, http://diveintopython.org/, i ją przetwarzają.

Przy okazji dowiemy się, czym jest locals i globals, a także jak formatować łańcuchy znaków za pomocą słowników.