go言語で画像収集クローラを作ってみた話、続き。
作業を続けてわかったことなどを記します。
まず、サーバーの負担を減らすため、httpリクエストを一度だけにまとめたい問題から。
ぐぐって色んな人のコードを見たところ、画像データを取得するには画像URLに対して毎回http.Get()しているようです。
そういうものですか。ええい、なら別の手段だ!
というわけで、別の方法でサーバーの負担を軽減させることに。
考えたことその1。リクエストの間にちょっと時間を置く。
これはtime関数で簡単、ただしサーバーに無知なので、どれくらい時間を置けばどれくらいの影響があるのかよくわかりません。
その2。リクエストの数を減らす。
最初のhttp.Get()では、指定したウェブサイトをパースします、返って来た値を元にページの全ての要素をチェックし、srcタグに対してのみ取得処理を行う、というのが今回のクローラの動きなのですが、この最初のリクエストで取得したデータでなんやかんや判断する必要があります。
まずは正規表現で拡張子の選別。画像収集が目的なら大抵はjpgかpngになると思いますので、それ以外は無視。これで無用なリクエストが減らせます。
それから、とあるサイトで全く同じURLを持つ画像がありました。これはハジきたいということで、洗い出したURLをスライスに保存、その時for rangeで同じ値がないかチェックをかけることに、一度保存したURLは無視です。正規表現処理と合体させて、保存を扱う関数としてまとめました。
URLを保存するスライスを作るのなら、上限を決めとけばいいや、ということで 1サイトにつき10個のURLしか保存できないように、とかしておけば、あまり無茶なことにはならんだろう、と。 パースしたデータの後ろの方に激ヤバ画像があった場合、残念ながら取得できませんね。
そもそも、データサイズが数キロバイトのものは無視したい、サムネイルとかバナー、ボタン等、 なんとか出来ないかと 以下を試しました。
サイトによってはhtml内の画像データにwidthやheightを指定しています、 これは最初のリクエストで閲覧可能なため、ここでwidthが200px以下のものなどは無視するようにしましたが、 サイト側がサイズを指定していない場合はスルーされてしまいます。サイトによってマチマチですが、おおむね効果があります。
それより画像のデータサイズを取得できれば大体判断できるな... どうにかしてデータサイズを... あ!http.Get()で画像URLを指定しデータを取得すれば ContentLength プロパティが含まれる!これでデータサイズを取得できるぞ!やった!って、おバカ。
リクエスト投げちゃ主旨から外れます。 ただしリクエストを投げた後、データサイズを見て画像を保存するどうかは決められるので 採用しましたが「httpリクエストを減らす」という目的には一歩届かず。
その後は、画像を保存するために"os"パッケージをインポートしてフォルダーとファイル作成、それから書き込み処理(というかコピー処理)。フォルダーとファイルは連番で作成できるように作りました。
こんな所で作業終了。学習のために作ったものですので、むやみにクロールをかけることはしませんので、ご安心を。