2015年11月24日火曜日

DockerでCentOSのコンテナを作る

このエントリーをはてなブックマークに追加

CentOSのコンテナを作成したいと思うので、docker searchコマンドで確認する。

$ docker search centos
NAME                                        DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
centos                                      The official build of CentOS.                   1652      [OK]
jdeathe/centos-ssh                          CentOS-6 6.6 x86_64 / EPEL/IUS Repos / Ope...   11                   [OK]
blalor/centos                               Bare-bones base CentOS 6.5 image                9                    [OK]
million12/centos-supervisor・・・
:
:
:
見つけた一番上のOffcialイメージをダウンロードする。
$ docker pull centos
Using default tag: latest
latest: Pulling from library/centos
fa5be2806d4c: Pull complete
0cd86ce0a197: Pull complete
e9407f1d4b65: Pull complete
c9853740aa05: Pull complete
e9fa5d3a0d0e: Pull complete
Digest: sha256:c96eeb93f2590858b9e1396e808d817fa0ba4076c68b59395445cb957b524408
Status: Downloaded newer image for centos:latest
イメージができているか確認する。
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
centos              latest              e9fa5d3a0d0e        5 weeks ago         172.3 MB
起動して確認する。
$ docker run -t -i centos:latest /bin/bash
[root@25fc2734ad99 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@25fc2734ad99 /]# whoami
root
[root@25fc2734ad99 /]# systemctl list-unit-files
UNIT FILE                            STATE
proc-sys-fs-binfmt_misc.automount    static
dev-hugepages.mount                  masked
dev-mqueue.mount                     static
proc-sys-fs-binfmt_misc.mount        static
:
:
終わって、コンテナ自体も終了しているか確認する。
[root@25fc2734ad99 /]# exit
exit
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
25fc2734ad99        centos:latest       "/bin/bash"         11 minutes ago      Exited (0) 4 seconds ago                       jovial_meninsky

今日の作業

大阪へ戻ります。

2015年11月23日月曜日

久しぶりにMacでDockerを動かそうとした

このエントリーをはてなブックマークに追加

最近、あまり用事がなかったので無かったので、MacにインストールしたDocker環境をほったらかしにしてたけど、久しぶりに触ろうかと思ったらDockerのバージョンアップと共にBoot2DockerからDocker Toolboxに変更になっていた。

以下、メモ。以前インストールしていたBoot2Dockerはアンインストールしていないけど。。。

ちなみにインストール手順はDockerの公式ドキュメントである"Get Started with Docker for Mac OS X"を参考にした

Docker Toolboxのページから"Download (Mac)"をクリックしダウンロードする。

こんな感じでインストーラが動くので指示に従って進める。


iTermで動かすとこんな感じで起動されるので、ターミナルを眺める。

Creating Machine default...
Creating CA: /Users/xxx/.docker/machine/certs/ca.pem
Creating client certificate: /Users/xxx/.docker/machine/certs/cert.pem
Running pre-create checks...
Creating machine...
(default) OUT | Creating VirtualBox VM...
(default) OUT | Creating SSH key...
(default) OUT | Starting VirtualBox VM...
(default) OUT | Starting VM...
Waiting for machine to be running, this may take a few minutes...
Machine is running, waiting for SSH to be available...
Detecting operating system of created instance...
Detecting the provisioner...
Provisioning created instance...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
To see how to connect Docker to this machine, run: /usr/local/bin/docker-machine env default
Setting environment variables for machine default...


## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/


docker is configured to use the default machine with IP 192.168.99.100
For help getting started, check out the docs at https://docs.docker.com

はい終了。


dockerコマンドで確認する。

# docker version
Client:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.3
 Git commit:   a34a1d5
 Built:        Fri Nov 20 17:56:04 UTC 2015
 OS/Arch:      darwin/amd64

Server:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.3
 Git commit:   a34a1d5
 Built:        Fri Nov 20 17:56:04 UTC 2015
 OS/Arch:      linux/amd64

VirtualBoxの画面を見ると以前のBoot2Dockerのvmはそのまま、新しいDocker Machineは"default"で作成されている。昔のは捨ててしまおう。


以前の boot2dockerコマンドはすべて docker-machineコマンドに置き換えられている。

こんな感じ。

$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM
default   *        virtualbox   Running   tcp://192.168.99.100:2376

$ docker-machine status default
Running

$ docker-machine stop default

$ docker-machine start default
(default) OUT | Starting VM...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
$ docker-machine env default
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/fumio/.docker/machine/machines/default"
export DOCKER_MACHINE_NAME="default"
# Run this command to configure your shell:
# eval "$(docker-machine env default)"

今日の作業

大阪から東京への移動と私用でほぼ終了。。。

2015年11月20日金曜日

CasperJSでログインしてみよう

このエントリーをはてなブックマークに追加

今回はCasperJSを使って、よく使う朝日新聞デジタルの無料会員IDでログインをしてみる。

ログイン部分のソースを確認して,form名やテキストボックスの名前を取得する。
var user = "ユーザ名";
var pass = "パスワード";

//CasperJSオブジェクトの生成
var casper = require('casper').create();

// これ以降、run()メソッドまでの前の処理がrun()実行時に行われる
casper.start();

// ログインページへ接続
casper.open('https://digital.asahi.com/login/');

// ログインする
casper.then(function(){
// フォームを特定し、ユーザ・パスワードを入力する。
 this.fill('form[action="login.html"]', {
  login_id: user,
  login_password: pass
 }, true);
});

// ログイン後のキャプチャをとる
casper.then(function(){
 casper.capture("asahi.png");
});

casper.run();

ログインできた。


結構、なんでもサイトをいじれて便利。いろんなツールとの組み合わせでテストなどにも使えそうだ。

今日の作業

3連休、留守にします。

2015年11月18日水曜日

CasperJSでFlickrの検索結果を取得する

このエントリーをはてなブックマークに追加
先ほどの画面キャプチャの応用というか、横展開というか。

// CasperJSオブジェクトの生成
var casper = require('casper').create();

// これ以降、run()メソッドまでの前の処理がrun()実行時に行われる
casper.start();

// 画面サイズを設定
casper.viewport(1400, 800);

// UserAgent設定
casper.userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36");

// 検索ワード
var text = encodeURIComponent("大阪");

// サイトへ接続
casper.open('https://www.flickr.com/search/?text=' + text);

// サイト接続後、capture取得
casper.then(function(){
 casper.capture("flickr-image.png",{top:0,left:0,width:1400,height:800});
});

// 処理開始
casper.run();

できたできた。


ユーザエージェントと画面サイズの変更してあげれば、iPhoneとかスマートフォンのふりをすることも可能。


今日の作業

触りで終わってしまった。

(続)CasperJSで画面キャプチャを撮る〜日本語を利用できるようにする

このエントリーをはてなブックマークに追加
タイトルの通り、昨日の続き。なるほど、TTFフォントをインストールしていないからフォントが豆腐になったのか。

LinuxなのでIPAフォントを使ってみよう。書体はゴシックでいいや。

# wget http://dl.ipafont.ipa.go.jp/IPAexfont/ipaexg00301.zip
# unzip ipaexg00301.zip
# mkdir /usr/share/fonts/ipaexg00301
# cp -ip ipaexg00301/ipaexg.ttf /usr/share/fonts/ipaexg00301/
# fc-cache -fv
/usr/share/fonts: caching, new cache contents: 0 fonts, 1 dirs
/usr/share/fonts/ipaexg00301: caching, new cache contents: 1 fonts, 0 dirs
/usr/share/X11/fonts/Type1: skipping, no such directory
/usr/share/X11/fonts/TTF: skipping, no such directory
/usr/local/share/fonts: skipping, no such directory
/root/.local/share/fonts: skipping, no such directory
/root/.fonts: skipping, no such directory
/usr/share/fonts: caching, new cache contents: 0 fonts, 1 dirs
/usr/share/X11/fonts/Type1: skipping, no such directory
/usr/share/X11/fonts/TTF: skipping, no such directory
/usr/local/share/fonts: skipping, no such directory
/root/.local/share/fonts: skipping, no such directory
/root/.fonts: skipping, no such directory
/var/cache/fontconfig: cleaning cache directory
/root/.cache/fontconfig: not cleaning non-existent cache directory
/root/.fontconfig: not cleaning non-existent cache directory
fc-cache: succeeded
確認。
# fc-list
/usr/share/fonts/ipaexg00301/ipaexg.ttf: IPAexゴシック,IPAexGothic:style=Regular

