これからはじめる!Webクローリング技術

ひょんなことからWebクローラーを作ることにになったのでいろいろまとめていきたいと思います。

Webクローラーとは
Googleなどの検索エンジン(キーワードからリンクリストを作るサービス)や、マーケティングの情報収集などに使われる「Web上の情報を収集するプログラム」のことです。
スパイダーとも言われますが厳密には違うとのこと。

Webクローリングを構成するプログラム
リンクを辿ってページをキャッシュする
キャッシュを解析して情報を抽出する
抽出した情報を整理する
整理した情報をHTMLなどで出力する

Webクローラーを作るためには
Webのキャッシュを収集する方法とキャッシュを解析する方法の2つを実現する必要があります。
アウトプット方法は個々の目的によって違うのでまずはこの2要素に絞って勉強していきたいと思います。

気になる本

参考サイト

WindowsでもVMware playerでUbuntuを動かす話(初期設定編)

続くかわからないけどシリーズ化してみる。

長い前置き

前回、Railsなプロジェクトの資産を動かそうとして一部ライブラリがWindowsで死亡状態だったのでスッパリあきらめてVMを使うことの話をしたいと思います。


世の中個人開発者には優しい時代になりました。
PCスペックも向上し、VMであれこれやれるって素敵です。
昔はWindowsだとVirtualPCぐらいしかなかった記憶なんですが、今はMSサーバー機能だったHyper-VがクライアントOSに装備されているくらい一般ユーザーでもVMを使う機会が与えられていると思います。

そこであえて私は「VMware player」で構築したいと思います。
理由なんてない、VMVMwareというイメージが一番強いことです。
少し補足すると今仕事でVMwareをつかってるので深掘りもかねて個人的に使おうと思ったのが理由でもあります。

VMware playerをインストールしよう!

VMware playerのインストールは簡単です。

公式サイトよりインストーラーを拾ってきてインストールするだけです。

https://my.vmware.com/jp/web/vmware/free#desktop_end_user_computing/vmware_player/6_0|PLAYER-601|product_downloads

Windows(32/64bit)用とLinux(32/64bit)用があります。
DevOpsとかを目指しているならGUIのものより「vagrant」とかの方がいいかもしれません。
インストーラーを実行すればインストール完了です。

OSをインストールしよう!

VM環境ができたら次に仮想マシンを作りましょう。
VMware playerを起動すると「新規仮想マシンの作成」というメニューがあるので選択します。

ウィザードが起動し、OSのインストール元を聞かれるので選択します。
今回はLinux環境を作ることが目的なのでフリーなディストリビューションを選びたいと思います。

ぱっと思いついたのはCentOSですが、ちまたで話題になってる「Ubuntu」で作業をす住めてみたいと思います。

日本語有志のサイトより日本語Remixイメージをダウンロードしてください。
http://www.ubuntulinux.jp/

今回私は「64bit版 v13.10」のISOイメージにしました。
なのでVMware側では「インストーラディスクイメージファイル(iso)」でダウンロードしたisoを選択します。


という手順をつらつらと述べてもいいんですが、日が暮れるので世はネット時代、参考になるサイトを紹介してその通り進めてください。
(私はText modeではなくGUI付の無印でやってます)

http://www.aise.ics.saitama-u.ac.jp/~gotoh/VMPlayerIntoWindows7.html

VMに割り当てるリソースはご自身のマシンスペックと相談してください。
当方は以下のホストスペックの上で次のようなゲストリソースを割り当てました。

 CPU: Core2Duo E8400 3.00GHz/2core
 RAM: DDR2 4GB
 OS: Windows7 Pro 64bit
 Storage: SDD120GB、HDD1-500GB、HDD2-2TB、HDD3-3TB

VM上の割り当て

 CPU: 1core(1vCPU)
 RAM: 1GB
 Storage: 50GB

ネットワークは接続を前提としたいのでNATにしています。
その他設定はVMwareに言われたままにしています。
今後問題があれば随時調整する予定です。

といった具合に作成していくと簡易インストールが始まるのでインストール完了を待ちます。
恐らく途中で初期ユーザーの設定を聞かれるので、このときのユーザーとパスワードはちゃんとおぼえておいてください。

ログインから初期設定

あなたのネットワーク環境にもよりますが、ルータでDHCPが有効になっていてネットワークでNATになっていればすでにネット接続できるはずです。
初期ユーザーでログインしてFireFoxが標準で入っているので起動してgoogleにでもアクセスしてみてください。
ネットワークに接続していることを前提に進めていきたいと思います。

rootユーザーのパスワード設定

簡易インストールだとrootユーザーのパスワードがなんか適当に決められているようです。
まず設定しましょう。

sudo su -
passwd

つづく

http://www.oiax.jp/rails/zakkan/rails_3_2_installation_on_ubuntu.html

上記参考サイトのとおり進めていく(rubyは2013/12/07最新のp484を使用)けど某PJのRMagickのgemインストールでこける。
Winの時と同じや!

