W tej sekcji przyjrzymy się kilku dostępnym w języku Python modułom użytkowym służącym do rozwiązywania typowych problemów.
System plików – os, os.path, snapshotil
Moduły *os* i *os.path* zawierają wiele funkcji umożliwiających interakcję z systemem plików. Moduł *shutil* może kopiować pliki.
- dokumentacja modułu OS
- filenames = os.listdir(dir) – lista nazw plików w ścieżce danego katalogu (z wyłączeniem plików . i ..). Nazwy plików to tylko nazwy w katalogu, a nie ich ścieżki bezwzględne.
- os.path.join(dir, filename) -- jeśli masz nazwę pliku z powyższej listy, użyj tej opcji, aby umieścić zarówno dir, jak i nazwę pliku w celu utworzenia ścieżki
- os.path.abspath(path) – dla danej ścieżki zwraca wartość bezwzględną, np. /home/nick/foo/bar.html
- os.path.dirname(path), os.path.basename(path) -- dany katalog/foo/bar.html zwraca nazwę katalogu „dir/foo” i nazwa bazowa „bar.html”
- os.path.exists(path) – true, jeśli istnieje
- os.mkdir(dir_path) -- tworzy jeden dir, os.makedirs(dir_path) tworzy wszystkie wymagane dir w tej ścieżce
- openil.copy(source-path, dest-path) – kopiowanie pliku (powinny istnieć katalogi ścieżki doc)
## Example pulls filenames from a dir, prints their relative and absolute paths def printdir(dir): filenames = os.listdir(dir) for filename in filenames: print(filename) ## foo.txt print(os.path.join(dir, filename)) ## dir/foo.txt (relative to current dir) print(os.path.abspath(os.path.join(dir, filename))) ## /home/nick/dir/foo.txt
Poznawanie modułu dobrze sprawdza się z wbudowanymi funkcjami help() i dir() języka Python. W tłumaczeniu wykonaj polecenie „import os”, a następnie za pomocą tych poleceń sprawdź, jakie elementy są dostępne w module: dir(os), help(os.listdir), dir(os.path), help(os.path.dirname).
Uruchamianie procesów zewnętrznych – podproces
Moduł *subprocess* to prosty sposób na uruchamianie polecenia zewnętrznego i rejestrowanie jego danych wyjściowych.
- dokumentacja modułu podprocesu
- output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) – uruchamia polecenie, czeka na jego zakończenie i zwraca tekst wyjściowy. Polecenie jest uruchamiane ze standardowymi danymi wyjściowymi i błędami standardowymi połączonymi w jeden tekst wyjściowy. W przypadku niepowodzenia zwraca błąd CalledProcessError.
- Jeśli chcesz mieć większą kontrolę nad uruchamianiem podprocesu, zapoznaj się z klasą subprocess.popen.
- Istnieje też prosty subprocess.call(cmd), który uruchamia polecenie i umieszcza dane wyjściowe w danych wyjściowych i zwraca kod błędu. Sprawdza się to, gdy chcesz uruchomić polecenie, ale nie musisz przechwytywać danych wyjściowych w strukturach danych w języku Python.
import subprocess ## Given a dir path, run an external 'ls -l' on it -- ## shows how to call an external program def listdir(dir): cmd = 'ls -l ' + dir print("Command to run:", cmd) ## good to debug cmd before actually running it (status, output) = subprocess.getstatusoutput(cmd) if status: ## Error case, print the command's output to stderr and exit sys.stderr.write(output) sys.exit(status) print(output) ## Otherwise do something with the command's output
Wyjątki
Wyjątek stanowi błąd czasu działania, który zatrzymuje normalne wykonywanie w danym wierszu i przekazuje kontrolę do kodu obsługi błędów. W tej sekcji opisujemy tylko podstawowe zastosowania wyjątków. Na przykład błąd czasu działania może wynikać z tego, że zmienna używana w programie nie ma wartości (ValueError .. sporadycznie występuje to kilka razy) lub wystąpił błąd operacji otwierania pliku z powodu braku pliku (IOError). Więcej informacji znajdziesz w samouczku oraz na całej liście wyjątków.
Bez kodu obsługi błędów (tak jak dotychczas) wyjątek czasu działania powoduje tylko zatrzymanie programu i wyświetlenie komunikatu o błędzie. To dobre zachowanie domyślne, które widzieliśmy już wiele razy. Możesz użyć polecenia „try/except”, do obsługi wyjątków, na przykład:
try: ## Either of these two lines could throw an IOError, say ## if the file does not exist or the read() encounters a low level error. f = open(filename, 'rb') data = f.read() f.close() except IOError: ## Control jumps directly to here if any of the above lines throws IOError. sys.stderr.write('problem reading:' + filename) ## In any case, the code then continues with the line after the try/except
Sekcja try: zawiera kod, który może zgłosić wyjątek. Sekcja wyjątkiem: zawiera kod, który ma zostać uruchomiony w przypadku wystąpienia wyjątku. Jeśli nie ma wyjątku, pomijana jest sekcja z wyjątkiem: (czyli kod służy jedynie do obsługi błędów, a nie „normalny” przypadek kodu). Możesz uzyskać wskaźnik do samego obiektu wyjątku ze składnią „poza IOError jako e: ..”. (wskaźnik e wskazuje obiekt wyjątku).
HTTP – urllib i urlparse
Moduł *urllib.request* umożliwia pobieranie adresów URL – przez co adres URL wygląda jak plik, z którego można odczytać dane. Moduł *urlparse* może rozkładać strony i łączyć ze sobą adresy URL.
- Dokumentacja modułu urllib.request
- ufile = urllib.request.urlopen(url) -- zwraca plik podobny do obiektu w przypadku danego adresu URL.
- text = ufile.read() – może z niego odczytywać dane podobnie jak plik (readlines() itp. również działają).
- info = ufile.info() -- metadane dla tego żądania. info.gettype() to typ MIME, np. „text/html”
- baseurl = ufile.geturl() -- pobiera "base" url żądania, który może się różnić od pierwotnego z powodu przekierowań
- urllib.request.urlretrieve(url, nazwa pliku) – pobiera dane z URL-a pod podaną ścieżkę pliku
- urllib.parse.urljoin(baseurl, url) -- podany adres URL, który może (ale nie musi) być pełny, oraz baseurl strony, z której pochodzi, zwraca pełny adres URL. Użyj metody geturl() powyżej, aby podać podstawowy adres URL.
Wszystkie wyjątki znajdują się w pliku urllib.error.
from urllib.request import urlopen ## Given a url, try to retrieve it. If it's text/html, ## print its base url and its text. def wget(url): ufile = urlopen(url) ## get file-like object for url info = ufile.info() ## meta-info about the url content if info.get_content_type() == 'text/html': print('base url:' + ufile.geturl()) text = ufile.read() ## read all its text print(text)
Powyższy kod działa prawidłowo, ale nie obejmuje obsługi błędów, jeśli z jakiegoś powodu adres URL nie działa. Oto wersja funkcji, która dodaje logikę try/except, aby wyświetlić komunikat o błędzie, jeśli operacja związana z adresem URL się nie powiedzie.
Jeśli urlopen()
wydaje się zawieszać, system może nie zezwalać na bezpośredni dostęp do niektórych
adresy http. Możesz to sprawdzić, próbując pobrać ten sam adres URL za pomocą polecenia wget
lub
curl
Jeśli te programy także zawiodą, trzeba będzie pobrać treść HTTP za pośrednictwem serwera proxy
posprzedażna. Samouczek nie omawia konfigurowania dostępu przez serwer proxy.
## Version that uses try/except to print an error message if the ## urlopen() fails. def wget2(url): try: ufile = urlopen(url) if ufile.info().get_content_type() == 'text/html': print(ufile.read()) except IOError: print('problem reading url:', url)
Ćwiczenie
Aby przećwiczyć korzystanie z systemu plików i materiałów poleceń zewnętrznych, zapoznaj się z odpowiednim ćwiczeniem polegającym na kopiowaniu. Aby poćwiczyć materiał urllib, zobacz Ćwiczenie z łamigłówkami.