読者です 読者をやめる 読者になる 読者になる

Dockerを少し

久々です。 Cloud9のRails環境を使っていましたが、ローカルでRailsを扱いたかったのでDockerを使って見ました。 Vagrantなどは使ったことがありますが、Dockerはさわったことはありませんでした。

インストール

ローカル環境はiOS。 とりあえずDockerの下記の公式ページに沿ってインストールします。今回はStable Channel(安定版)を選択しました。

docs.docker.com

日本語で手順を紹介されている方がいらっしゃいましたので、こちらもどうぞ。 Kitematicのインストール手順も記載されています。(GUIは不要でしたので私は利用しませんでした。)

qiita.com

インストール確認。

$ docker --version
Docker version 17.03.1-ce, build c6d412e

ちょっと試す

Dockerをインストールしたといっても扱い方にはまだ知識が乏しいので、とりあえず動くものをと…。 Gollum(Ruby製のwikiエンジン)の環境構築手順を見つけたので試して見ました。問題なく動作しました。

dev.classmethod.jp

あとがき

試して見ましたが、聞いた通りに簡単に環境構築ができました。(詳しいことは分かっていませんですが…) 確かに便利ですので、少しDocker勉強してみようか。 とりあえずこの辺から。

Docker入門

Macで初めてDockerを使う際に覚えておくと良いこと - Qiita

【初心者向け】Docker for Macで開発環境を作る(アプリサーバとDBサーバのコンテナ間連携まで) - Qiita

React勉強中(react router)

色々と忙しく、しばらくブログを書けていませんでしたが、再開していこうと思います。
さて、YouTubeの動画『REACT JS TUTORIAL』でReact の勉強をしていたところ、react router の動作確認で「The prop history is marked as required in Router, but its value is undefined.」というエラーが表示されてうまく動作せず詰まってしまいました。
調べたところ、以下に解決方法がありました。

reactjs - React Router failed prop 'history', is undefined - Stack Overflow

モジュールに変更があったようですね。使い方は以下の通りです。

react router dom のインストール
$ npm install --save-dev react-router-dom
動作確認
 import React from 'react'
 import ReactDOM from 'react-dom'
 import { BrowserRouter, Route } from 'react-router-dom'

 const app = document.getElementById('app')

 class App extends React.Component {
     render() {
         return (
             <div>
                 Hello, World!
             </div>
         )
     }
 }

 ReactDOM.render((
     <BrowserRouter >
         <Route path="/" component={App} />
     </BrowserRouter>
 ), app)

React のチュートリアル閲読後

前回 ReactJS の環境を構築してから、本家サイトのチュートリアルで学習をしてみました。なんとなくですが分かったことを書いておきます。

正確か分からないが、上に書いた感じで大体合っていると思います。

今後、どう知識を深めるか、どんなアプリを作るかと試行していくために、もう少し情報を探っていく必要があります。…が、どこから探して良いものか。

ReactJS の環境構築(2)

前回「ReactJS の環境構築(1)」の続きです。

ReactJS アプリの作成

ReactJS のチュートリアルでとても分かりやすい記事がありましたので、そちらに沿って環境構築させて頂きました。

<参考文献>
フォルダ構成

ディレクトリ構成は以下の通りにしました。

myApp/
 ├ .babelrc
 ├ package.json
 ├ webpack.config.js
 ├ development.js
 ├ dist/
 │ └ js/
 └ src/
   ├ index.html
   ├ js/
   └ css/

プロジェクトフォルダを作成します。

$ cd ~
$ mkdir myApp; cd $_
$ npm init -y
Babel の設定