キャプチャスクリプトを再実行
# casperjs screenshot.js


できたー

2015年11月17日火曜日

CasperJSで画面キャプチャを撮る

このエントリーをはてなブックマークに追加
CasperJSで画面キャプチャも取れるらしい。マニュアルとか作る時超便利やんなんか思いながらやってみる。

// CasperJSオブジェクトの生成
var casper = require('casper').create();

// これ以降、run()メソッドまでの前の処理がrun()実行時に行われる
casper.start();

// サイトへ接続
casper.open('http://www.google.co.jp');
// サイト接続後、capture取得
casper.then(function(){
 casper.capture("screenShot.png");
});

// 処理開始
casper.run();

キャプチャを開くと文字がない。

なんでなんだろう。。。

今日の作業

文字が出ないのが残った。。。

2015年11月16日月曜日

PhantomJSとCasperJS

このエントリーをはてなブックマークに追加

世の中にはいろいろ便利なJavaScriptのライブラリがあるものです。今回はコマンドラインから利用できるPhantomJSと、そのPhantomJSを便利に使うことができるようになるCasperJSを使ってみる。

まずはインストールから。npmを使う。
# /usr/local/node/bin/npm install -g phantomjs
/usr/local/src/node-v4.2.2-linux-x64/bin/phantomjs -> /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs/bin/phantomjs

> phantomjs@1.9.18 install /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs
> node install.js

Looks like an `npm install -g`; unable to check for already installed version.
Downloading https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2
Saving to /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs/phantomjs/phantomjs-1.9.8-linux-x86_64.tar.bz2
Receiving...
  [=================================-------] 82% 0.0s
Received 12854K total.
Extracting tar contents (via spawned process)
Removing /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs/lib/phantom
Copying extracted folder /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs/phantomjs/phantomjs-1.9.8-linux-x86_64.tar.bz2-extract-1447702852021/phantomjs-1.9.8-linux-x86_64 -> /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs/lib/phantom
Writing location.js file
Done. Phantomjs binary available at /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs
phantomjs@1.9.18 /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs
├── which@1.0.9
├── progress@1.1.8
├── kew@0.4.0
├── adm-zip@0.4.4
├── request-progress@0.3.1 (throttleit@0.0.2)
├── request@2.42.0 (tunnel-agent@0.4.1, forever-agent@0.5.2, aws-sign2@0.5.0, caseless@0.6.0, oauth-sign@0.4.0, stringstream@0.0.5, json-stringify-safe@5.0.1, tough-cookie@2.2.1, mime-types@1.0.2, qs@1.2.2, node-uuid@1.4.7, http-signature@0.10.1, hawk@1.1.1, form-data@0.1.4, bl@0.9.4)
├── npmconf@2.1.1 (ini@1.3.4, inherits@2.0.1, uid-number@0.0.5, semver@4.3.6, once@1.3.2, mkdirp@0.5.1, nopt@3.0.6, config-chain@1.1.9, osenv@0.1.3)
└── fs-extra@0.23.1 (path-is-absolute@1.0.0, jsonfile@2.2.3, graceful-fs@4.1.2, rimraf@2.4.3)
# /usr/local/node/bin/npm install -g casperjs
|
> phantomjs@1.9.18 install /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs/node_modules/phantomjs
> node install.js

Looks like an `npm install -g`; unable to check for already installed version.
Downloading https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2
Saving to /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs/node_modules/phantomjs/phantomjs/phantomjs-1.9.8-linux-x86_64.tar.bz2
Receiving...
  [===================================-----] 88% 0.0s
Received 12854K total.
Extracting tar contents (via spawned process)
Removing /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs/node_modules/phantomjs/lib/phantom
Copying extracted folder /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs/node_modules/phantomjs/phantomjs/phantomjs-1.9.8-linux-x86_64.tar.bz2-extract-1447702982784/phantomjs-1.9.8-linux-x86_64 -> /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs/node_modules/phantomjs/lib/phantom
Writing location.js file
Done. Phantomjs binary available at /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs/node_modules/phantomjs/lib/phantom/bin/phantomjs
/usr/local/src/node-v4.2.2-linux-x64/bin/casperjs -> /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs/bin/casperjs
casperjs@1.1.0-beta3 /usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/casperjs
└── phantomjs@1.9.18 (which@1.0.9, progress@1.1.8, kew@0.4.0, adm-zip@0.4.4, request-progress@0.3.1, npmconf@2.1.1, request@2.42.0, fs-extra@0.23.1)

サイトのタイトルを取ってくる簡単なサンプルを書いて実行してみる。
// 取得するURLを設定
var TARGET_URL = "http://smile-smile-at-smile.blogspot.jp/";

// CasperJSオブジェクトの生成
var casper = require('casper').create();

// 指定のサイトを開く
casper.start(TARGET_URL, function(){
 // サイトタイトルの表示
 this.echo(casper.getTitle());
});

// このrun()メソッドが呼ばれた時点で
// start()メソッドに登録した処理が実行される
casper.run();

実行したら怒られた。
# casperjs getTitle.js
/usr/local/src/node-v4.2.2-linux-x64/lib/node_modules/phantomjs/lib/phantom/bin/phantomjs: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory

fontconfigをインストール。
# yum install fontconfig

再度、実行してみる。
# casperjs getTitle.js
いつも君は僕のPAYDAYを取り上げるんだ

できたじゃん。

今日の作業

OpenCVの画像検出できた時はすごいうれしかった!あとは黙々とパース処理。。。

node.jsでRSSをパースする

このエントリーをはてなブックマークに追加
この前までクローリングとかやったので、今度はRSSをパースしてみる。

ここでnodeでXMLを読み込む際に便利なxml2jsをインストールしておく
# /usr/local/node/bin/npm install xml2js
xml2js@0.4.15 node_modules/xml2js
├── sax@1.1.4
└── xmlbuilder@4.1.0 (lodash@3.10.1)

今回は地元の大阪の週間天気を取り出すことにした。内容はこちら

取得したRSSをパースして天気の内容を取りだす。
// 大阪の週間天気予報RSS
var RSS = "http://rss.weather.yahoo.co.jp/rss/days/6200.xml";

// モジュールの読み込み
var parseString = require('xml2js').parseString;
var request = require('request');

// RSS取得
request(RSS, function(err, response, body){
 if(!err && response.statusCode == 200){
  analyzeRSS(body);
 }
});

// 関数定義
function analyzeRSS(xml){
 // XMLをJSのオブジェクトに変換
 parseString(xml, function(err, obj){
  // エラー処理
  if(err){
   console.log(err);
   return;
  }
  
  // RSS内のあるrss要素の下のchannel要素のitemをすべて取り出す
  var items = obj.rss.channel[0].item;
  
  // item要素の数だけループさせる
  for(var i in items){
   var item = items[i];
   // item内のtitle要素をコンソールに表示
   console.log(item.title[0]);
  }
 });
}

取得した結果はこちら。

# /usr/local/node/bin/node tenki.js
【 16日(月) 大阪(大阪) 】 晴れ - 22℃/12℃ - Yahoo!天気・災害
【 17日(火) 大阪(大阪) 】 曇後雨 - 22℃/14℃ - Yahoo!天気・災害
【 18日(水) 大阪(大阪) 】 曇時々雨 - 21℃/16℃ - Yahoo!天気・災害
【 19日(木) 大阪(大阪) 】 曇時々雨 - 19℃/13℃ - Yahoo!天気・災害
【 20日(金) 大阪(大阪) 】 曇時々晴 - 19℃/11℃ - Yahoo!天気・災害
【 21日(土) 大阪(大阪) 】 晴時々曇 - 18℃/10℃ - Yahoo!天気・災害
【 22日(日) 大阪(大阪) 】 曇時々晴 - 19℃/11℃ - Yahoo!天気・災害
【 23日(月) 大阪(大阪) 】 曇り - 19℃/13℃ - Yahoo!天気・災害
【 大阪市 】警報・注意報はありません - Yahoo!天気・災害
【 北大阪 】警報・注意報はありません - Yahoo!天気・災害
【 東部大阪 】警報・注意報はありません - Yahoo!天気・災害
【 南河内 】警報・注意報はありません - Yahoo!天気・災害
【 泉州 】警報・注意報はありません - Yahoo!天気・災害

