Zanurkuj w Pythonie/Wyciąganie danych z dokumentu HTML

Z Wikibooks, biblioteki wolnych podręczników.
Skocz do: nawigacja, szukaj

Wyciąganie danych z dokumentu HTML[edytuj]

Aby 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...]
  1. 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).
  2. Najprostszym sposobem wykorzystania urllib-a jest pobranie całego tekstu strony internetowej przy pomocy funkcji urlopen. Otworzenie URL-a jest równie proste, jak otworzenie pliku. Zwracana wartość funkcji urlopen przypomina normalny obiekt pliku i posiada niektóre analogiczne metody do obiektu pliku.
  3. Najprostszą czynnością, którą możemy wykonać na obiekcie zwróconym przez urlopen, jest wywołanie read. 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.
  4. Kiedy skończymy pracę na tym obiekcie, powinniśmy go jeszcze zamknąć za pomocą close, podobnie jak normalny plik.
  5. 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)
  1. 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.
  2. Zawsze, kiedy parser odnajdzie znacznik <a>, wywoła metodę start_a. Znacznik może posiadać atrybut href, a także inne jak na przykład name, czy title. Parametr attrs 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 przypadku attrs będzie pustą listą.
  3. Możemy stwierdzić, czy znacznik <a> posiada atrybut href, za pomocą prostego wielozmiennego wyrażenie listowego.
  4. 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 tworzenia attrs 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 ...]
  1. Wywołujemy metodę feed zdefiniowaną w SGMLParser, 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 przez usock.read().
  2. Podobnie jak pliki, powinniśmy zamknąć swoje obiekty URL, kiedy już nie będą ci potrzebne.
  3. 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łamy close, mamy pewność, że bufor zostanie opróżniony i wszystko zostanie całkowicie sparsowane.
  4. 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.)