調べると「ImageMagick」関連が入ってないとこけるようで。。。

Can't install RMagick 2.13.2. Can't find Magick-config

http://qiita.com/yuiseki/items/55bded2e32d07aef23ab

というわけで調べてみるといくつかの記事で "aptitude" を使ってインストールするとのことなので "aptitude" をまずインストールする。

sudo apt-get aptitude

上記で "aptitude" を入れた後、下記をやる。

sudo aptitude install imagemagick libimagemagick libmagickcore libmagickcore-dev libmagickwand-dev
sudo gem install rmagick

最終行のgemは個別にやってもいいし、Gemfileがあるならbundleしてもよい。

これで無事Rubyの環境はできた。
あとはDBなどの準備をしてRailsサーバーを起動。

rake db:migrate
rails s

WindowsでRailsなアプリ実行環境でハマったこと(あきらめ)

Windows環境でRuby on Railsの実行環境を構築しているときにハマったのでその記録を。

1.DevKitがちゃんとインストールされていない

いれたつもりがパスが通っていなかった。
"C:\dev\RubyDevKit" 配下に展開していたので以下のPathを追加。

  • C:\dev\RubyDevKit\bin
  • C:\dev\RubyDevKit\mingw\bin

2.libv8のインストールでこける

bundle install

を実行したら

Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

C:/Ruby193/bin/ruby.exe extconf.rb
creating Makefile
以下略

とエラーが出て進まない。
どうやらWindowsでは "therubyracer" のインストールまわりでうまくいかないらしい。
ということで手動でインストールを試みたけどダメ。

gem install libv8 -v '3.11.8.13'

これはダメ

どうやら手動でWindows用のtherubyracerをいれないとダメらしい。
参考:http://gagapi.hatenablog.jp/entry/2013/05/15/190651

ということで下記GitHubよりgemとdll2個の計3つをダウンロードします。(開いてRawボタンでダウンロード開始)
https://github.com/hiranpeiris/therubyracer_for_windows

dll2つはパスの通っている場所(自分はRubyインストール先のbin配下にしました)へコピー。

gemは仕方ないのでローカルgemを使うようにunpackしてGemfileに手を入れます。

gem unpack therubyracer-0.11.0beta1-x86-mingw32.gem

アプリrootで展開

#gem 'therubyracer'
gem 'therubyracer', :path => 'therubyracer-0.11.0beta1-x86-mingw32'

パス指定でgemを見るように変更

これで進むようになったけど第三の刺客が現る。
"RMagick" でこける。同じくWindowsだとダメということなので同様にWindows用のローカルgemを用意します。

Installing rmagick (2.13.2)
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

C:/Ruby193/bin/ruby.exe extconf.rb
checking for Ruby version >= 1.8.5... yes

http://rubyforge.org/frs/?group_id=12

gem unpack rmagick-2.13.2.gem

アプリrootで展開

#gem 'rmagick'
gem 'rmagick', :path => 'rmagick-2.13.2'

Path指定

次は "ruby-debug-base19 (0.11.25)" でエラー。

Windowsでやるなってことか・・・。

つづく

つづき 2013/12/04

結論からいうと、Windowsあきらめました。
RailsそのものはWindowsでもナンの苦労もなく利用できるんだけど、今回参加するプロジェクトの環境がMacユーザーのモトで作られたようでWindowsでは難のあるライブラリが多かったようで。

というわけで次回エントリにてVM上でUbuntuを動かす話にてこの話題にケリをつけたいと思います。

Nexus7(2012)+TWRPv2.6.0.0でJWR66V→JWR66Yにアップデートできないとき

数ヶ月間謎のままだけどようやく解決方法をみつけた。

TWRP v2.6.0.0 で Nexus7 の Android 4.3 JWR66V→JWR66Y のアップデートが失敗する件について
http://d.hatena.ne.jp/xr0038/touch/20130829/1377771183

「Nexus7 update 4.3 twrp」とかでぐぐってもRoot化の方法!みたいなのしか出てこなくて困った。
「twrp update」という線でぐぐったらビンゴ上記記事を見つけました。
手順は記載済みですが少し補足しながらまとめます。

発生事象
TWRP導入済みのNexus7(2012)でビルド番号JWR66V(Android4.3)からJWR66Y(同)のアップデートをするため
通知バーから再起動し、TWRPからInstall→/cache/xxxx.zipを選んでも途中でエラーになる。

原因
install時に使用するシェル(/system/etc/install-recovery.sh)のファイル属性(immutable)に問題がある。

解決策
問題のシェルのファイル属性を変更する。

手順
1.Nexus7を再起動し、TWRPを起動します。
*1
*2

2.TWRPホームからMountを選び、Systemをマウントする(☒にする)
*3

3.TWRPホームからAdvancedを選び、Terminal Commandを選ぶ

4.ターミナルの開始ディレクトリを選択しろと言われるので/system/etcを選択し、Selectを押す

5.下記のコマンドを実行する

chattr -i install-recovery.sh

*4

