Zanurkuj w Pythonie/Wyciąganie danych z dokumentu HTML: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
zamiana {{Nawigacja|Python|->{{Nawigacja|Zanurkuj w Pythonie| [[Python/->[[../
Piotr (dyskusja | edycje)
poprawki
Linia 1:
{{Podświetl|py}}
== Wyciąganie danych z dokumentu HTML ==
 
Aby wyciągnąć dane z dokumentu HTML, tworzymy podklasę klasy <ttcode>SGMLParser</ttcode> i definiujemy dla encji lub każdego znacznika, który nas interesuje, odpowiednią metodę.
 
Pierwszym krokiem do wydobycia danych z dokumentu HTML jest zdobycie jakiegoś dokumentu. Jeśli posiadaszposiadamy jakiś dokument HTML na swoim twardym dysku, możeszmożemy wykorzystać [[../Praca na plikach|funkcje do obsługi plików]], aby go odczytać, jednak prawdziwa zabawa rozpocznierozpoczyna się, jeśligdy weźmieszweźmiemy HTML z istniejącej strony internetowej.
 
{{Python/Przykład
'''Przykład 8.5. Wprowadzenie do <tt>urllib</tt>'''
|8.5|Moduł <code>urllib</code>
|tekst=
<nowiki>
>>> import urllib #(1)
>>> sock = urllib.urlopen("http://diveintopython.org/") #(2)
>>> htmlSource = sock.read() #(3)
>>> sock.close() #(4)
>>> print htmlSource #(5)</nowiki>
{{samp|<nowiki><!DOCTYPE html
PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loosestrict.dtd">
<html><head 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'>
<title>Dive Into Python</title>
<link rev='made' href='mailto:mark@diveintopython.org'>
<link rel='"stylesheet'" href='"diveintopython.css'" type='"text/css'">
<meta name='keywords' content='Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free'>
<link rev='"made'" href='"mailto:markf8dy@diveintopython.org'">
<meta name='description' content='a free Python tutorial for experienced programmers'>
<meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
</head>
<meta name="description" content=" This book lives at .
<body bgcolor='white' text='black' link='#0000FF' vlink='#840084' alink='#0000FF'>
If you're reading it somewhere else, you may not have the latest version.">
<table cellpadding='0' cellspacing='0' border='0' width='100%'>
<meta name='"keywords'" content='"Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free'>
<tr><td class='header' width='1%' valign='top'>diveintopython.org</td>
documentation, book, free">
<td width='99%' align='right'><hr size='1' noshade></td></tr>
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://diveintopython.org/history.xml">
<tr><td class='tagline' colspan='2'>Python&nbsp;for&nbsp;experienced&nbsp;programmers</td></tr>
</head>
<body>
<table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
if href:<tr>
<td id="breadcrumb" colspan="6">&nbsp;</td>
</tr>
<tr>
<td colspan="3" id="logocontainer">
<h1 id="logo">Dive Into Python</h1>
<p id="tagline">Python from novice to pro</p>
</td>
[...ciach...]</nowiki>}}</nowiki>
 
# Moduł <ttcode>urllib</ttcode> jest częścią standardowej biblioteki Pythona. Zawiera on funkcje służące do pobierania informacji o danych, a także pobierania samych danych z internetu na podstawie adresu URL (głównie strony internetowe).
# Najprostszym sposobem wykorzystania <ttcode>urllib</ttcode>-a jest pobranie całego tekstu strony internetowej przy pomocy funkcji <ttcode>urlopen</ttcode>. Otworzenie URL-a jest równie proste, jak otworzenie pliku. Zwracana wartość funkcji <ttcode>urlopen</ttcode> przypomina normalny [[../Praca na plikach|obiekt pliku]] i posiada niektóre analogiczne metody identycznedo obiektu pliku.
# Najprostszą czynnością, którą możemy wykonać na obiekcie zwróconym przez <ttcode>urlopen</ttcode>, jest wywołanie <ttcode>read</ttcode>. Metoda ta odczyta cały HTML strony internetowej i zwróci go w postaci napisu, łańcucha znaków. Obiekt ten posiada także metodę <ttcode>readlines</ttcode>, która czyta tekst linia po linii, dodając kolejne linie do listy.
# Kiedy skończymy pracę na tym obiekcie, powinniśmy go jeszcze zamknąć za pomocą <ttcode>close</ttcode>, podobnie jak normalny plik.
# Mamy kompletny dokument HTML w postaci łańcucha znaków, pobrany ze strony domowej [http://diveintopython.org/ http://diveintopython.org/] i jesteśmy przygotowani do tego, aby go sparsować.
}}
 
'''Przykład 8.6. Wprowadzenie do <tt>urllister.py</tt>'''
 
Jeśli jeszcze tego nie zrobiłeś, możesz pobrać [http://diveintopython.org/download/diveintopython-examples-5.4.zip ten i inne przykłady] użyte w tej książce.
 
{{Python/Przykład
from sgmllib import SGMLParser
'''Przykład |8.6. |Wprowadzenie do <tt>{{Python/Src|urllister.py</tt>'''}}
|tekst=
<nowiki>from sgmllib import SGMLParser
class URLLister(SGMLParser):
def start_areset(self, attrs): #(21)
SGMLParser.reset(self)
self.urls.extend(href) = []
def start_a(self, attrs): #(2)
class URLLister(SGMLParser):
def reset(self): href = [v for k, v in attrs if k=='href'] #(3) #(14)
if SGMLParser.reset(self)href:
self.urls = [].extend(href)</nowiki>
def start_a(self, attrs): #(2)
href = [v for k, v in attrs if k=='href'] #(3) (4)
if href:
self.urls.extend(href)
 
# <ttcode>reset</ttcode> jest wywoływany przez metodę <ttcode>__init__</ttcode> <ttcode>SGMLParser</ttcode>-a, a także można go wywołać ręcznie już po utworzeniu instancji parsera. Zatem, jeśli potrzebujeszpotrzebujemy powtórnie zainicjalizować instancję parsera, który był wcześniej używany, zrobiszzrobimy to za pomocą <ttcode>reset</ttcode> (nie przez <ttcode>__init__</ttcode>). Nie ma potrzeby tworzenia nowego obiektu.
# Zawsze, kiedy parser odnajdzie znacznik <tt><nowiki><a></nowiki></tt>, wywoła metodę <ttcode>start_a</ttcode>. Znacznik może posiadać atrybut <ttcode>href</ttcode>, a także inne jak na przykład <ttcode>name</ttcode>, czy <ttcode>title</ttcode>. Parametr <ttcode>attrs</ttcode> jest listą krotek, <ttcode>[(atrybutatrybut1, wartośćwartość1), (atrybutatrybut2, wartośćwartość2), ...]</ttcode>. Znacznik ten może być także samym <ttcode><nowiki><a></nowiki></ttcode>, poprawnym (lecz bezużytecznym) znacznikiem HTML, a w tym przypadku <ttcode>attrs</ttcode> będzie pustą listą.
# Możemy stwierdzić, czy znacznik <ttcode><nowiki><a></nowiki></ttcode> posiada atrybut <tt>href</tt>, za pomocą prostego [[../Deklarowanie zmiennych#Wielozmienne przypisania|wielozmiennego]] [[../Odwzorowywanie listy|wyrażenie listowego]].
# Porównywanie napisów (np. <ttcode>k=='href'</ttcode>) jest zawsze wrażliwe na wielkość liter, lecz w tym przypadku jesttakie toużycie jest bezpieczne, ponieważ <ttcode>SGMLParser</ttcode> konwertuje podczas tworzenia <ttcode>attrs</ttcode> nazwy atrybutów na małe litery.
}}
 
{{Python/Przykład
'''Przykład |8.7. |Korzystanie z <tt>{{Python/Src|urllister.py</tt>'''}}
|tekst=
<nowiki>
>>> import urllib, urllister
Linia 64 ⟶ 80:
>>> usock.close() #(2)
>>> parser.close() #(3)
>>> for url in parser.urls: print url #(4)</nowiki>
{{samp|toc/index.html
#download
#languages
Linia 78 ⟶ 94:
download/diveintopython-common-5.0.zip
[... ciach ...]}}
... pozostała część pominięta dla czytelności ...
</nowiki>
 
# Wywołujemy metodę <ttcode>feed</ttcode> zdefiniowaną w <ttcode>SGMLParser</ttcode>, aby przekazać"nakarmić" parser przekazując mu kod HTML-a. doMetoda parserata przyjmuje łańcuch znaków, którym w tym przypadku będzie wartość zwrócona przez <refcode>usock.read()</code>.
# Podobnie jak pliki, powinieneśpowinniśmy zamknąć swoje obiekty URL, kiedy już nie będą ci potrzebne.
Technicznym określeniem parsera, takiego jak <tt>SGMLParser</tt>, jest konsument (ang. ''consumer''): konsumuje on HTML i rozkłada go. Przypuszczalnie nazwa <tt>feed</tt> (czyli ''karm'' w języku polskim) została wybrana, aby dopasować parser do takiego motywu „konsumenta”. W tym momencie, niektórym może przyjść na myśl zoo, w którym znajduje się ciemna klatka bez drzew, roślin i bez żadnych oznak życia. Jeśli będziesz bardzo cicho i przyglądniesz się bardzo dokładnie, to zobaczysz w odległym lewym rogu parę lśniących oczu spoglądających na ciebie, ale przekonujesz sam siebie, że to tylko twój mózg płata ci figle, a jedyną rzeczą, która ci mówi, że to co widzisz nie jest właściwie pustą klatką, jest mała, nieszkodliwa tabliczka na barierce z napisem „Nie karmić parsera”. Jednak jest to tylko interesujący obraz, stworzony przez wyobraźnię jednego z autorów tego podręcznika.
# Powinieneś także zamknąć obiekt parsera, lecz z innego powodu. Podczas czytania danych przekazujemy je do parsera, lecz metoda <ttcode>feed</ttcode> nie gwarantuje, że wszystkie przekazane dane, zostały przetworzone. Parser może te dane zbuforować i czekać na dalszą porcję danych. Kiedy wywołamy <ttcode>close</ttcode>, mamy pewność, że bufor zostanie opróżniony i wszystko zostanie całkowicie sparsowane.
</ref>. Metoda ta przyjmuje łańcuch znaków, którym w tym przypadku będzie wartość zwrócona przez <tt>usock.read()</tt>.
# Ponieważ parser został zamknięty, więc parsowanie zostało zakończone i <ttcode>parser.urls</ttcode> zawiera listę wszystkich URL-i, do których linki zawiera dokument HTML. (Twoje wyjście może wyglądać inaczej, ponieważ z biegiem czasu linki mogły ulec zmianie.)
# Podobnie jak pliki, powinieneś zamknąć swoje obiekty URL, kiedy już nie będą ci potrzebne.
}}
# Powinieneś także zamknąć obiekt parsera, lecz z innego powodu. Podczas czytania danych przekazujemy je do parsera, lecz metoda <tt>feed</tt> nie gwarantuje, że wszystkie przekazane dane, zostały przetworzone. Parser może te dane zbuforować i czekać na dalszą porcję danych. Kiedy wywołamy <tt>close</tt>, mamy pewność, że bufor zostanie opróżniony i wszystko zostanie całkowicie sparsowane.
# Ponieważ parser został zamknięty, więc parsowanie zostało zakończone i <tt>parser.urls</tt> zawiera listę wszystkich URL-i, do których linki zawiera dokument HTML. (Twoje wyjście może wyglądać inaczej, ponieważ z biegiem czasu linki mogły ulec zmianie.)
 
'''Przypisy'''
----
<references/>
 
<noinclude>
Linia 97 ⟶ 107:
[[../Wprowadzenie do BaseHTMLProcessor.py|Wprowadzenie do <tt>BaseHTMLProcessor.py</tt>]]|
}}
{{Podświetl|py}}
</noinclude>