OpenCV Tutorial(4)〜特定画像の検出

このエントリーをはてなブックマークに追加
ドラクエの戦闘画面からカンダタの子分を取り出してみた。

元画像のこれから
これを取り出してみる。

import cv2
import numpy as np
from matplotlib import pyplot as plt

img_rgb = cv2.imread('dq.jpeg')
img_rgb2 = img_rgb.copy()
img_gray = cv2.cvtColor(img_rgb2, cv2.COLOR_BGR2GRAY)
template = cv2.imread('template.png',0)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
    cv2.rectangle(img_rgb2, pt, (pt[0] + w, pt[1] + h), (255,0,0), 1)

plt.subplot(121),plt.imshow(img_rgb)
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_rgb2)
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.show()

おぉ、とりだせた。


2015年11月15日日曜日

OpenCV Tutorial(3)〜画像の輪郭検出

このエントリーをはてなブックマークに追加
本当ならガウシアンフィルタにかけてノイズの提言をさせてから、色相の勾配を該当ピクセルの近傍と比較して計算して...ってやらないといけないわけだけど、OpenCVに関しては、関数を一発呼ぶだけでやってくれる。

すげえ。

import cv2
import numpy as np
from matplotlib import pyplot as plt

# グレースケールで読み込み
img = cv2.imread('20120129-00000000-jijp-000-0-view-thumb-450x300-8462.jpg',0)

# 閾値の上限200、下限を100に指定
edges = cv2.Canny(img,100,200)

plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

plt.show()


今日の作業

この辺からだいたい分かっとく必要のあるところと、飛ばしてもいいところを見極めるのが難しくなってきた。そのおかげでか進捗が少ない。。。

2015年11月13日金曜日

OpenCV Tutorial(2)〜画像の平滑化

このエントリーをはてなブックマークに追加
Smoothing Images

画像の平滑化手法(Smoothing Images)に幾つかのやり方があり、それぞれ得意/不得意があるので簡単にでも理解した上で使い分けるのがベター。

大きくはノイズを減らすのが得意なlow-pass filters(LPF)と輪郭をシャープにするhigh-pass filters(HPF)に分けられる。

代表的な種類としてはこんなものがある。
  • 2D Convolution(2次元畳み込み)
  • Averaging(平均)
  • Gaussian Blurring(ガウシアンぼかし)
  • Median Blurring(中央値ぼかし)
  • Bilateral Filtering(バイラテラルフィルタ)
それぞれやってみる。画像は適当なものを取ってきた。

2D Convolution(2次元畳み込み)


import cv2
import numpy as np
from matplotlib import pyplot as plt

# 画像をそのまま読み込む
img = cv2.imread('G-symbol.png')

# すべての要素が浮動小数点1の5×5の行列を作成、平均を出すために25で割る
# このカーネルさえ自作できれば、いろいろなフィルターが自作できる
kernel = np.ones((5,5),np.float32)/25
# kernelをそのまま適用する。ビット深度はそのまま
dst = cv2.filter2D(img,-1,kernel)

# 横に1行で2つならべ、1つ目なので(1, 2, 1)
# subplot(121)はsubplot(1, 2, 1)と同じ
plt.subplot(121),plt.imshow(img),plt.title('Original')
# x,y軸のメモリなし
plt.xticks([]), plt.yticks([])
# 横に1行で2つならべ、2つ目なので(1, 2, 2)
plt.subplot(122),plt.imshow(dst),plt.title('Averaging')
# x,y軸のメモリなし
plt.xticks([]), plt.yticks([])

# 画像表示
plt.show()


Averaging(平均)


import cv2
from matplotlib import pyplot as plt

# 画像をそのまま読み込む
img = cv2.imread('G-symbol.png')

# 平均値ぼかし処理。今回の場合2Dフィルタと同じ処理になる。
blur = cv2.blur(img,(5,5))

plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()                                                                         


Gaussian Blurring(ガウシアンぼかし)


import cv2
from matplotlib import pyplot as plt

img = cv2.imread('G-symbol.png')

# ガウシアンぼかし(5, 5)は中心からの計算するピクセル範囲
# ガウシアンの場合は自動的に中心に近いほど近傍値としての重みが高くなり平滑化される
blur = cv2.GaussianBlur(img,(5,5),0)

plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()


Median Blurring(中央値ぼかし)


import cv2
from matplotlib import pyplot as plt

img = cv2.imread('ZebraWithAttachedShadow_noisy_Salt_and_Pepper.jpg')

# 指定した範囲内でのピクセル数の平均値をとる。
# 白、黒などの極端なノイズは無視されるため、ノイズ除去に強い
median = cv2.medianBlur(img,5)

plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(median),plt.title('Median')
plt.xticks([]), plt.yticks([])
plt.show()


Bilateral Filtering(バイラテラルフィルタ)


import cv2
from matplotlib import pyplot as plt

img = cv2.imread('woos4.jpg')

# 入力画像、中心部からのピクセル範囲、カラーシグマ値、空間シグマ値
# カラーシグマが大きいとピクセル間での濃淡差が大きくないと効果がでない
# 空間シグマが大きいと輪郭意外のボケがおおきくなるが計算処理に時間がかかる
blur = cv2.bilateralFilter(img,9,75,75)

plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Bilateral')
plt.xticks([]), plt.yticks([])
plt.show()


今日の作業

スムージングの特徴をもう少し明確につかみたい。

EclipseからFedora23へRSEでサーバにSSH接続できない

このエントリーをはてなブックマークに追加

いつもサーバへソースなどファイルをアップロードする時にはEclipseのRSE経由でSFTPで行っているのだが、今使っているFedora23へ同様にしようとすると下記のようなメッセージが出て接続できなかった。

"172.16.33.160:22" 上で sshd の接続に失敗しました
Session.connect: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)

その他のCentOS7などのサーバへは同様に接続できる。

クライアントの環境はこんな感じ。

OS:MacOS El Capitan
Java:1.7.0_67
Eclipse:Version: Mars.1 Release (4.5.1)、Build id 20150924-1200
RSE:3.7.0.201505221634

調べてみると「SunJCE の Diffie-Hellman アルゴリズムで 1024 ビットを超える素数が使えない」にJava8にアップデートしたらいけそうな感じだったのでしてみることに。

Java SDK8をダウンロードしてきてインストール。

インストールされたか今までのバージョンの確認をしてみる。
# java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
# /usr/libexec/java_home -V
Matching Java Virtual Machines (4):
    1.8.0_65, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home
    1.7.0_67, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home
    1.6.0_65-b14-468, x86_64: "Java SE 6" /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
    1.6.0_65-b14-468, i386: "Java SE 6" /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home

Eclipseを再起動して、再度RSEで接続してみるといけた。

ちなみにJavaのバージョンを切り替える場合は下記のようにする。
# export JAVA_HOME=`/usr/libexec/java_home -v 1.7.0_67`
# java -version
java version "1.7.0_67"
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
# export JAVA_HOME=`/usr/libexec/java_home -v 1.8.0_65`
# java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

2015年11月12日木曜日

OpenCV Tutorial(1)〜特定色のトラッキング

このエントリーをはてなブックマークに追加
OpenCVのサイトにオンラインドキュメントでチュートリアルがあったので、ざっと眺めてためそうと思う。使う言語はCではなくpythonにしてみる。(慣れてるし)

Image Processing in OpenCVから。

Changing Colorspaces

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

while(1):

    # Take each frame
    _, frame = cap.read()

    # Convert BGR to HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    # define range of blue color in HSV
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])

    # Threshold the HSV image to get only blue colors
    mask = cv2.inRange(hsv, lower_blue, upper_blue)

    # Bitwise-AND mask and original image
    res = cv2.bitwise_and(frame,frame, mask= mask)

    cv2.imshow('frame',frame)
    cv2.imshow('mask',mask)
    cv2.imshow('res',res)
    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break

cv2.destroyAllWindows()

青色でマスクされた部分が動画でトラッキングされながらグレースケールと青のみでマスクされて表示された。


今日の作業

Bloggerのデザイン微修正とOpenCVのチュートリアル見つけて1つのみ。残念。あと、ソースにコメントを付けて補足したい。

2015年11月11日水曜日

画像の特徴点を抽出する

このエントリーをはてなブックマークに追加
せっかく入れたOpenCVなので何かやってみたい。

