Help us understand the problem. What is going on with this article?

はじめてのdocker+cli+Kotlin~南ことりの画像を収集~

More than 1 year has passed since last update.

はじめに

・JAVAは未経験
・qiita初投稿
・kotlinはを1冊読んで手を動かして遊んだ程度
・普段はPHPやrails
・理解度が浅いため、全体的にふんわりしています。ご指摘等頂ければ幸いです

dockerで環境を作る。

まずはkotlinがコンパイル出来るよう、環境を作っていきます。
docker-hubのdockerfileをベースにしますが
gradleが足りないので入れます(gradleについては後述)
gradle公式dockerfileを参考にしました

alpine-linuxは軽量なため、コマンドが最小限です。
curlなども入っていないので必要なものはapkで入れています。

FROM openjdk:8-jdk-alpine
RUN apk update \
    && apk upgrade \
    && apk add coreutils curl   


ARG BUILD_DATE
ARG VCS_REF

# Set Appropriate Environmental Variables
ENV GRADLE_HOME /usr/lib/gradle
ENV GRADLE_VERSION 4.7
ENV GRADLE_FOLDER=/root/.gradle

ARG GRADLE_DOWNLOAD_SHA256=fca5087dc8b50c64655c000989635664a73b11b9bd3703c7d6cabd31b7dcdb04
RUN set -o errexit -o nounset \
    && echo "Installing build dependencies" \
    && apk add --no-cache --virtual .build-deps \
        ca-certificates \
        openssl \
        unzip \
    \
    && echo "Downloading Gradle" \
    && wget -O gradle.zip "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
    \
    && echo "Checking download hash" \
    && echo "${GRADLE_DOWNLOAD_SHA256} *gradle.zip" | sha256sum -c - \
    \
    && echo "Installing Gradle" \
    && unzip gradle.zip \
    && rm gradle.zip \
    && mkdir /opt \
    && mv "gradle-${GRADLE_VERSION}" "${GRADLE_HOME}/" \
    && ln -s "${GRADLE_HOME}/bin/gradle" /usr/bin/gradle \
    \
    && apk del .build-deps \
    \
    && echo "Adding gradle user and group" \
    && addgroup -S -g 1000 gradle \
    && adduser -D -S -G gradle -u 1000 -s /bin/ash gradle \
    && mkdir /home/gradle/.gradle \
    && chown -R gradle:gradle /home/gradle \
    \
    && echo "Symlinking root Gradle cache to gradle Gradle cache" \
    && ln -s /home/gradle/.gradle /root/.gradle

LABEL org.label-schema.build-date=$BUILD_DATE \
      org.label-schema.description="Kotlin docker images built upon official openjdk alpine images" \
      org.label-schema.name="alpine-kotlin" \
      org.label-schema.schema-version="1.0.0-rc1" \
      org.label-schema.usage="https://github.com/Zenika/alpine-kotlin/blob/master/README.md" \
      org.label-schema.vcs-url="https://github.com/Zenika/alpine-kotlin" \
      org.label-schema.vcs-ref=$VCS_REF \
      org.label-schema.vendor="Zenika" \
      org.label-schema.version="1.2-jdk8"