ES6 でコードを書くために Babel を使います。(参考 Babel
Babel をインストールします。

$ npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react

.babelrc を以下の内容で作成します。

{ "presets": [ "es2015", "react" ] }
Webpack の設定

Webpack をインストールします。

$ npm install --save-dev webpack

webpack-dev-server をインストールします。

$ npm install --save-dev webpack-dev-server html-webpack-plugin

また、SASS(SCSS) を利用するためのツールもインストールしておきます。

$ npm install --save-dev webpack style-loader css-loader sass-loader

webpack.config.js と development.js を作成します。

// webpack.config.js

require('babel-core/register');
module.exports = require('./development');
// development.js

import path from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'

const src = path.resolve(__dirname, 'src')
const dist = path.resolve(__dirname, 'dist')

export default [
  {
    entry: {
      bundle: src + '/js/index.jsx'
    },
    output: {
      path: dist + '/js',
      filename: '[name].js'
    },
    module: {
      loaders: [
    {
          test: /\.css$/,
          loader: 'style!css'
        },
    {
        test: /\.scss$/,
        loader: 'style!css!sass'
        },
        {
          test: /\.jsx$/,
          exclude: /node_modules/,
          loader: 'babel'
        }
      ]
    },
    resolve: {
      extensions: ['', '.js']
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: src + '/index.html',
        filename: 'index.html'
      })
    ]
  }
]
React のインストール【追記 2017/04/01】

React のインストールを行います。一番重要な内容を書き忘れていました。

$ npm install --save-dev react react-dom
アプリの作成

さて、いよいよアプリを作成します。
React の使い方はまだよく分かっていなので、引き続き上記のチュートリアル本家サイトを参考に作ってみました。

とりあえず「ボタンを押すと表示がかわる」を目指して簡単なものができました。
完成したアプリが以下です。ボタンを押すと「Hello!!!」の文字の色が変化します。
f:id:ashiris:20170205211701p:plain

index.html の内容。

// index.html


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>React Test</title>
  </head>
  <body>
    <div id="app" />
  </body>
</html>

myApp/src/js/index.jsx を作成。

import React from 'react'
import {render} from 'react-dom'

import CSS from '../css/sample.scss'

class Sample extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      style: {color: "black"},
      ind: 0,
    }
  }
  changeColor(i) {
    const colors = ['black', 'crimson', 'aqua', 'orange', 'lime', 'navy', 'silver']
    let ind = (i+1) % colors.length
    this.setState({
      style: {color: colors[ind]},
      ind: ind,
    })
  }
  render () {
    return (
      <div>
        <p style={this.state.style}>Hello!!!</p>
        <button className="change" onClick={() => this.changeColor(this.state.ind)}>
          CHANGE
        </button>
      </div>
    )
  }
}
render(<Sample />, document.getElementById('app'))

myApp/src/css/sample.scss を作成。

body {
  font: 14px "Century Gothic", Futura, sans-serif;

  .change {
    font-weight: bold;
    background-color: slateblue;
    color: white;
    padding: 5px 20px;
  }
}
アプリの起動

webpack-dev-server を起動しアプリの動作確認を行います。

$ ./node_modules/.bin/webpack-dev-server

ブラウザから web サーバーにアクセスすると画面が表示されました。

後書き

分からないなりに環境設定から行いましたが何とか ReactJS のアプリ作成までできました。 今回もそうですが、React についての記事がたくさんありますので困ってもググれば大体解決できます。 まずは、本家サイトのチュートリアルから学習していこうと思います。

ReactJS の環境構築(1)

ReactJS の勉強しようと思いたち、kvm で仮想化した CentOS に ReactJS の環境構築しました。その時のメモです。

環境

設定の流れ

  1. nodebrew のインストール
  2. NodeJS のインストール
  3. Nginx の設定
  4. ReactJS アプリの作成

(本記事には、1.〜3.を記載しています。4.は次記事に記載します。)

nodebrew のインストール

nodebrew は NodeJS のバージョン管理を行うツールです。

<参考文献>

curl コマンドでダウンロードしてインストールします。

$ curl -L git.io/nodebrew | perl - setup

nodebrew にパスを通すために、bash_profile を編集する。

$ vim ~/.bash_profile

ファイル最下行に下記を追加する。

export PATH=$HOME/.nodebrew/current/bin:$PATH

設定を反映し、インストールの確認をする。

$ source ~/.bash_profile
$ nodebrew -v
nodebrew 0.9.6
...

NodeJS のインストール

nodebrew で最新安定版の NodeJS をインストールします。

$ nodebrew install-binary stable
$ nodebrew list
v7.4.0
$ nodebrew use v7.4.0
$ node -v
v7.4.0
$ npm -v
4.0.5

Nginx の設定

web サーバには、Nginx を使用します。

<参考文献>

Nginx をインストールします。

$ sudo yum install -y http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
$ sudo yum -y install --enablerepo=nginx nginx

