ページコンテンツ
web上の静的ファイルを一括でダウンロードしたいと思うことない?
いろんなサイトを運用している中で、サイトの管理情報をド忘れしてしまい、サイトにアクセスできなくなった。
別サイトに移行するために、アップロードしていた静的ファイルを一括で取得したいと思った。
昨今はサイトの一括ダウンロードツールなどあるが、どうせなら自分でできないか、考えてみた。
そして、PCを触り始めたときに勉強したbatchのスクリプトでできるんじゃないかと思って、勉強がてら、batchスクリプトを作ってみようと思た。
前提条件
今回のコンテンツの前提条件だが、以下の通り。
- 取得したいコンテンツは、サイト上のどこのパスにあるかはわかっているが、複数の場所にある。
- それぞれの場所でファイルは1からの連番だが、それぞれの場所で異なる数のファイルがある。
- コンテンツは全て拡張子はjpg
スマートに作れば、いろいろかっこよくコーディングできるのだろうが、今回はこのためだけに作ったので、
- ファイルのリストを別で作り、
- それを引数としてダウンロードする
ことで、いろんなパス(ついでにURLにも)対応できるようにした。要は、どれをダウンロードするかはリスト次第ということにした。
まずはダウンロード
まずはというか、スクリプトでやるのは、
- リストを1行ずつ読み込む
- 読み込んだ行の情報に従ってダウンロード
という2つだけなので、ダウンロードができれば、ほぼ出来上がり。
ダウンロードだが、「bitsadmin」というのをつかうとできそうだった、
- ダウンロード元URLを指定して、ダウンロードできる
- 保存名を指定できる
とのことなので、これを使うことにした。win10ならデフォで使えるみたい。(他に、wgetに慣れていたので、これを使ってみたが、うまくファイル名を指定して保存できなかった。)
ちょっと使ってみた。まずはwin10左下のスタートボタンをクリックして「cmd」と入力してEnterすると、コマンドプロンプトが立ち上がる。
ここで、以下を実行。
bitsadmin /transfer download https://it.ama2pro.net/yovdMei1hgep/wp-content/uploads/2015/04/imasia_12292266_M1-150x150.jpg D:\test.jpg
これは「https://it.ama2pro.net/yovdMei1hgep/wp-content/uploads/2015/04/imasia_12292266_M1-150×150.jpg」というweb上のコンテンツを「Dドライブ直下」に「test.jpg」という名前で保存する。
つまり
bitsadmin /transfer download (ダウンロードするweb上のファイル) (保存先)
ということらしい。
なので、(ダウンロードするweb上のファイルのURL) ( 保存時のファイル名 )のセットをリストとして作ればいい。
リストファイルから1行ずつ読み込み
上で何をリストとして渡せばいいか分かったので、そのリストファイルを作って、1行ずつ読み込む繰り返し処理を検討する。
リストとしては、2つの文字列( ダウンロードするweb上のファイルのURL、保存時のファイル名)が必要なので、カンマ区切りでこの2つを記載しているファイルとした。
ファイルを指定して、1行ずつ読み込むには以下のようなfor文を使う方法がある。
for /f "tokens=1,2 delims=," %%i in (list.txt) do (
echo %%i
echo %%j
)
これで、1行ずつ読み込み、 ダウンロードするweb上のファイルのURLと 保存時のファイル名が表示されるようになった。
リストファイルは「list.txt」というファイル名にし、以下のような内容になる。
https://it.ama2pro.net/yovdMei1hgep/wp-content/uploads/2015/04/imasia_12292266_M1-150x150.jpg,D:\test.jpg
保存先ファイルパスの指定が難しかったので、別の方法をとった
上の例では保存先を「D:\test.jpg」としているが、実際のパスは「[あひる] ○○池での画像 家族と一緒」などの、
- 日本語のフォルダ名
- スペースあり
- その他よくわからない「[」などの記号がある。
というもので、そのままの文字列を与えてしまうと、文字列エラーやら、スペース区切りにより別引数して認識されていたりして、正常に動かなかった。
「保存時のファイル名 をダブルクォーテーションで囲う」とか、「(bitsadminの)実行文全体をダブルクォーテーションで囲う」とかいろいろ情報が出てきたが、どれもダメだった。
なので、保存時は「tmp」というフォルダ名を使って、データダウンロード後にそのフォルダ名を別の名前にリネームする方法とした。
フォルダ名変更
フォルダ名変更は、
rename (変更前フォルダ名) (変更後フォルダ名)
でできる。
基本的にファイルやフォルダを指定するとき、実行場所によってはエラーになるなど、実行環境により上手く動かないのでなるべく絶対パスで指定していた。
ただ、絶対パスで指定しようとすると、どうしてもエラーになった。
(rename d:\tmp “d:\[あひる] ○○池での画像 家族と一緒” とかが、エラーになる。)
いろいろ悩んだ挙句、実行はコマンドプロンプトで、このスクリプトを置くフォルダに移動して、そこで実行することにした。
すると、renameに指定するのは、「tmp」「[あひる] ○○池での画像 家族と一緒」といったフォルダ名の身になる。
rename tmp "[あひる]○○池での画像 家族と一緒"
これで上手くいった。
ちなみに、ここではダブルクォーテーションでスペースなどをエスケープできた。
これにより、上で作ったリストの 「保存時のファイル名」はパスを含まないファイル名のみとして、フォルダ名はスクリプトの一番上で変数に入れてやる方法にした。
フォルダ名は異なるので、毎回実行毎にスクリプトのフォルダ名部分を変更しないといけないが、しょうがない。。。
最後に
最終的にスクリプトは以下のようになった。
@echo off
set "foldername=[あひる] ○○池での画像 家族と一緒"
set folderpath=D:\tmp
if exist %folderpath% (
echo "tmp exist"
exit /b
) else (
mkdir %folderpath%
)
for /f "tokens=1,2 delims=," %%i in (list.txt) do (
timeout /t 10 > nul
REM echo %%j
bitsadmin /transfer download %%i %folderpath%\%%j
)
rename tmp "%foldername%"
exit /b
何点か追記。
- 1行目の文は、実行時にechoなどの表示をしなくなるものらしい。エラー文とか出してデバッグしたいときは消したほうがいい。
- for文内のtimeoutの文について。私はサーバの管理を行うことが多いが、このスクリプトはサーバにfor文で回す分だけサーバアクセスを行う。こういう場合はマナーとして十分な間隔をあけてアクセスするのが礼儀だと考える。
(これについてはまた改めて。。。)
- 「if exist」文については、(何らかの原因で)tmpフォルダがあるのに、このスクリプトを実行しようとした場合、tmpフォルダのチェックをしないと、tmpフォルダ内にいろんなファイルが混ざったり、すでに保存されていたファイルを上書きする可能性などもあるかも、と思い、tmpがある場合は、スクリプトを停止するようにした。
- このスクリプトファイル(名前はなんでもいいと思うが、拡張子として「.bat」を付けること。つけなくてもいいのかな?)と、上の「list.txt」を「D:\」に置いて実行する。
で、試したところ上手くいった。
感想、注意など
webを探せば、自分がやりたいことができるツールはいくらでもあると思ったが(web一括ダウンロードとか)、勉強のためにやってみたけど、正直、これを極めても「なんだかなぁ。。。」と思った。
この勉強のために時間を費やすなら、別の勉強したほうがいいかも。
他のスクリプト言語と比べて、癖も強いと思った。
あと、これを使えば、いろんなダウンロードを行えるかもしれないけど、くれぐれも「違法ダウンロード」はやめましょう。
あと、アタックもやめましょう。(まぁ、アタックするなら、もっと手の込んだスクリプトを使うと思うけど。)
「インターネットは匿名」とかいうけど、匿名じゃないから!(特定が面倒なだけで)
上のスクリプトを使って発生した不利益に対して、一切責任持ちません。
(まぁ、使うとしても上のスクリプトをコピペして使うと思うので、ウィルスを仕込んでいるとかの危険はないけど)