RUN apk add --no-cache bash && \
    apk add --no-cache -t build-dependencies wget && \
    cd /usr/lib && \
    wget https://github.com/JetBrains/kotlin/releases/download/v1.2.41/kotlin-compiler-1.2.41.zip && \
    unzip kotlin-compiler-*.zip && \
    rm kotlin-compiler-*.zip && \
    rm kotlinc/bin/*.bat && \
    apk del --no-cache build-dependencies

ENV PATH $PATH:/usr/lib/kotlinc/bin


RUN apk del coreutils curl
# コンテナのワークディレクトリの指定
WORKDIR /app
CMD ["kotlinc"]



VOLUME  $GRADLE_FOLDER
docker-compose.yml
version: '2'

services:

  kotlin:
    build: .
    command: bash -c "gradle run"
    volumes:
    - .:/app

これでdocker-compose build後、
docker-compose upをすれば
gradle runを実行してくれます

2 gradleを書く

gradleはビルドの自動化ツールです。

Android開発者ならbuild.gradleを見たことがあると思います。
「ライブラリとか追加するときに編集する奴」程度の認識で
あまりgradleの恩恵を分かっていませんでした

今回はAndroidではなくコマンドライン上での実行になるため、
kotlincコマンド でコンパイルし、kotlinjavaで実行をしますが
ライブラリ等の依存関係管理がとても面倒です。
ここでgradleが登場します。

gradleを使えばライブラリの管理やビルド、実行を全て行ってくれます。
(厳密にはそれ以外にもなんでも出来るみたいです)
build.gradleに依存関係やmainクラス名を書きます。

その後gradle runを叩けばでビルドと実行をやってくれます
android studioで開発するときもエディタが自動で認識して
コーディングヒントを与えてくれます
gradleの理解が曖昧だったためここに一番時間がかかりましたが、結局こうなりました。

build.gradle

apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = "ScrapingKt"
buildscript {
    ext.kotlin_version = '1.2.41'
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    compile "org.jsoup:jsoup:1.10.3"
    compile "org.apache.httpcomponents:httpclient:4.5"
}
allprojects {
    repositories {
        jcenter()
    }
}

4 動くか確認

くそコードで動くか確認。
build.gradleでスクレイピング用ライブラリJsoupを足しているので
それが使えるかの確認です。

src/main/kotlin/scraping.kt
import org.jsoup.Jsoup

//Jsoupが使えているかのテスト。引数とかはまだ特に関係ない。
class Hoge(val url: String) {
    fun test() {
        val doc = org.jsoup.Jsoup.parse("<div id='a'>aiueo</div><div id='b'>bbb</div>")
        println(doc.select("#a"))
    }
}


fun main(args: Array<String>) {
    val foo = Hoge("test")
    foo.test()

}

docker-compose upを叩き、<div id='a'>aiueo</div>とコンソールに出れば成功です

3 スクレイピングする。

準備が整ったのでスクレイピングしていきます。
まずはkotlinうんぬんの前に、
「どのURLにどういう値を投げれば、何が返ってくるのか」

ChromeのDeveloper Toolで確認
キャプチャ.PNG
https://search.yahoo.co.jp/image/paginationjsというAPIが関係してそう。

GETなのでブラウザのURLに直接入れて確認。
投げる値を変更したり、余計そうなのを無くしてみたり。
.crumb
.ncrumb
が必須みたい?

キャプチャ.PNG

てかjsonで帰ってくるけど、中身はほぼhtmlなのかー。(エスケープ処理はしている?)

エスケープシーケンスの\を取り除いてjsoupに流し込めば、セレクタ使ってほしいものがとれそう。

やっかいなのは。
.crumb
.ncrumb
最初はGET値決め打ちで通信出来たけど、時間がたつと失敗してしまう。
.ncrumbが時間とともに変わってるくさい。
じゃあこいつらはどこで生成されてるんだ、どうせhiddenだろうと思ったが
https://search.yahoo.co.jp/image/search中でjavascriptにより生成されている
セレクタ使えないじゃんーってことで正規表現でゴリゴリ取得。
ちなみにUser Agent見てるらしく、適当だとこの部分だけ生成してくれない。
かなり苦戦。

APIの仕様が分かれば、後はセレクタで欲しいものを指定して、
ループ処理をするだけ。
ファイル保存関連はググればJAVAのコードがたくさん出てきます

最終的に

最終的にこんな感じになりました
docker-compose up
をすると南ことりちゃんの画像が自動でsaveディレクトリに保存されるようになりました

以下感想

エディタについて

最初はatomでやってましたが、
最終的にはandroid-studioで作業しました。
この神IDEを無料で使えるのが強みの1つだと思います。
JAVAのコードを貼ると自動でkotlinに変えてくれるので、JAVA未経験マンにとってはとても助かりました

スクレイピング

結局はセレクタ使うので、ある程度ベースができればjavascriptやpythonでのスクレピングとあんまり変らないかも
Javaの広大な知見がそのまま使えるのが非常に助かります、

画像の質

ディープラーニング用の画像を集める という目的もあったのですが
個々の画像の精度に関してはyahoo画像検索よりもpinterestのほうが良さそうでした。
pinterestからディープラーニング用二次元画像を集める
とは言えyahoo画像検索の画像数は大量のため、絞り込み条件をうまく使えば
実用的だなぁと思いまいた

最後に

・kotlin、名前に惹かれて勉強したけどかなり良い言語
・Android Studio神
・間違い等あると思いますのでご指摘お待ちしております
・rootが取れなくてインテリアになった【作ってみた】スクフェス専用コントローラー

sirojake
フリーランサー
https://www.ginjake.net
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away