今回は、Pythonでzipファイルを解凍(展開)する方法についてご紹介します。
zipファイルは複数のファイルを一つにまとめ、圧縮してサイズを小さくできる便利な形式です。
Pythonではzipfileモジュールを活用することで、プログラムから簡単に解凍(展開)作業が行えます。
ここでは基本的な解凍方法から安全に解凍するための方法、そしてよくあるエラーへの対処法を順に見ていきます。
Pythonでzipファイルを解凍する基本的な方法
まずはzipfileモジュールを使った、最もシンプルな解凍方法を確認します。
以下の例では、extractall()メソッドでzipファイル内の全てのファイルを一度に展開しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import zipfile import os zip_path = "sample.zip" extract_dir = "extracted_files" # 展開先のディレクトリが存在しない場合は作成 if not os.path.exists(extract_dir): os.makedirs(extract_dir) # zipファイルを開いて全ファイルを解凍 with zipfile.ZipFile(zip_path, "r") as zip_ref: zip_ref.extractall(extract_dir) print("解凍が完了しました。") |
解凍が完了しました。
この方法では、zipファイル内の全てのファイルがextract_dirに展開されます。
指定したディレクトリが存在しない場合は、os.makedirs()であらかじめ作成しておくのが一般的です。
個別ファイルの解凍
次に、zipファイル内の特定のファイルだけを解凍する方法を紹介します。
以下の例ではnamelist()でファイル名一覧を取得し、条件に合うファイルのみextract()で展開しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import zipfile import os zip_path = "sample.zip" target_dir = "extracted_specific" if not os.path.exists(target_dir): os.makedirs(target_dir) with zipfile.ZipFile(zip_path, "r") as zip_ref: # Zip内のファイル名一覧を取得 file_list = zip_ref.namelist() print("含まれているファイル:", file_list) # 特定の拡張子(例:.txt)のファイルだけを抽出 for file_name in file_list: if file_name.endswith(".txt"): print(f"抽出中: {file_name}") zip_ref.extract(file_name, target_dir) print("指定ファイルのみの解凍が完了しました。") |
含まれているファイル: [‘data1.txt’, ‘data2.csv’, ‘image.png’]
抽出中: data1.txt
指定ファイルのみの解凍が完了しました。
このようにextract()を使うと、条件を指定してピンポイントで必要なファイルのみ解凍できます。
大量のファイルが含まれるzipを扱う際や、特定の種類のファイルだけを取り出したい場合に便利です。
パスワード保護されたzipファイルの解凍
zipファイルがパスワード保護されている場合は、setpassword()メソッドにバイト文字列としてパスワードを指定します。
下記の例ではpasswordという変数にあらかじめパスワードを設定し、extractall()で解凍します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import zipfile import os zip_path = "encrypted.zip" extract_dir = "extracted_encrypted" password = b"your_password" # パスワードはバイト文字列で指定 if not os.path.exists(extract_dir): os.makedirs(extract_dir) with zipfile.ZipFile(zip_path, "r") as zip_ref: zip_ref.setpassword(password) zip_ref.extractall(extract_dir) print("暗号化されたZipファイルの解凍が完了しました。") |
暗号化されたZipファイルの解凍が完了しました。
暗号化方式によっては、zipfileモジュールが対応していない場合があります。
その場合はpyzipperなどのサードパーティ製ライブラリを検討する必要があります。
安全な解凍(Zip Slip対策)
zipファイルには「../」などのパス情報を仕込むことで、意図しない場所にファイルを展開させる攻撃が存在します。
これを防ぐためには、展開前にファイル名の安全性をチェックする方法が有効です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import os import zipfile def is_safe_path(base_path, target_path): # 展開先ディレクトリの絶対パスと結合し、正規化したパスがbase_path内にあるか確認 abs_base = os.path.abspath(base_path) abs_target = os.path.abspath(os.path.join(base_path, target_path)) return abs_target.startswith(abs_base) def safe_extract(zip_ref, extract_dir): for member in zip_ref.infolist(): if not is_safe_path(extract_dir, member.filename): raise Exception(f"不正なパスが検出されました: {member.filename}") zip_ref.extractall(extract_dir) zip_path = "sample.zip" extract_dir = "extracted_safe" if not os.path.exists(extract_dir): os.makedirs(extract_dir) with zipfile.ZipFile(zip_path, "r") as zip_ref: safe_extract(zip_ref, extract_dir) print("安全な解凍が完了しました。") |
安全な解凍が完了しました。
このような対策を行うことで、ファイルの配置先を不正に操作されるリスクを最小限に抑えられます。
よくあるエラーと対処法
zipファイルの解凍処理では、以下のようなエラーがよく発生します。
- ファイルパスの指定ミス: zipファイルや解凍先ディレクトリのパスが間違っていないか確認してください。
- パスワードの不一致: パスワード保護されたzipの場合、指定パスワードがバイト文字列になっているか、誤字がないかを再度チェックします。
- パーミッションエラー: 展開先のディレクトリに書き込み権限があるか、OSやユーザーの設定を確認してください。
- エンコーディングの問題: zipファイルに含まれるファイル名が特殊文字の場合、文字化けなどのトラブルが起こりやすいです。必要に応じてエンコーディングの指定や対応ライブラリの使用を検討します。
- 対応していない暗号化方式: 一部の暗号化方式にはzipfileが対応しておらず、その場合はpyzipperなどのライブラリを利用します。
まとめ
Pythonでzipファイルを解凍する際は、標準ライブラリのzipfileモジュールが便利です。
基本的な使い方から安全な解凍まで、幅広い場面に対応できます。
よくあるエラーを把握しておくことで、スムーズに解決できるでしょう。