といってもパッと難しいことはできないので、よくある画像の特徴点抽出をやってみようかと思った。
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('/usr/local/src/opencv-3.0.0/samples/data/lena.jpg',0)

# Initiate STAR detector
orb = cv2.ORB_create()

# find the keypoints with ORB
kp = orb.detect(img,None)

# compute the descriptors with ORB
kp, des = orb.compute(img, kp)

# draw only keypoints location,not size and orientation
img2 = cv2.drawKeypoints(img,kp, None,color=(0,255,0))
plt.imshow(img2),plt.show()

出来た。

今日の作業

OpenCVのインストールが手強すぎて、あまり他のことに時間が割けなかった。とはいえ、OpenCV入れたので何ができるかの基本は押さえておきたい。明日は少し進展できたらいいな。

gcc: エラー: /usr/lib/rpm/redhat/redhat-hardened-cc1: そのようなファイルやディレクトリはありません

このエントリーをはてなブックマークに追加
gcc: エラー: /usr/lib/rpm/redhat/redhat-hardened-cc1: そのようなファイルやディレクトリはありません

と出た時はrpm-buildパッケージが足りないので、インストールしないといけない。
#dnf -y install rpm-build
依存性が解決されました。
================================================================================
 パッケージ                   アーキテクチャ
                                       バージョン               リポジトリ
                                                                           容量
================================================================================
インストール中:
 dwz                          x86_64   0.12-1.fc23              fedora    106 k
 ghc-srpm-macros              noarch   1.4.2-2.fc23             fedora    8.2 k
 gnat-srpm-macros             noarch   2-1.fc23                 fedora    8.4 k
 go-srpm-macros               noarch   2-3.fc23                 fedora    8.0 k
 ocaml-srpm-macros            noarch   2-3.fc23                 fedora    8.1 k
 perl-generators              noarch   1.06-1.fc23              updates    15 k
 perl-srpm-macros             noarch   1-17.fc23                fedora    9.7 k
 redhat-rpm-config            noarch   36-1.fc23                fedora     59 k
 rpm-build                    x86_64   4.13.0-0.rc1.6.fc23      updates   135 k
アップグレード中:
 rpm                          x86_64   4.13.0-0.rc1.6.fc23      updates   509 k
 rpm-build-libs               x86_64   4.13.0-0.rc1.6.fc23      updates   115 k
 rpm-libs                     x86_64   4.13.0-0.rc1.6.fc23      updates   293 k
 rpm-plugin-selinux           x86_64   4.13.0-0.rc1.6.fc23      updates    50 k
 rpm-plugin-systemd-inhibit   x86_64   4.13.0-0.rc1.6.fc23      updates    50 k
 rpm-python                   x86_64   4.13.0-0.rc1.6.fc23      updates    99 k
 rpm-python3                  x86_64   4.13.0-0.rc1.6.fc23      updates   100 k

トランザクションの要約
================================================================================
インストール    9 Packages
アップグレード  7 Packages

総ダウンロード容量: 1.5 M


(2016/1/1:追記)
redhat-rpm-configだけあればいけるみたい。

OpenCV3.0.0のインストール

このエントリーをはてなブックマークに追加

昔、1.x時代に少し触ったことがあったのだけど、今は3.0にまでなってると知ったのでもう一回触ってみたくてインストールしてみた。

OpenCVのインストールに必要なパッケージのインストール


まずはソースをダウンロードして解凍するとこまでは省略。

こっからcmakeしていくわけだけど、画像や動画周りのライブラリがあからさまに足りなさそう。なので、OpenCVのドキュメントを見ながら潰していくことにした。
http://docs.opencv.org/3.0-last-rst/doc/tutorials/introduction/linux_install/linux_install.html?highlight=install

Ubuntuベースで書かれているので少し困る。僕が入れようとしているのはFedoraだ。apt-getではなくdnfなのだ。すでに心が折れそうなのだが読み解いて、足らない時は考える方向にした。

書かれているのは
[compiler] sudo apt-get install build-essential
[required] sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
[optional] sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
といった感じ。すでにffmpegがないのが気がかりな点だったのだが、
ffmpeg or libav development packages: libavcodec-dev, libavformat-dev, libswscale-dev
とあるので、ライブラリかffmpegかが入っていればよさそうだ。

少し調べてみよう。

ちなみにRPM Fusionのリポジトリは追加済み。パッケージ調べてみてこれでいけるんじゃないかと踏んだ。
# dnf install ffmpeg-devel ffmpeg gtk2-devel pkgconfig python-devel numpy openjpeg-devel libpng-devel libtiff-devel jasper-devel tbb tbb-devel libdc1394-devel libdc1394
メタデータの期限切れの確認は、0:16:32 前の Wed Nov 11 03:30:28 2015 に実施しました。
Package pkgconfig-1:0.28-9.fc23.x86_64 is already installed, skipping.
依存性が解決されました。
========================================================================================================================
 パッケージ                アーキテクチャ
                                       バージョン                             リポジトリ                           容量
========================================================================================================================
インストール中:
 SDL                       x86_64      1.2.15-20.fc23                         updates                             213 k
 atk-devel                 x86_64      2.18.0-1.fc23                          fedora                              185 k
 atlas                     x86_64      3.10.2-6.fc23                          fedora                              5.7 M
 cairo-devel               x86_64      1.14.2-2.fc23                          fedora                              354 k
 expat-devel               x86_64      2.1.0-12.fc23                          fedora                               61 k
 ffmpeg                    x86_64      2.8.1-1.fc23                           rpmfusion-free-updates-testing      1.3 M
 ffmpeg-devel              x86_64      2.8.1-1.fc23                           rpmfusion-free-updates-testing      679 k
 ffmpeg-libs               x86_64      2.8.1-1.fc23                           rpmfusion-free-updates-testing      5.5 M
 fontconfig-devel          x86_64      2.11.94-4.fc23                         fedora                              137 k
 freetype-devel            x86_64      2.6.0-3.fc23                           fedora                              378 k
 fribidi                   x86_64      0.19.6-5.fc23                          fedora                               69 k
 gdk-pixbuf2-devel         x86_64      2.32.1-1.fc23                          fedora                              217 k
 gl-manpages               noarch      1.1-10.20140424.fc23                   fedora                              1.0 M
 glib2-devel               x86_64      2.46.1-2.fc23                          fedora                              436 k
 graphite2-devel           x86_64      1.2.4-5.fc23                           fedora                               41 k
 gtk2-devel                x86_64      2.24.28-2.fc23                         fedora                              2.9 M
 harfbuzz-devel            x86_64      1.0.6-1.fc23                           updates                             122 k
 jasper-devel              x86_64      1.900.1-31.fc23                        fedora                              379 k
 lame-libs                 x86_64      3.99.5-5.fc23                          rpmfusion-free-updates-testing      345 k
 libX11-devel              x86_64      1.6.3-2.fc23                           fedora                              984 k
 libXau-devel              x86_64      1.0.8-5.fc23                           fedora                               19 k
 libXcomposite-devel       x86_64      0.4.4-7.fc23                           fedora                               21 k
 libXcursor-devel          x86_64      1.1.14-4.fc23                          fedora                               27 k
 libXdamage-devel          x86_64      1.1.4-7.fc23                           fedora                               14 k
 libXext-devel             x86_64      1.3.3-3.fc23                           fedora                               79 k
 libXfixes-devel           x86_64      5.0.1-5.fc23                           fedora                               17 k
 libXft-devel              x86_64      2.3.2-3.fc23                           fedora                               24 k
 libXi-devel               x86_64      1.7.4-3.fc23                           fedora                              109 k
 libXinerama-devel         x86_64      1.1.3-5.fc23                           fedora                               18 k
 libXrandr-devel           x86_64      1.5.0-2.fc23                           fedora                               25 k
 libXrender-devel          x86_64      0.9.9-2.fc23                           fedora                               21 k
 libXxf86vm-devel          x86_64      1.1.4-2.fc23                           fedora                               23 k
 libass                    x86_64      0.12.1-2.fc23                          fedora                               85 k
 libavdevice               x86_64      2.8.1-1.fc23                           rpmfusion-free-updates-testing       76 k
 libdc1394                 x86_64      2.2.2-4.fc23                           fedora                              123 k
 libdc1394-devel           x86_64      2.2.2-4.fc23                           fedora                               57 k
 libdrm-devel              x86_64      2.4.65-1.fc23                          fedora                              111 k
 libgfortran               x86_64      5.1.1-4.fc23                           fedora                              285 k
 libicu-devel              x86_64      54.1-5.fc23                            fedora                              741 k
 libjpeg-turbo-devel       x86_64      1.4.1-2.fc23                           fedora                              104 k
 libpng-devel              x86_64      2:1.6.17-2.fc23                        fedora                              310 k
 libquadmath               x86_64      5.1.1-4.fc23                           fedora                              173 k
 libraw1394-devel          x86_64      2.1.0-6.fc23                           fedora                               44 k
 libtiff-devel             x86_64      4.0.4-1.fc23                           fedora                              487 k
 libva                     x86_64      1.6.1-1.fc23                           fedora                               83 k
 libxcb-devel              x86_64      1.11.1-1.fc23                          updates                             1.1 M
 libxshmfence-devel        x86_64      1.2-2.fc23                             fedora                              9.6 k
 mesa-libEGL-devel         x86_64      11.0.3-1.20151012.fc23                 fedora                               42 k
 mesa-libGL-devel          x86_64      11.0.3-1.20151012.fc23                 fedora                              163 k
 numpy                     x86_64      1:1.9.2-2.fc23                         fedora                              3.0 M
 openal-soft               x86_64      1.16.0-7.fc23                          fedora                              290 k
 opencv-core               x86_64      2.4.11-5.fc23                          fedora                              1.8 M
 openjpeg                  x86_64      1.5.1-15.fc23                          fedora                              189 k
 openjpeg-devel            x86_64      1.5.1-15.fc23                          fedora                              376 k
 openjpeg-libs             x86_64      1.5.1-15.fc23                          fedora                               89 k
 pango-devel               x86_64      1.38.1-1.fc23                          fedora                              324 k
 pixman-devel              x86_64      0.33.4-1.fc23                          updates                              18 k
 python-devel              x86_64      2.7.10-8.fc23                          fedora                              397 k
 python-macros             noarch      2.7.10-8.fc23                          fedora                               61 k
 python-nose               noarch      1.3.7-4.fc23                           fedora                              280 k
 schroedinger              x86_64      1.0.11-9.fc23                          fedora                              317 k
 tbb                       x86_64      4.3-3.20141204.fc23                    fedora                              140 k
 tbb-devel                 x86_64      4.3-3.20141204.fc23                    fedora                              259 k
 x264-libs                 x86_64      0.148-1.20151020gita0cd7d3.fc23        rpmfusion-free-updates-testing      590 k
 x265-libs                 x86_64      1.8-1.fc23                             rpmfusion-free-updates-testing      528 k
 xorg-x11-proto-devel      noarch      7.7-16.fc23                            fedora                              287 k
 xvidcore                  x86_64      1.3.4-2.fc23                           rpmfusion-free-updates-testing      266 k
 zlib-devel                x86_64      1.2.8-9.fc23                           fedora                               55 k