設定ファイルを編集します。

$ sudo vim /etc/nginx/conf.d/default.conf

ブラウザからアクセスしたら、起動しているReact アプリ表示するように編集する。

# 追加 ---------------------------------
upstream myApp {
    ip_hash;
    server 127.0.0.1:8080;
}
# --------------------------------------

server {
    listen       80;
    server_name  localhost;

    # 追加 ------------------------------------------------------------
    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
    # -----------------------------------------------------------------

    # location の設定を編集
    location / {
        proxy_pass http://myApp/;
    }

...

web サーバにアクセスできるように SELinux を無効にしておきます。

$ setenforce 0

次回起動時からも SELinux が無効になるように設定を編集します。

$ sudo vim /etc/selinux/config

以下のようにファイルを編集する。

...
# SELINUX=enforcing   # コメントアウト
SELINUX=Permissive    # 追加
...

次記事に続きます。

Amazon の自動購入プログラミングをやってみる(NodeJS)

先日インストールした CasperJS を使って Amazon サイトの自動購入処理を行うプログラミングを作成してみました。

環境

  • Arch Linux
  • PhantomJS
  • CasperJS

参考文献

プログラム

普段加湿器のアロマで使用しているオイルを自動購入するプログラムを作成します。

ソースコード
// onlineShopping.js

var AZ_EMAIL = 'XXXXXXXX';      // Amazon ID
var AZ_PASSWD = 'XXXXXXXX';     // Amazon password

var casper = require('casper').create({
        pageSettings: {
                loadImages: false,
                loadPlugins: false
        },
        waitTimeout: 30000,
        verbose: true
});

// iPhone 画面としてブラウザ操作する。
casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OSX) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

// ログイン画面へアクセスする。
casper.start('https://www.amazon.co.jp/ap/signin?_encoding=UTF8&openid.assoc_handle=jpflex&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.co.jp%2F%3Fref_%3Dnav_signin', function() {
        this.echo(this.getTitle());
        this.capture('capture1.png', {top:0, left:0, width:1280, height:720});
        this.waitForSelector('form[name="signIn"]', function() {
                this.evaluate(function(email, passwd) {
                        document.querySelector('#ap_email').value = email;
                        document.querySelector('#ap_password').value = passwd;
                }, AZ_EMAIL, AZ_PASSWD);
        });
});

// ログインする。
casper.then(function() {
        this.capture('capture2.png', {top:0, left:0, width:1280, height:720});
        this.waitForSelector('form[name="signIn"]', function() {
                this.evaluate(function() {
                        document.querySelector('#signInSubmit').click();
                });
        });
});

// 商品の画面へアクセスする。
casper.then(function() {
        this.capture('capture3.png', {top:0, left:0, width:1280, height:720});
        this.waitForSelector('#nav-logo', function() {
                this.open('https://www.amazon.co.jp/dp/B000FQR2BO/');
        });
});

// カードに入れる。
casper.then(function() {
        this.echo(this.getTitle());
        this.capture('capture4.png', {top:0, left:0, width:1280, height:720});
        this.waitForSelector('#add-to-cart-button', function() {
                this.evaluate(function() {
                        document.querySelector('#add-to-cart-button').click();
                });
        });
});

// レジへ進む。
casper.then(function() {
        this.capture('capture5.png', {top:0, left:0, width:1280, height:720});
        this.waitForSelector('#a-autoid-2-announce', function() {
                this.evaluate(function() {
                        document.querySelector('#a-autoid-2-announce').click();
                });
        });
});

// 注文を確定する。
casper.then(function() {
        this.echo(this.getTitle());
        this.capture('capture6.png', {top:0, left:0, width:1280, height:720});
        this.waitForSelector('input[name="placeYourOrder1"]', function() {
                this.echo('click click');
                this.evaluate(function() {
                        document.querySelector('input[name="placeYourOrder1"]').click();
                });
        });
});

casper.then(function() {
        this.echo(this.getTitle());
        this.capture('capture7.png', {top:0, left:0, width:1280, height:720});
});

casper.run();
コード解説

「getTitle」と「capture」を使用している箇所は、処理が正常に進んでいるかの確認のためなので主処理には無関係です。

