LoginSignup
4
3

More than 1 year has passed since last update.

暇すぎて画像ダウンロードツールを作ってみた話

Last updated at Posted at 2020-01-02

年末年始暇ですね。

暇つぶしに何か作ろうと思ったんですが、何も思いつかず。。。
普段AngularやNestJSでTypescriptばっかり書いてますが、たまにはJavascriptでも書いてみようと思いました。

とりあえずWebページのスクレイピングってやったことないからJavascriptで書いてみるかーということでしょうもないツールを作ってみました。

(2022/03/05追記)
GUI版も作りました

作ったもの

WebページのURLを指定すると、そのページ内のimgタグの写真をすべてダウンロードするコマンドラインツールです
img-downloader

使い方

  • nodeコマンドでimg-downloader.jsを実行します
  • 引数に対象のWebページURLを指定します
npm install
node img-downloader.js {web-page-url}

結果

  • output/{YYYYMMDDhhmmss}ディレクトリに画像が出力されます

実行例

以下のページから画像を取得してみます
https://www.irasutoya.com/2018/12/blog-post_676.html

node img-downloader https://www.irasutoya.com/2018/12/blog-post_676.html

↓ 実行

image.png

 ↓ 出力

image.png

指定したページ内の全画像をとってくるので、ロゴやバナーの画像なんかの意図しない画像も取れてしまうのが難点です。。。

技術的な話

すごいシンプルなJavascriptで書いてます。
ほんとはスクレイピングも自前でやろうかと思ったんですが、めんどくさくなってscraperjs使っちゃいました。。

使ってるパッケージ

  • fs
    • ファイルの入出力用パッケージ
  • request
    • HTTPリクエスト用パッケージ
  • scraperjs
    • Webページのスクレイピング用パッケージ

スクレイピング

scraperjsを扱うためのUtilクラスを作りました。
getTargetImgURl()で指定URLからimgタグのsrc属性をピックアップします。

utils/scraper.util.js
class ScraperUtil {
    getTargetImgUrl(pageUrl) {
        return this.scrape(pageUrl, ($) => {
            return $('img').map(function () {
                return $(this).attr('src');
            }).get();
        });
    }

    scrape(pageUrl, fnScraping) {
        return new Promise((resolve, reject) => {
            scraperjs.StaticScraper.create(pageUrl)
                .scrape(($) => fnScraping($))
                .then(items => resolve(items))
                .catch(err => reject(err));
        });
    }
}

簡単にスクレイピングできて良いですね。

画像のダウンロード

src属性に指定された値によってダウンロード方法が変わります

URLの場合

  • requestパッケージで画像データをGET
  • GETしたデータをfsパッケージのwriteFileSyncでファイル出力
    • ファイル名はURLから取得

BASE64データの場合

data:image/xxx~で始まる文字列の場合、BASE64データが指定されていると判断し、以下のように出力しています。

  • str.match()でdata:image/xxxx;base64,を抽出
  • 上記で抽出した文字列を除いた文字列(画像データ)をBASE64デコード
    • ブラウザ上でないとwindow.atobは使えないため、Bufferを使ってデコードしています
  • fsパッケージのwriteFileSyncでファイル出力
    • ファイル名はraw{cnt}.{type}で出力
    • typeは上記で抽出した文字列の画像タイプ(xxxxの部分)を指定

最後に

休みボケの中で適当に書いているため、突っ込みどころ満載なコードになってしまいましたが、良い暇つぶしになりました。

Typescriptだと型とかきっちりしてて書いてる途中でエラーに気付けますが、Javascriptだと実行してようやく気付くことが多いので、久々だと意外と難しいですね(笑)

(追記)
Googleの画像検索の結果一括保存したかったのにできてないので、気が向いたらアップデートしていこうかと思います。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3