トランザクションの要約
========================================================================================================================
インストール  68 Packages

総ダウンロード容量: 34 M
インストール済み容量: 139 M

OpenCVのインストール

OpenCVのconfigureをccmakeで行う。インストール先は/usr/local/opencvとして、python, javaにも対応しておく。あとexampleも入れておきたい。
# cd /usr/local/src/opencv-3.0.0/
# mkdir build
# cd build/
# ccmake ..

PackageKit-Qt5-develも必要だったのと、python3-develpython3-numpyplibv4l-develpmesa-libGL-develmesa-libGLU-develも追加しておいた。

またJAVA用にantも探しているぽかったのでインストールしておいた。

# wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/ant/binaries/apache-ant-1.9.6-bin.tar.gz
# tar -xvzf apache-ant-1.9.6-bin.tar.gz
# ln -s /usr/local/src/apache-ant-1.9.6 /usr/local/ant
antへのパスも通しておく。
ANT_HOME=/usr/local/ant
PATH=$PATH:$ANT_HOME/bin

今回ccmakeで選んだオプションをキャプチャーしたので貼っておく。




ここからmakeしていく。
# make -j7
バリバリにwarningが出てるが、一旦、気にしない。気長に待つ。

エラーが出てこけた。

大域スコープ:
cc1plus: 警告: 認識できないコマンドラインオプション ‘-Wno-unnamed-type-template-args’ です
[ 47%] Linking CXX executable ../../bin/cpp-example-autofocus
../../lib/libopencv_world.so.3.0.0: `DefaultViewPort::staticMetaObject' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for CvWinProperties' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `CvWindow::staticMetaObject' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `CvTrackbar::staticMetaObject' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for CvPushButton' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for GuiReceiver' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for CvCheckBox' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for CvTrackbar' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for DefaultViewPort' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for CvWindow' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `CvButtonbar::staticMetaObject' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for CvRadioButton' に対する定義されていない参照です
../../lib/libopencv_world.so.3.0.0: `vtable for CvButtonbar' に対する定義されていない参照です
collect2: エラー: ld はステータス 1 で終了しました
samples/cpp/CMakeFiles/example_autofocus.dir/build.make:97: recipe for target 'bin/cpp-example-autofocus' failed
make[2]: *** [bin/cpp-example-autofocus] Error 1
CMakeFiles/Makefile2:3671: recipe for target 'samples/cpp/CMakeFiles/example_autofocus.dir/all' failed
make[1]: *** [samples/cpp/CMakeFiles/example_autofocus.dir/all] Error 2
Makefile:138: recipe for target 'all' failed
make: *** [all] Error 2

opencv_worldが悪さをしているみたいなので、一旦OFFにした。各種モジュールを1つのライブラリにするだけみたいなので、特に問題ないかなと。

あと、POLICYIDがどうのこうのと言われるので、CMakeList.txtに追記した。
if(POLICY CMP0045)
  cmake_policy(SET CMP0049 OLD)
endif()

if(POLICY CMP0059)
  cmake_policy(SET CMP0059 OLD)
endif()
再トライしたところ、うまくmake終了。make installもうまくいった。

ただ、ここまでだとsampleがインストールされないので、動作確認するまでにsampleもインストールしておく。
# cd /usr/local/src/opencv-3.0.0/build/samples
# make
この後、もうCMakeList.txtができるので、もう1度ccmake

# pwd
/usr/local/src/opencv-3.0.0/build/samples
# ccmake .
# make

これで/usr/local/src/opencv-3.0.0/samplesにサンプルがインストールされた。

実際に試してみる。

# /usr/local/src/opencv-3.0.0/samples/cpp/cpp-example-facedetect --cascade="/usr/local/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml" --scale=1.3 /usr/local/src/opencv-3.0.0/samples/data/lena.jpg 


出来た!!!
でもソースをコンパイルしたディレクトリ配下なので少し気持ち悪い。/usr/local/opencvの下にどうしたらインストールできるんやろう。

Fedora23にRPM Fusionリポジトリを追加する

このエントリーをはてなブックマークに追加

そういややってなかったので、Fedora23にRPM Fusionのリポジトリを追加しておく。

RPM Fusionは公式リポジトリに入っていないオープンソースのfreeとライセンス的にNGやソース非公開などのプロダクトが収録されたnonfreeの2つあるので両方いれておく。

ちなみにdnfのリポジトリ自体はまだ/etc/yum.repos.d/にある。

それっと追加。

# dnf install 'http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-23.noarch.rpm' 'http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-23.noarch.rpm'
メタデータの期限切れの確認は、0:24:26 前の Wed Nov 11 02:35:49 2015 に実施しました。
依存性が解決されました。
========================================================================================================================
 パッケージ                               アーキテクチャ        バージョン            リポジトリ                   容量
========================================================================================================================
インストール中:
 rpmfusion-free-release                   noarch                23-0.1                @commandline                 19 k
 rpmfusion-nonfree-release                noarch                23-0.1                @commandline                 19 k

トランザクションの要約
========================================================================================================================
インストール  2 Packages

合計容量: 39 k
インストール済み容量: 20 k
これでいいですか? [y/N]: y
パッケージをダウンロードしています:
トランザクションの確認を実行中...
トランザクションの確認に成功しました。
トランザクションのテストを実行中...
トランザクションのテストに成功しました。
トランザクションを実行中...
  インストール中  : rpmfusion-free-release-23-0.1.noarch                                                            1/2
  インストール中  : rpmfusion-nonfree-release-23-0.1.noarch                                                         2/2
