Pythonでwgetを使用してWebページとファイルをダウンロードする方法

この包括的なガイドでは、HTTP、HTTPS、FTP経由でファイルをダウンロードするための強力なコマンドラインツールであるwgetを、Pythonのrequestsライブラリと比較しながら紹介しています。
3 min read
Illustration of wget usage with Python

このガイドでは、次の内容を説明します:

  • wgetとは何か。
  • なぜrequestsライブラリよりも優れているのか。
  • Pythonでwgetを使用するのがいかに簡単か。
  • Pythonスクリプトにwgetを導入するメリットとデメリット。

さっそく始めましょう!

wgetとは何か?

wgetは、HTTP、HTTPS、FTP、FTPS、およびその他のインターネットプロトコルを使用してWebからファイルをダウンロードするためのコマンドラインユーティリティです。ほとんどのUnix系OSにネイティブでインストールされていますが、Windowsでも使用できます。

なぜrequestsのようなPythonパッケージではなくwgetを使うべきなのですか?

確かにwgetはクールなコマンドラインツールですが、Pythonでのファイルのダウンロードにrequestsのような人気のあるライブラリではなく、wgetを使うべきなのはなぜでしょうか?

以下に挙げる通り、requestsよりもwgetを使用するべき理由はたくさんあります:

  • requestsよりも多くのプロトコルをサポートしているから。
  • 中止または中断されたダウンロードを再開できるから。
  • ネットワーク帯域幅を使い切らないように、ダウンロード速度を制限する仕様をサポートしているから。
  • ワイルドカードを使用したファイル名とネットワークロケーションをサポートしているから。
  • 多言語に対応したNLSベースのメッセージファイル。
  • ダウンロードしたドキュメント内の絶対リンクを相対リンクに変換できるから。
  • HTTP/Sプロキシをサポートしているから。
  • 持続的HTTP接続をサポートしているから。
  • 無人ダウンロード/バックグラウンドダウンロード操作を実行できるから。
  • ローカルファイルのタイムスタンプを使用して、ミラーリング時にドキュメントを再ダウンロードする必要があるかどうかを判断するから。
  • 特定のウェブページにリンクされたファイルを再帰的にダウンロードすることや、ユーザーが指定した再帰の深さに達するまでダウンロードすることができるから。
  • robots.txtで定義されたロボット除外ルールを自動的に尊重するから。ウェブスクレイピングについては、robots.txtのガイドで詳細をご覧ください。

これらはwgetの機能のほんの一部で、どのPython HTTPクライアントライブラリよりも強力で特別です。詳細は公式マニュアルをご覧ください。

特に、wgetはHTMLページのリンクをたどって、そのページで引用されているファイルをダウンロードできることに注意してください。これによりWebサイト全体を取得することも可能になるため、wgetWebクローリングに最適です。

簡単に言うと、wgetはWebからファイルやWebページをダウンロードする必要があるスクリプトを書く場合に最適なオプションです。Pythonでwgetを使用する方法を学びましょう!

PythonでのCLIコマンドの実行

以下の手順に従い、wgetコマンドを実行できるPythonスクリプトを作成してください。

前提条件

始める前に、マシンにwgetがインストールされていることを確認します。セットアッププロセスはOSによって異なります:

  • Linuxではすでにプリインストールされているはずです。それ以外の場合は、ディストリビューションのパッケージマネージャーを使用してインストールしてください。
  • Macでは、ホームブリューでwgetをインストールします。
  • Windowsでは、Windows用wgetバイナリをダウンロードし、フォルダに配置してください。次に、wgetバイナリパス(例:C:\Program Files (x86)\ wget)をPATH環境変数に追加します。

マシンにはPython 3+もインストールされている必要があります。セットアップするには、インストーラーをダウンロードし、アイコンをダブルクリックした後、プロンプトの指示に従ってください。

PyCharm Community EditionなどのPython IDEか、Python拡張機能を入れたVisual Studio Codeがおすすめです。

Pythonプロジェクトのセットアップ

以下のコマンドを使用することで、仮想環境wget Pythonプロジェクトを作成できます:

mkdir wget-python-demo

cd wget-python-demo

python -m venv env

上記で作成したwget-python-demoディレクトリは、プロジェクトのフォルダを表しています。

これをPython IDEで読み込み、script.pyファイルを作成し、次のように初期化します:

print('Hello, World!')