6.TWRPホームからInstallを選び、/cache配下にある長いファイル名のZip(アップデートファイル)を選択する
*5

7.Swipe to Confirm Flashをスライドして書き込みを始めるとほどなくしてインストールが終わる

8.Successfulと表示されていることを確認し、Reboot Systemで再起動する
*6

9.ビルド番号が上がっていることを確認


うーむ、助かった。

*1:通知バーから更新のインストールを選べば自動的にTWRPが起動

*2:もしくは電源投入時にボリュームダウンボタンを押しながら電源ボタン長押しで電源投入→ブートローダーでRecovery modeで起動

*3:選んだらTWRPホームへバックキーで戻る

*4:コマンドを打ったらTWRPホームへバックキーx2で戻る

*5:XXXXXXXXXX.signed-nakasi-JWR66Y-from-JWR66V.XXX.zip みたいなの

*6:再rootする場合はDo Not Fixではなくて下部のSwipeをスライド

VBAでUTF-8(BOMなし)でファイル保存する方法

VBAUTF-8でのファイルを扱うためにADODB.Streamを使用する際に、BOMなしで保存する場合に必要な処理。

前提条件

  • Microsoft Office (Excel 2010)
    • 2010以外でも同じ
  • 処理簡略化のため参照設定で「Microsoft AxtiveX Data Object 6.1 Library」を追加していること

処理内容

ADODB.Streamを使ってデータを追加するところまでは同じ。

Dim myStream As ADODB.Stream
Set myStream = New ADODB.Stream

myStream.Type = adTypeText
myStream.Charset = "UTF-8"
myStream.Open

myStream.WriteText "ほげほげ", adWriteLine
myStream.WriteText "もげもげ", adWriteLine
myStream.WriteText "そげそげ", adWriteLine

ファイルを保存する直前にBOMを削除する処理を追加。

Dim byteData() As Byte
myStream.Position = 0
myStream.Type = adTypeBinary
myStream.Position = 3
byteData = myStream.Read
myStream.Close
myStream.Open
myStream.Write byteData

簡単に仕組みを説明すると次のようなイメージ。

  1. バイナリデータを保持するバイト配列を用意する
  2. ストリームのカーソル位置を0バイト目(先頭)にする
  3. ストリームのデータタイプをバイナリに変更する
  4. ストリームのカーソル位置を3バイト目に変更する(BOMは先頭3バイトのデータなのでそれを飛ばす)
  5. 現在のカーソル位置以降のデータをすべてバイト配列に保持する
  6. 一旦ストリームを閉じる
  7. 再度ストリームを開く
  8. BOMを読み飛ばしたバイトデータをストリームに書き込む

あとは保存するなり好きにすればOK

myStream.SaveToFile "C:\Temp\myStream.dat", adSaveCreateOverWrite

SaveToFileの第2パラメーターは上書きするかどうかの指定。

adSaveCreateOverWrite 上書き保存(強制上書き)
adSaveCreateNotExist ファイルがなければ作成

上書き確認は別途Dir関数等でファイル有無をチェックしてください。

なお、adXXXX系の定数はVBEditorで参照設定をしないと調べるのもだるいので
参照設定をしておくことをオススメします。
(他の実行環境でも追加する必要があるかは別途検証します)

jQueryでAjaxしたXMLデータで.html()するとIEでエラー

jQueryで次のような処理を書くとIEでハマるお話。

前提

処理内容

Ajaxを用いてXMLファイルを読み込んだあと、そのXMLデータの中身を .html() で取り出す。

JavaScript
var conf = null;
$.ajax({{
    url: "./data.xml",
    type: "GET",
    dataType: "xml",
    cache: false,
    async: false,
    timeout: 10000,
    success: function(data, textStatus, xhr) {
        conf = $(data).find("conf").html();
    }
});
XML(data.xml
<conf>
    <span class="sample">サンプル</span>
</conf>

FireFoxだとこれで動くんだけどIEだと以下のようなエラーが出てしまう。

SCRIPT5007: プロパティ 'replace' の値を取得できません: オブジェクトは Null または未定義です。

理由はjQueryが .html() で使用する innerHTML が定義されていないためである。
というのもAjaxのデータタイプ(dataType)を"XML"にしているのが原因なので
ちゃんとinnerHTMLが扱えるように"HTML"としてやる必要があるようだ。

JavaScript(修正後)
var conf = null;
$.ajax({{
    url: "./data.xml",
    type: "GET",
    dataType: "html",
    cache: false,
    async: false,
    timeout: 10000,
    success: function(data, textStatus, xhr) {
        conf = $(data).find("conf").html();
    }
});

$.ajaxのdataTypeによるオブジェクトの違いとかをちゃんと理解していないとこうなる。
あらためて勉強しようと思ったのであった。

更新再開

長らく放置していましたが情報発信の重要性に気づき、更新を再開することにしました。
整理された優良な情報を発信できるかはわかりませんが、ぐぐって調べることができるのは
様々な情報を発信している方々のおかげですので、私もそっち側の人間になりたいと思います。