Zanurkuj w Pythonie/Wyciąganie danych z dokumentu HTML
Wyciąganie danych z dokumentu HTML
edytujAby wyciągnąć dane z dokumentu HTML, tworzymy podklasę klasy SGMLParser
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 posiadamy jakiś dokument HTML na swoim twardym dysku, możemy wykorzystać funkcje do obsługi plików, aby go odczytać, jednak prawdziwa zabawa rozpoczyna się, gdy weźmiemy HTML z istniejącej strony internetowej.
Przykład. Moduł
urllib
>>> import urllib #(1)
>>> sock = urllib.urlopen("http://diveintopython.org/") #(2)
>>> htmlSource = sock.read() #(3)
>>> sock.close() #(4)
>>> print htmlSource #(5)
<!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">
<link rev="made" href="mailto:f8dy@diveintopython.org">
<meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
<meta name="description" content=" This book lives at .
If you're reading it somewhere else, you may not have the latest version.">
<meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming,
documentation, book, free">
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://diveintopython.org/history.xml">
</head>
<body>
<table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
<tr>
<td id="breadcrumb" colspan="6"> </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...]
- Moduł
urllib
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
urllib
-a jest pobranie całego tekstu strony internetowej przy pomocy funkcjiurlopen
. Otworzenie URL-a jest równie proste, jak otworzenie pliku. Zwracana wartość funkcjiurlopen
przypomina normalny obiekt pliku i posiada niektóre analogiczne metody do obiektu pliku. - Najprostszą czynnością, którą możemy wykonać na obiekcie zwróconym przez
urlopen
, jest wywołanieread
. Metoda ta odczyta cały HTML strony internetowej i zwróci go w postaci łańcucha znaków. Obiekt ten posiada także metodęreadlines
, 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ą
close
, podobnie jak normalny plik. - Mamy kompletny dokument HTML w postaci łańcucha znaków, pobrany ze strony domowej http://diveintopython.org/ i jesteśmy przygotowani do tego, aby go sparsować.
Przykład. Wprowadzenie do urllister.py
from sgmllib import SGMLParser
class URLLister(SGMLParser):
def reset(self): #(1)
SGMLParser.reset(self)
self.urls = []
def start_a(self, attrs): #(2)
href = [v for k, v in attrs if k=='href'] #(3) (4)
if href:
self.urls.extend(href)
reset
jest wywoływany przez metodę__init__
SGMLParser
-a, a także można go wywołać ręcznie już po utworzeniu instancji parsera. Zatem, jeśli potrzebujemy powtórnie zainicjalizować instancję parsera, który był wcześniej używany, zrobimy to za pomocąreset
(nie przez__init__
). Nie ma potrzeby tworzenia nowego obiektu.- Zawsze, kiedy parser odnajdzie znacznik <a>, wywoła metodę
start_a
. Znacznik może posiadać atrybuthref
, a także inne jak na przykładname
, czytitle
. Parametrattrs
jest listą krotek[(atrybut1, wartość1), (atrybut2, wartość2), ...]
. Znacznik ten może być także samym<a>
, poprawnym (lecz bezużytecznym) znacznikiem HTML, a w tym przypadkuattrs
będzie pustą listą. - Możemy stwierdzić, czy znacznik
<a>
posiada atrybut href, za pomocą prostego wielozmiennego wyrażenie listowego. - Porównywanie napisów (np.
k=='href'
) jest zawsze wrażliwe na wielkość liter, lecz w tym przypadku takie użycie jest bezpieczne, ponieważSGMLParser
konwertuje podczas tworzeniaattrs
nazwy atrybutów na małe litery.
Przykład. Korzystanie z urllister.py
>>> import urllib, urllister
>>> usock = urllib.urlopen("http://diveintopython.org/")
>>> parser = urllister.URLLister()
>>> parser.feed(usock.read()) #(1)
>>> usock.close() #(2)
>>> parser.close() #(3)
>>> for url in parser.urls: print url #(4)
toc/index.html
#download
#languages
toc/index.html
appendix/history.html
download/diveintopython-html-5.0.zip
download/diveintopython-pdf-5.0.zip
download/diveintopython-word-5.0.zip
download/diveintopython-text-5.0.zip
download/diveintopython-html-flat-5.0.zip
download/diveintopython-xml-5.0.zip
download/diveintopython-common-5.0.zip
[... ciach ...]
- Wywołujemy metodę
feed
zdefiniowaną wSGMLParser
, aby "nakarmić" parser przekazując mu kod HTML-a. Metoda ta przyjmuje łańcuch znaków, którym w tym przypadku będzie wartość zwrócona przezusock.read()
. - Podobnie jak pliki, powinniśmy 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
feed
nie gwarantuje, że wszystkie przekazane dane, zostały przetworzone. Parser może te dane zbuforować i czekać na dalszą porcję danych. Kiedy wywołamyclose
, 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
parser.urls
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.)