「userAgent」を使用するとブラウザ指定や端末の種別指定ができます。ユーザーエージェントの指定によって画面の構成などが変わります。こちらのサイトでユーザーエージェントの一覧が参照できます。
いろいろと試した結果、今回は iPhone 端末上でオンライン注文する操作にしました。

「waitForSelector」を呼び出すと、第1引数で指定したセレクタが機能できるまで画面描画を待った後、第2引数で指定した処理を行います。指定したセレクタが画面上に存在しない場合はタイムアウトエラーになります。操作を確実に行うためにボタン操作はこの関数を使って行います。

後書き

今回は注文操作のために CasperJS を利用してプログラムを作成しましたが、使ってみてこのツールの便利さがわかりました。画面のキャプチャやセレクタの情報をログに履いたりとテストツールとして本当に素晴らしいです。CasperJS の公式サイトを見ると他にいろいろとできそうですのでたくさん試してみたいです。

CasperJSを使ってみる

CasperJS というツールを使ってみたので今回記事にしました。
CasperJS は PhantomJS というヘッドレスブラウザ(GUIなしのブラウザ)の拡張ライブラリで、ブラウザの操作を行ったりキャプチャをとったりできます。主にウェブアプリの自動テストに使用したりするそうです。
参考情報: Wikipedia

環境

ノートPC(OS: Arch Linux)

<余談>
Raspberry Pi に環境を構築する予定でしたが、ラズパイ用 PhantomJS のパッケージがないのでソースからビルドする必要があるらしいです。長時間がかかるそうなので後日設定してみようと思います。

作業手順

  1. PhantomJS のインストール
  2. ChasperJS のインストール

PhantomJS のインストール

<参考文献>
PhantomJSをインストールする

公式サイトよりパッケージをダウンロード。

$ cd /usr/local/src/
$ wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2

ダンロードファイルを展開し配置する。

$ sudo tar xvf phantomjs-2.1.1-linux-x86_64
$ sudo ln -s phantomjs-2.1.1-linux-x86_64 phantomjs
$ sudo ln -s /usr/local/src/phantomjs/bin/phantomjs /usr/local/bin/phantomjs

インストールの確認。

$ phantomjs -v
2.1.1

CasperJS のインストール

<参考文献>

WEB

公式サイト

書籍

JS+Node.jsによるWebクローラー/ネットエージェント開発テクニック

公式サイトの手順に従ってインストールする。

$ cd /usr/local/src
$ git clone git://github.com/casperjs/casperjs.git
$ ln -s casperjs/bin/casperjs /usr/local/bin/casperjs

インストールの確認。

$ casperjs --version
1.1.3

動作確認

グーグルトップページの全アンカータグのURLを取得するプログラムを作成してみます。

ソースコード
// getAnchors.js

var casper = require('casper').create();

// グーグルにアクセスする。
casper.start('http://www.google.com', function() {
    // ページのタイトルを表示する。
    this.echo(this.getTitle());
});

//アクセス後、ページの全アンカータグのURLを取得する。
casper.then(function() {
    // 全アンカータグを取得
    var hrefs = this.evaluate(function() {
        var alist =  document.querySelectorAll("a");
        var hrefList = [];
        for (var i=0; i<alist.length; i++) {
            hrefList.push(alist[i].href);
        }
        return hrefList;
    });
    // アンカータグのURLを表示する。
    for (var i in hrefs) {
        this.echo(hrefs[i]);
    }
});

casper.run();
プログラム実行
$ casperjs getAnchors.js
Google
https://plus.google.com/?gpsrc=ogpy0&tab=wX
https://www.google.co.jp/webhp?tab=ww
...

プログラム解説

「start(URL, 処理)」で「URL」のページへアクセスします。

そして、アクセス後の処理は「then(処理)」を使って作成します。
「casper.then(); casper.then(); ...」と実装していくことで、ブラウザ操作を順次実行することができます。

DOM操作を実装するには、「evaluate(処理)」を使います。evaluate関数内にコードを書き、関数の戻り値からセレクタの情報を拾います。

上記のようなコードが、CasperJSの基本的な実装のようです。

後書き

今回はノートPC環境で CasperJS の実装を行いましたが、Raspberry Pi で実行できるように環境を整えて行きたいです。