警告: rpmfusion-nonfree-release-23-0.1.noarch: ヘッダー V4 RSA/SHA1 Signature、鍵 ID 5ca6c469: NOKEY
  検証中          : rpmfusion-nonfree-release-23-0.1.noarch                                                         1/2
  検証中          : rpmfusion-free-release-23-0.1.noarch                                                            2/2

インストール:
  rpmfusion-free-release.noarch 23-0.1                      rpmfusion-nonfree-release.noarch 23-0.1

完了しました!

無事終了。

2015年11月10日火曜日

特定サイトをクローリングする

このエントリーをはてなブックマークに追加
ある特定のドメインのサイトを一定階層までダウンロードしてみる。

/**
 * メイン処理
 */

// ライブラリ読み込み
var client = require('cheerio-httpcli');
var request = require('request');
var URL = require('url');
var fs = require('fs');
var path = require('path');

// 読み込み階層を今回は3までに指定
var LINK_LEVEL = 3;
// ダウンロード先
var TARGET_URL = "http://docs.opencv.org/3.0.0/";
var list = {};

// ダウンロード関数実行
downloadRec(TARGET_URL, 0);

/*
 * 関数定義
 */
function downloadRec(url, level){
 // 読み込み階層を超えてたら実行終了
 if( level >= LINK_LEVEL){
  return;
 }
 
 // listに追加されたurlがTRUE(ダウンロード済み)であれば抜ける
 if(list[url]){
  return;
 }
 
 list[url] = true;
 
 // 外部ドメインは無視する
 var us = TARGET_URL.split("/");
 us.pop();
 var base = us.join("/");
 if(url.indexOf(base) < 0){
  return;
 }
 
 client.fetch(url, {}, function(err, $, res){
  // エラーが返されたら終了
  if(err){
         console.log("Error", err);
         console.log("RESPONCE", res);
  }
  // aタグをすべてチェック
  $("a").each(function(idx){
   var href = $(this).attr("href");
   // リンク先がなければ終了
   if(!href){
    return;
   }
   
   // 相対パスを絶対パスへ変更
   href = URL.resolve(url, href);
   
   // アンカーリンクは無視
   href = href.replace(/\#.+$/, "");
   
   // リンク先のURLに対して再帰的に実行
   downloadRec(href, level + 1);
  });
  
  // URLの最後が’/’だけだったらindex.htmlを足す
  if(url.substr(url.length-1, 1) == "/"){
   url += "index.html";
  }
  
  // 3層までなのでURLを一旦’/’で分割し、最後から2つの要素を取り出し、再度’/’をつけてディレクトリパスにする。
  var savepath = url.split("/").slice(2).join("/");
  checkSaveDir(savepath);
  console.log(savepath);
  fs.writeFileSync(savepath, $.html());
  
 });
}

// 該当のディレクトリがあるかどうかチェック
function checkSaveDir(fname){
 var dir = path.dirname(fname);
 
 var dirlist = dir.split("/");
 var p = "";
 
 for(var i in dirlist){
  p += dirlist[i] + "/";
  if(!fs.existsSync(p)){
   fs.mkdirSync(p);
  }
 }
}
順調に行ってたら、このメッセージが出た。エラー処理を入れて確認してみる。
getall.js:37 $("a").each(function(idx){ ^ TypeError: $ is not a function     at Object.callback (/root/WebCrawler-NetAgent/ch02/getall.js:37:3)     at Object.module.exports.fail (/root/node_modules/cheerio-httpcli/lib/client.js:59:15)     at Object.<anonymous> (/root/node_modules/cheerio-httpcli/lib/client.js:191:21)     at Object.<anonymous> (/root/node_modules/cheerio-httpcli/lib/client.js:129:16)     at self.callback (/root/node_modules/cheerio-httpcli/node_modules/request/request.js:198:22)     at emitOne (events.js:77:13)     at Request.emit (events.js:169:7)     at null._onTimeout (/root/node_modules/cheerio-httpcli/node_modules/request/request.js:811:12)     at Timer.listOnTimeout (timers.js:92:15)
client.fetchの一番上にエラー処理を入れてみた。
:
:
 client.fetch(url, {}, function(err, $, res){
  if(err){
   console.log("Error", err);
   console.log("RESPONCE", res);
   return;
  }
  
  $("a").each(function(idx){
   var href = $(this).attr("href");
   if(!href){
    return;
   }
:
:
すると、約300ページほどタイムアウトで取得できていないことがわかった。ただURLを直接ブラウザで確認すると問題なさそうなので、なんでかなと思いつつ一旦スルー。ちなみにこんなエラー。
Error { [Error: ETIMEDOUT]   code: 'ETIMEDOUT',   connect: true,   url: 'http://docs.opencv.org/3.0.0/dd/de2/classcv_1_1AutoLock.html',   param: {} } RESPONCE undefined Error { [Error: ETIMEDOUT]   code: 'ETIMEDOUT',   connect: true,   url: 'http://docs.opencv.org/3.0.0/d7/d7b/classcv_1_1BackgroundSubtractorMOG2.html',   param: {} } RESPONCE undefined Error { [Error: ETIMEDOUT]   code: 'ETIMEDOUT',   connect: true,   url: 'http://docs.opencv.org/3.0.0/d0/d2e/classcv_1_1CommandLineParser.html',   param: {} }
こんなのが300個ほど。(正確には332個だった) 取得したのを確認してみるとこんな感じ。 あと404も1つあった。これは実際のサイトのURLをたどっても404だったのでプログラム的には問題なし。
Error { [Error: server status]   url: 'http://docs.opencv.org/3.0.0//3.0-last-rst',   param: {},   statusCode: 404 } RESPONCE IncomingMessage {   _readableState:    ReadableState {      objectMode: false,      highWaterMark: 16384,      buffer: [],      length: 0,      pipes: null,      pipesCount: 0,      flowing: true,      ended: true,      endEmitted: true,      reading: false,      sync: false,      needReadable: false,      emittedReadable: false,      readableListening: false,      defaultEncoding: 'utf8',      ranOut: false,      awaitDrain: 0,      readingMore: false,      decoder: null,      encoding: null,      resumeScheduled: false },   readable: false,   domain: null,   _events:    { end: [ [Function: responseOnEnd], [Function], [Function], [Function] ],      close: [ [Function], [Function] ],      data: [Function],      error: [Function] },   _eventsCount: 4,   _maxListeners: undefined,   socket:    Socket {      _connecting: false,      _hadError: false,      _handle: null,      _parent: null,      _host: 'docs.opencv.org',      _readableState:       ReadableState {         objectMode: false,         highWaterMark: 16384,         buffer: [],         length: 0,         pipes: null,         pipesCount: 0,         flowing: true,         ended: true,         endEmitted: true,         reading: false,         sync: false,         needReadable: false,         emittedReadable: false,         readableListening: false,         defaultEncoding: 'utf8',         ranOut: false,         awaitDrain: 0,         readingMore: false,         decoder: null,         encoding: null,         resumeScheduled: false },      readable: false,      domain: null,      _events:       { end: [Object],         finish: [Function: onSocketFinish],         _socketEnd: [Function: onSocketEnd],         free: [Function: onFree],         close: [Object],         agentRemove: [Function: onRemove],         drain: [Function: ondrain],         error: [Object],         data: [Function: socketOnData],         timeout: [Object] },      _eventsCount: 10,      _maxListeners: 0,      _writableState:       WritableState {         objectMode: false,         highWaterMark: 16384,         needDrain: false,         ending: true,         ended: true,         finished: true,         decodeStrings: false,         defaultEncoding: 'utf8',         length: 0,         writing: false,         corked: 0,         sync: false,         bufferProcessing: false,         onwrite: [Function],         writecb: null,         writelen: 0,         bufferedRequest: null,         lastBufferedRequest: null,         pendingcb: 0,         prefinished: true,         errorEmitted: false },      writable: false,      allowHalfOpen: false,      destroyed: true,      bytesRead: 383,      _bytesDispatched: 292,      _sockname: null,      _pendingData: null,      _pendingEncoding: '',      parser: null,      _httpMessage:       ClientRequest {         domain: null,         _events: [Object],         _eventsCount: 5,         _maxListeners: undefined,         output: [],         outputEncodings: [],         outputCallbacks: [],         outputSize: 0,         writable: true,         _last: true,         chunkedEncoding: false,         shouldKeepAlive: false,         useChunkedEncodingByDefault: false,         sendDate: false,         _removedHeader: {},         _contentLength: 0,         _hasBody: true,         _trailer: '',         finished: true,         _headerSent: true,         socket: [Circular],         connection: [Circular],         _header: 'GET /3.0.0//3.0-last-rst HTTP/1.1\r\nHost: docs.opencv.org\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36\r\nReferer: http://docs.opencv.org/3.0.0/d9/df8/tutorial_root.html\r\nAccept-Encoding: gzip, deflate\r\nConnection: close\r\n\r\n',         _headers: [Object],         _headerNames: [Object],         _onPendingData: null,         agent: [Object],         socketPath: undefined,         method: 'GET',         path: '/3.0.0//3.0-last-rst',         timeoutCb: [Function: emitTimeout],         parser: null,         res: [Circular] },      _idleTimeout: -1,      _idleNext: null,      _idlePrev: null,      _idleStart: 4136,      read: [Function],      _consuming: true,      write: [Function: writeAfterFIN] },   connection:    Socket {      _connecting: false,      _hadError: false,      _handle: null,      _parent: null,      _host: 'docs.opencv.org',      _readableState:       ReadableState {         objectMode: false,         highWaterMark: 16384,         buffer: [],         length: 0,         pipes: null,         pipesCount: 0,         flowing: true,         ended: true,         endEmitted: true,         reading: false,         sync: false,         needReadable: false,         emittedReadable: false,         readableListening: false,         defaultEncoding: 'utf8',         ranOut: false,         awaitDrain: 0,         readingMore: false,         decoder: null,         encoding: null,         resumeScheduled: false },      readable: false,      domain: null,      _events:       { end: [Object],         finish: [Function: onSocketFinish],         _socketEnd: [Function: onSocketEnd],         free: [Function: onFree],         close: [Object],         agentRemove: [Function: onRemove],         drain: [Function: ondrain],         error: [Object],         data: [Function: socketOnData],         timeout: [Object] },      _eventsCount: 10,      _maxListeners: 0,      _writableState:       WritableState {         objectMode: false,         highWaterMark: 16384,         needDrain: false,         ending: true,         ended: true,         finished: true,         decodeStrings: false,         defaultEncoding: 'utf8',         length: 0,         writing: false,         corked: 0,         sync: false,         bufferProcessing: false,         onwrite: [Function],         writecb: null,         writelen: 0,         bufferedRequest: null,         lastBufferedRequest: null,         pendingcb: 0,         prefinished: true,         errorEmitted: false },      writable: false,      allowHalfOpen: false,      destroyed: true,      bytesRead: 383,      _bytesDispatched: 292,      _sockname: null,      _pendingData: null,      _pendingEncoding: '',      parser: null,      _httpMessage:       ClientRequest {         domain: null,         _events: [Object],         _eventsCount: 5,         _maxListeners: undefined,         output: [],         outputEncodings: [],         outputCallbacks: [],         outputSize: 0,         writable: true,         _last: true,         chunkedEncoding: false,         shouldKeepAlive: false,         useChunkedEncodingByDefault: false,         sendDate: false,         _removedHeader: {},         _contentLength: 0,         _hasBody: true,         _trailer: '',         finished: true,         _headerSent: true,         socket: [Circular],         connection: [Circular],         _header: 'GET /3.0.0//3.0-last-rst HTTP/1.1\r\nHost: docs.opencv.org\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36\r\nReferer: http://docs.opencv.org/3.0.0/d9/df8/tutorial_root.html\r\nAccept-Encoding: gzip, deflate\r\nConnection: close\r\n\r\n',         _headers: [Object],         _headerNames: [Object],         _onPendingData: null,         agent: [Object],         socketPath: undefined,         method: 'GET',         path: '/3.0.0//3.0-last-rst',         timeoutCb: [Function: emitTimeout],         parser: null,         res: [Circular] },      _idleTimeout: -1,      _idleNext: null,      _idlePrev: null,      _idleStart: 4136,      read: [Function],      _consuming: true,      write: [Function: writeAfterFIN] },   httpVersionMajor: 1,   httpVersionMinor: 1,   httpVersion: '1.1',   complete: true,   headers:    { server: 'nginx',      date: 'Tue, 10 Nov 2015 09:58:11 GMT',      'content-type': 'text/html; charset=iso-8859-1',      vary: 'Accept-Encoding',      'content-encoding': 'gzip',      connection: 'close' },   rawHeaders:    [ 'Server',      'nginx',      'Date',      'Tue, 10 Nov 2015 09:58:11 GMT',      'Content-Type',      'text/html; charset=iso-8859-1',      'Vary',      'Accept-Encoding',      'Content-Encoding',      'gzip',      'Connection',      'close' ],   trailers: {},   rawTrailers: [],   upgrade: false,   url: '',   method: null,   statusCode: 404,   statusMessage: 'Not Found',   client:    Socket {      _connecting: false,      _hadError: false,      _handle: null,      _parent: null,      _host: 'docs.opencv.org',      _readableState:       ReadableState {         objectMode: false,         highWaterMark: 16384,         buffer: [],         length: 0,         pipes: null,         pipesCount: 0,         flowing: true,         ended: true,         endEmitted: true,         reading: false,         sync: false,         needReadable: false,         emittedReadable: false,         readableListening: false,         defaultEncoding: 'utf8',         ranOut: false,         awaitDrain: 0,         readingMore: false,         decoder: null,         encoding: null,         resumeScheduled: false },      readable: false,      domain: null,      _events:       { end: [Object],         finish: [Function: onSocketFinish],         _socketEnd: [Function: onSocketEnd],         free: [Function: onFree],         close: [Object],         agentRemove: [Function: onRemove],         drain: [Function: ondrain],         error: [Object],         data: [Function: socketOnData],         timeout: [Object] },      _eventsCount: 10,      _maxListeners: 0,      _writableState:       WritableState {         objectMode: false,         highWaterMark: 16384,         needDrain: false,         ending: true,         ended: true,         finished: true,         decodeStrings: false,         defaultEncoding: 'utf8',         length: 0,         writing: false,         corked: 0,         sync: false,         bufferProcessing: false,         onwrite: [Function],         writecb: null,         writelen: 0,         bufferedRequest: null,         lastBufferedRequest: null,         pendingcb: 0,         prefinished: true,         errorEmitted: false },      writable: false,      allowHalfOpen: false,      destroyed: true,      bytesRead: 383,      _bytesDispatched: 292,      _sockname: null,      _pendingData: null,      _pendingEncoding: '',      parser: null,      _httpMessage:       ClientRequest {         domain: null,         _events: [Object],         _eventsCount: 5,         _maxListeners: undefined,         output: [],         outputEncodings: [],         outputCallbacks: [],         outputSize: 0,         writable: true,         _last: true,         chunkedEncoding: false,         shouldKeepAlive: false,         useChunkedEncodingByDefault: false,         sendDate: false,         _removedHeader: {},         _contentLength: 0,         _hasBody: true,         _trailer: '',         finished: true,         _headerSent: true,         socket: [Circular],         connection: [Circular],         _header: 'GET /3.0.0//3.0-last-rst HTTP/1.1\r\nHost: docs.opencv.org\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36\r\nReferer: http://docs.opencv.org/3.0.0/d9/df8/tutorial_root.html\r\nAccept-Encoding: gzip, deflate\r\nConnection: close\r\n\r\n',         _headers: [Object],         _headerNames: [Object],         _onPendingData: null,         agent: [Object],         socketPath: undefined,         method: 'GET',         path: '/3.0.0//3.0-last-rst',         timeoutCb: [Function: emitTimeout],         parser: null,         res: [Circular] },      _idleTimeout: -1,      _idleNext: null,      _idlePrev: null,      _idleStart: 4136,      read: [Function],      _consuming: true,      write: [Function: writeAfterFIN] },   _consuming: true,   _dumped: false,   req:    ClientRequest {      domain: null,      _events:       { socket: [Object],         timeout: [Object],         response: [Function: bound ],         error: [Function: bound ],         drain: [Function] },      _eventsCount: 5,      _maxListeners: undefined,      output: [],      outputEncodings: [],      outputCallbacks: [],      outputSize: 0,      writable: true,      _last: true,      chunkedEncoding: false,      shouldKeepAlive: false,      useChunkedEncodingByDefault: false,      sendDate: false,      _removedHeader: {},      _contentLength: 0,      _hasBody: true,      _trailer: '',      finished: true,      _headerSent: true,      socket:       Socket {         _connecting: false,         _hadError: false,         _handle: null,         _parent: null,         _host: 'docs.opencv.org',         _readableState: [Object],         readable: false,         domain: null,         _events: [Object],         _eventsCount: 10,         _maxListeners: 0,         _writableState: [Object],         writable: false,         allowHalfOpen: false,         destroyed: true,         bytesRead: 383,         _bytesDispatched: 292,         _sockname: null,         _pendingData: null,         _pendingEncoding: '',         parser: null,         _httpMessage: [Circular],         _idleTimeout: -1,         _idleNext: null,         _idlePrev: null,         _idleStart: 4136,         read: [Function],         _consuming: true,         write: [Function: writeAfterFIN] },      connection:       Socket {         _connecting: false,         _hadError: false,         _handle: null,         _parent: null,         _host: 'docs.opencv.org',         _readableState: [Object],         readable: false,         domain: null,         _events: [Object],         _eventsCount: 10,         _maxListeners: 0,         _writableState: [Object],         writable: false,         allowHalfOpen: false,         destroyed: true,         bytesRead: 383,         _bytesDispatched: 292,         _sockname: null,         _pendingData: null,         _pendingEncoding: '',         parser: null,         _httpMessage: [Circular],         _idleTimeout: -1,         _idleNext: null,         _idlePrev: null,         _idleStart: 4136,         read: [Function],         _consuming: true,         write: [Function: writeAfterFIN] },      _header: 'GET /3.0.0//3.0-last-rst HTTP/1.1\r\nHost: docs.opencv.org\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36\r\nReferer: http://docs.opencv.org/3.0.0/d9/df8/tutorial_root.html\r\nAccept-Encoding: gzip, deflate\r\nConnection: close\r\n\r\n',      _headers:       { host: 'docs.opencv.org',         'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36',         referer: 'http://docs.opencv.org/3.0.0/d9/df8/tutorial_root.html',         'accept-encoding': 'gzip, deflate' },      _headerNames:       { host: 'Host',         'user-agent': 'User-Agent',         referer: 'Referer',         'accept-encoding': 'Accept-Encoding' },      _onPendingData: null,      agent:       Agent {         domain: null,         _events: [Object],         _eventsCount: 1,         _maxListeners: undefined,         defaultPort: 80,         protocol: 'http:',         options: [Object],         requests: {},         sockets: [Object],         freeSockets: {},         keepAliveMsecs: 1000,         keepAlive: false,         maxSockets: Infinity,         maxFreeSockets: 256 },      socketPath: undefined,      method: 'GET',      path: '/3.0.0//3.0-last-rst',      timeoutCb: [Function: emitTimeout],      parser: null,      res: [Circular] },   request:    Request {      domain: null,      _events:       { error: [Function: bound ],         complete: [Function: bound ],         pipe: [Function],         end: [Object],         data: [Function] },      _eventsCount: 5,      _maxListeners: undefined,      callback: [Function],      followRedirect: true,      timeout: 30000,      headers:       { Host: 'docs.opencv.org',         'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36',         Referer: 'http://docs.opencv.org/3.0.0/d9/df8/tutorial_root.html',         'Accept-Encoding': 'gzip, deflate' },      encoding: null,      method: 'GET',      uri:       Url {         protocol: 'http:',         slashes: true,         auth: null,         host: 'docs.opencv.org',         port: 80,         hostname: 'docs.opencv.org',         hash: null,         search: null,         query: null,         pathname: '/3.0.0//3.0-last-rst',         path: '/3.0.0//3.0-last-rst',         href: 'http://docs.opencv.org/3.0.0//3.0-last-rst' },      readable: true,      writable: true,      explicitMethod: true,      _qs:       Querystring {         request: [Circular],         lib: [Object],         useQuerystring: undefined,         parseOptions: {},         stringifyOptions: {} },      _auth:       Auth {         request: [Circular],         hasAuth: false,         sentAuth: false,         bearerToken: null,         user: null,         pass: null },      _oauth: OAuth { request: [Circular], params: null },      _multipart:       Multipart {         request: [Circular],         boundary: '03d2fef7-454d-4b17-85f7-74c8639b40e0',         chunked: false,         body: null },      _redirect:       Redirect {         request: [Circular],         followRedirect: true,         followRedirects: true,         followAllRedirects: false,         allowRedirect: [Function],         maxRedirects: 10,         redirects: [],         redirectsFollowed: 0,         removeRefererHeader: false },      _tunnel:       Tunnel {         request: [Circular],         proxyHeaderWhiteList: [Object],         proxyHeaderExclusiveList: [] },      setHeader: [Function],      hasHeader: [Function],      getHeader: [Function],      removeHeader: [Function],      localAddress: undefined,      pool: {},      dests: [],      __isRequestRequest: true,      _callback: [Function: bound ],      proxy: null,      tunnel: undefined,      setHost: false,      originalCookieHeader: undefined,      _jar: RequestJar { _jar: [Object] },      port: 80,      host: 'docs.opencv.org',      path: '/3.0.0//3.0-last-rst',      httpModule:       { IncomingMessage: [Object],         METHODS: [Object],         OutgoingMessage: [Object],         ServerResponse: [Object],         STATUS_CODES: [Object],         Agent: [Object],         globalAgent: [Object],         ClientRequest: [Object],         request: [Function],         get: [Function],         _connectionListener: [Function: connectionListener],         Server: [Object],         createServer: [Function],         Client: [Function: deprecated],         createClient: [Function: deprecated] },      agentClass: { [Function: Agent] super_: [Object], defaultMaxSockets: Infinity },      agent:       Agent {         domain: null,         _events: [Object],         _eventsCount: 1,         _maxListeners: undefined,         defaultPort: 80,         protocol: 'http:',         options: [Object],         requests: {},         sockets: [Object],         freeSockets: {},         keepAliveMsecs: 1000,         keepAlive: false,         maxSockets: Infinity,         maxFreeSockets: 256 },      _started: true,      href: 'http://docs.opencv.org/3.0.0//3.0-last-rst',      req:       ClientRequest {         domain: null,         _events: [Object],         _eventsCount: 5,         _maxListeners: undefined,         output: [],         outputEncodings: [],         outputCallbacks: [],         outputSize: 0,         writable: true,         _last: true,         chunkedEncoding: false,         shouldKeepAlive: false,         useChunkedEncodingByDefault: false,         sendDate: false,         _removedHeader: {},         _contentLength: 0,         _hasBody: true,         _trailer: '',         finished: true,         _headerSent: true,         socket: [Object],         connection: [Object],         _header: 'GET /3.0.0//3.0-last-rst HTTP/1.1\r\nHost: docs.opencv.org\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36\r\nReferer: http://docs.opencv.org/3.0.0/d9/df8/tutorial_root.html\r\nAccept-Encoding: gzip, deflate\r\nConnection: close\r\n\r\n',         _headers: [Object],         _headerNames: [Object],         _onPendingData: null,         agent: [Object],         socketPath: undefined,         method: 'GET',         path: '/3.0.0//3.0-last-rst',         timeoutCb: [Function: emitTimeout],         parser: null,         res: [Circular] },      timeoutTimer: null,      ntick: true,      response: [Circular],      originalHost: 'docs.opencv.org',      originalHostHeaderName: 'Host',      responseContent: [Circular],      _destdata: true,      _ended: true,      _callbackCalled: true },   toJSON: [Function: responseToJSON],   caseless:    Caseless {      dict:       { server: 'nginx',         date: 'Tue, 10 Nov 2015 09:58:11 GMT',         'content-type': 'text/html; charset=iso-8859-1',         vary: 'Accept-Encoding',         'content-encoding': 'gzip',         connection: 'close' } },   read: [Function],   body: <Buffer 1f 8b 08 00 00 00 00 00 00 03 4c 8e cd 0e 82 30 10 84 ef 3c c5 ca 1d 16 95 63 d3 83 fc 44 12 44 62 ea c1 23 a6 35 25 41 8a 6d d1 f8 f6 b6 70 f1 b4 99 ... >,   cookies: {}
今回はaタグのみで、imgタグやlinkタグ、scriptタグをたどっていないのでレイアウトは崩れて画像も表示できていなかった。
ちょっとタイムアウトが気持ち悪いけど、とりあえず再帰的に特定のドメイン以下のページを取得することはできた。
今日の作業

髪の毛切りに行ったりしてたら、今日はこれしかできなかった。。。