今のところ、これはターミナルに「Hello, World!」と表示するだけのサンプルスクリプトです。近い将来、wget統合ロジックが含まれる予定です。

IDEの実行(Run)ボタンを押すか、次のコマンドを実行して、スクリプトが機能することを確認してください:

python script.py

ターミナルには次のように表示されているはずです:

Hello, World!

素晴らしい!これでPythonプロジェクトが作成されました。

次のセクションでwgetの使用方法を参照してください!

サブプロセスモジュールを介してCLIコマンドを実行する関数の作成

PythonスクリプトでCLIコマンドを実行する最も簡単な方法は、サブプロセスモジュールを使用することです。

Python標準ライブラリの該当ライブラリを使用すると、新しいプロセスの生成や、その入出力/エラーパイプへの接続、リターンコードの取得ができます。言い換えると、Pythonからターミナルでコマンドを実行するために必要な要素をすべて揃えられるということです。

これは、サブプロセスからPopen()メソッドを使用してPythonでwgetのようなCLIコマンドを実行する方法です:

import subprocess

def execute_command(command):

"""

Execute a CLI command and return the output and error messages.

Parameters:

- command (str): The CLI command to execute.

Returns:

- output (str): The output generated by the command.

- error (str): The error message generated by the command, if any.

"""

try:

# execute the command and capture the output and error messages

process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

output, error = process.communicate()

output = output.decode("utf-8")

error = error.decode("utf-8")

# return the output and error messages

return output, error

except Exception as e:

# if an exception occurs, return the exception message as an error

return None, str(e)

popen()は、文字列として渡されたコマンドをOSの新しいプロセスで実行します。shell=Trueオプションは、このメソッドがOSで設定されているデフォルトのシェルを使用することを保証します。

上記のスニペットをscript.pyファイルに貼り付けます。これで、次の例のようにPythonでCLIコマンドを呼び出すことができます:

output, error = execute_command("")

if error:

print("An error occurred while running the CLI command:", error)

else:

print("CLI command output:", output)

Pythonでwgetを使用する:ユースケース

これはwgetコマンドの構文です:

wget [options] [url]

場所:

  • [options]はCLIツールの動作をカスタマイズするためにサポートされているオプションとフラグのリストです。
  • 「url」はダウンロードするファイルのURLです。これは、ファイルへの直接リンクでも、複数のファイルへのリンクを含むWebページのURLでもかまいません。

:Windowsでは、「wget」の代わりに「wget.exe」と書いてください。

一般的なユースケースをカバーするPythonスニペットでwgetが実際に動作するのを見てみましょう!

ファイルのダウンロード

wgetでhttp://lumtest.com/myip.jsonをダウンロードしたいとします。これを実現するコマンドは次のようになります:

wget http://lumtest.com/myip.json

Pythonでは、次のコード行になります:

output, error = execute_command("wget http://lumtest.com/myip.json")

出力を印刷すると、次のようになります:

--2024-04-18 15:20:59-- http://lumtest.com/myip.json

Resolving lumtest.com (lumtest.com)... 3.94.72.89, 3.94.40.55

Connecting to lumtest.com (lumtest.com)|3.94.72.89|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 266 [application/json]

Saving to: 'myip.json.1'

myip.json.1 100%[=================================================>] 266 --.-KB/s in 0s

2024-04-18 15:20:59 (5.41 MB/s) - 'myip.json.1' saved [266/266]

コマンドの出力から、次の結果が表示されます:

  1. URLはサーバーのIPアドレスに解決されます。
  2. wgetは、指定されたリソースへのHTTPリクエストを介してサーバーに接続します。
  3. サーバーが受信したHTTP応答ステータスコードは200です。
  4. wgetはファイルをダウンロードし、現在のディレクトリに保存します。

これでPythonプロジェクトディレクトリにmyip.jsonファイルが含まれるようになりました。

ダウンロードするファイルの保存先フォルダを変更する場合は、以下のように–directory-prefixまたは-Pフラグを使用してください:

output, error = execute_command("wget --directory-prefix=./download http://lumtest.com/myip.json")

これで、myip.jsonファイルがプロジェクトのディレクトリ内のダウンロードフォルダに保存されるようになりました。宛先フォルダが存在しない場合、wgetにより自動的に作成されることに注意してください。

ダウンロードリソースのファイル名を変更するには、–output-documentまたは-Oフラグを使用してください:

output, error = execute_command("wget --output-document=custom-name.json http://lumtest.com/myip.json")

今回は、wget Pythonスクリプトはmyip.jsonの代わりにcustom-name.jsonという名前のファイルを作成します。

Webページのダウンロード

wgetコマンドは以前と同じですが、主な違いは今回の「url」がWebページを指すことです:

output, error = execute_command("wget https://brightdata.com/")

これで、プロジェクトのディレクトリに、Webページ(https://brightdata.com/)のHTMLコンテンツを備えたindex.htmlファイルが含まれるようになります

前回のダウンロード以降に変更がある場合にのみファイルをダウンロードする

ディスク容量とネットワークリソースを節約するために、前回のダウンロードから変更されていないファイルはダウンロードしたくないと思うかもしれません。wgetファイルタイムスタンプ機能を提供している理由はここにあります。

詳しく説明すると、–timestampingオプションはwgetに、ローカルファイルのタイムスタンプをサーバー上のタイムスタンプと比較するように指示します。ローカルファイルのタイムスタンプがサーバー上のタイムスタンプと同じか新しい場合、wgetはファイルを再度ダウンロードしません。それ以外の場合は、ダウンロードされます。

これがタイムスタンプメカニズムの仕組みです:

  1. –timestampまたは-Nオプションを使用してファイルをダウンロードすると、wgetはリモートファイルのタイムスタンプを取得します。
  2. ローカルファイルのタイムスタンプ(存在する場合)をチェックし、リモートファイルのタイムスタンプと比較します。
  3. ローカルファイルが存在しない場合や、そのタイムスタンプがサーバー上のタイムスタンプよりも古い場合、wgetはファイルをダウンロードします。ローカルファイルが存在し、そのタイムスタンプがサーバー上のタイムスタンプと同じか新しい場合、wgetはファイルをダウンロードしません。

HTTPのタイムスタンプは、HEADリクエストの後にサーバーから返されるLast-Modifiedヘッダーをチェックすることで実装されます。wgetContent-Lengthヘッダーも調べてファイルサイズを比較します。それらが同じでない場合は、Last-Modifiedヘッダーの内容に関係なくリモートファイルがダウンロードされます。Last-Modifiedはオプションのレスポンスヘッダーであることに注意してください。ファイルが存在しない場合、wgetはいずれにしてもファイルをダウンロードします。

Pythonの–timestampオプションを次のコード行で使用してください:

output, error = execute_command("wget --timestamping https://brightdata.com")

index.hmlを既にダウンロードしている場合、ファイルが再びダウンロードされないことを示す以下のメッセージが表示されます:

--2024-04-18 15:55:06-- https://brightdata.com

Resolving brightdata.com (brightdata.com)... 104.18.25.60, 104.18.24.60

Connecting to brightdata.com (brightdata.com)|104.18.25.60|:443... connected.

HTTP request sent, awaiting response... 304 Not Modified

File 'index.html' not modified on server. Omitting download.

FTP経由でファイルをダウンロードする場合も、同じメカニズムが機能します。

中断されたダウンロードの完了

デフォルトでは、処理中に接続が失われた場合、wgetはファイルのダウンロードを自動的に最大20回再試行します。部分的にダウンロードされたファイルを手動で続行する場合は、次のように–continueまたは-cオプションを使用してください:

output, error = execute_command("wget --continue http://lumtest.com/myip.json")

サイト全体をダウンロード

再帰的ダウンロードは、1つのコマンドでサイト全体をダウンロードするwget機能です。

指定されたURLから始めて、wgetはHTMLページを解析し、srcおよびhref HTML属性またはurl() CSS属性で見つかった他のドキュメントに従います。次のファイルもテキスト/HTMLファイルである場合は、目的の深さに達するまでそれを解析し、そのドキュメントも追跡します。再帰的ダウンロードは幅優先検索アルゴリズムに従い、深度1でファイルを取得し、次に深度2という順序でファイルを取得します。

このダウンロードモードを使用する際に覚えておくべきwgetオプションは次のとおりです。

  • –recursiveまたは-r:ファイルを再帰的にダウンロードするように、wgetに指示します。つまり、Webページ上のリンクをたどります。これにより、画像、スタイルシート、スクリプトなど、リンクされたすべてのリソースを含むWebサイト全体のローカルコピーを作成できます。このオプションを指定すると、wgetはダウンロードされたすべてのファイルをターゲットサイトのドメイン名と同じ名前のフォルダに保存します。
  • –level=または-l=:リンクされたページをダウンロードするときに従う再帰の最大深度を指定します。たとえば、–level=1に設定した場合、wgetは開始URLから直接リンクされているページのみをダウンロードします。これらのページのリンクをたどって他のページをダウンロードすることはありません。巨大サイトのクロールを防ぐため、デフォルトの深度値は5です。このオプションを0に設定するか、’inf’に設定すると深度が無限になります。指定した深さに関係なく、ページを正しく表示するために必要なすべてのリソースがダウンロードされるようにするには、-pまたは–page-requisitesオプションを追加してください。
  • –convert-linksまたは-k:ダウンロードされたHTMLファイル内のリンクを、元のURLではなくローカルにダウンロードされたファイルを指すように変更します。このオプションは、サイトのローカルミラーを作成し、ダウンロードしたページ内のすべてのリンクがオフラインで正しく機能するようにしたい場合に便利です。

すべてのリンクをローカルファイルを指すように変換しながら、Bright Dataサイトを最大深度1で再帰的にダウンロードしたいとします。以下があなたが書くべきPython wgetコマンドです:

output, error = execute_command("wget --recursive --level=1 --convert-links https://brightdata.com")

:このコマンドはインターネット接続の速度によっては時間がかかる場合がありますので、しばらくお待ちください。

これで、brightdata.comフォルダに、Bright Dataサイトファイルのローカルコピーが1レベルの深さで再帰的に格納されます。

wgetとPythonを併用することの長所と短所

Pythonでwgetを使用するメリットとデメリットを見てみましょう。

メリット

  • サブプロセスモジュールによりPythonを簡単に統合できます。
  • 再帰的ダウンロード、自動再試行、ファイルスタンプなど、多数の機能とオプション。
  • 1つのコマンドでサイト全体のローカルコピーを作成できます。
  • FTPサポート。
  • プロキシ統合のサポート。
  • 中断されたダウンロードを回復できます。

デメリット

  • 出力はダウンロードされたファイルであり、Pythonスクリプトで直接使用できる文字列変数ではありません。
  • ダウンロードしたHTMLファイルから特定のDOM要素にアクセスするには、Beautiful Soupのようなパーサーが必要です。

[追加]プロキシでのwgetの使用

wgetを使用してファイルまたはサイト全体をダウンロードする際の主な課題は、リクエストがブロックされる可能性があることです。これは、wgetリクエストが送信先サーバーにボットからのリクエストとして表示されるためです。一部のWebサイトでは、ボットからのリクエストを防ぐため、ページやリソースに制限や上限を設けています。これらの制限には、地理的制限、律速ポリシー、またはスクレイピング対策が含まれる場合があります。

プロキシサーバーwgetへの統合は、こうした制限を回避するための現実的なソリューションです。プロキシは、コンピューターとインターネットの間の中間サーバーとして機能します。wgetトラフィックをプロキシサーバー経由で転送することで、IPの公開を回避し、サイトが課すほとんどの制限を回避できます。

さらに詳細なチュートリアルについては、wgetでプロキシを使用する方法に関するガイドを参照してください。

まとめ

この記事では、wgetとは何か、なぜこれがrequestsライブラリよりも優れているのか、そしてPythonでの使い方を理解しました。これで、wgetがHTTP、HTTPS、FTP経由でファイルやWebページをダウンロードするための強力なツールであることがお分かりいただけたかと思います。ここで学んだことのおかげで、Pythonでwgetを使用する方法の知識を獲得できました。

このガイドで見てきたように、wgetのようなユーティリティによるコンテンツのダウンロードを防ぐためにWebサイトが講じているボット対策をすべて回避するには、プロキシが非常に役立ちます。問題なのは、オンラインには数十種類のプロバイダーがあり、最適なプロバイダーを選択するのが簡単ではないことです。業界最高のオプションであるBright Dataに迷わず決めれば、プロキシプロバイダーを選ぶ時間を省くことができます

Bright Dataは世界最高レベルのプロキシサーバーを保有しており、フォーチュン500企業を含む20,000社以上の顧客にサービスを提供しています。Bright Dataは次のような様々な種類のプロキシを提供しています:

無料トライアルを開始するか、当社のデータ専門家に当社のプロキシおよびスクレイピングソリューションについてご相談ください。