cheerioを使ってクローラを作る

Node.js でクローラ

ちょっとクローラが必要になった。相当前にpythonで書いた覚えがあるけれど、今回はちょうどnode.jsの環境が手元にあるのでそれでやる。

jsdom を使うと、jQueryでいろいろできて便利そうなので、jsdomをnpm install しようと試してみた。
が、node-gypというのに依存しているらしく、こいつの動作には「Microsoft Visual Studio C++ 2012 for Windows Desktop (Express version works well)」が必要みたいで、ちょっと面倒そうなのでやめた。

cheerio を採用

調べてみると、cheerioというのでも、同じことが実現できるそうで、これを使うことにした。
あと、同期的に書きたいので、前の記事 で使ったfibrous も使う。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var request = require('request');
var cheerio = require('cheerio');
var fibrous = require('fibrous');
var fs = require('fs');
function sleep(ms, cb){
setTimeout(function(){
cb(null);
}, ms);
}
var requestUrl = 'http://hogehoge';
fibrous.run(function(){
var res = request.sync({url: requestUrl});
$ = cheerio.load(res.body);
$('img').each(function(i){ // 例えば、画像を全部DLする
var src = $(this).attr('src');
request(requestUrl + src).pipe(fs.createWriteStream('download/' + i + '.png')); //適当なファイル名に書き出し
sleep.sync(5000 + Math.random() * 5000); //大量にアクセスいくのもあれなので、適当に時間間隔を設けてみる。
});
});

fibrous で 同期処理

fibrous を使うと コールバックを使わないと書けない非同期処理を同期処理的に書けて、コールバック地獄がきれいに書けて良い。

インストールは npm install fibrous でOK。

これを使うと例えば、 request で url の情報を取得するときは、以下のように書ける。

1
2
3
4
5
6
var request = require('request');
var fibrous = require('fibrous');
fibrous.run(function(){ // fibrous でラップしないといけない
var res = request.sync({url: requestUrl});
console.log(res.body);
});

スリープ的なのも書きやすい

1
2
3
4
5
6
7
8
9
10
function sleep(ms, cb){
setTimeout(function(){
cb(null);
}, ms);
}
fibrous.run(function(){
console.log('sleep');
sleep.sync(1000);
console.log('wake up');
});

削除時のフック delete_post

投稿が削除されたときに、それをフックして処理を行う必要があった。
というのも、その投稿を参照している別の独自のテーブルがあってそれも削除したかったからである。
削除にはいくつかフックがあるが、削除直前にフックできる delete_post を使用する。
完全に削除した後だと、削除する投稿の情報が取れない。

以下のように、add_actionで delete_postを指定する。引数に削除される投稿のpost_idが来るので、get_post でそのidの投稿を取得して処理を行うことができる。

1
2
3
add_action('delete_post', function($post_id){
$deletePost = get_post($post_id);
// do something

Custom Field Template の FILE の バリデーション

Custom Field Templateのバリデーション

非常にニッチな話だけど、Custom Field Templateの FILE のバリデーションのTips。

Custom Field Templateは、グローバル設定の「jQuery バリデーションを使用する」にチェックを入れるとバリデーションを利用することができる。
この状態で、以下のようにclassに jquery-validationで利用できるやつを指定するとバリデーションしてくれる。
この例だと required なので入力が必須ということになる。

[image]
type = file
label=写真
class= required

FILEのバリデーション

問題はここから。
この状態で一度ファイルをアップロードして保存する。
その後、編集をもう一度したとき、requiredが効いてしまい、何かしらのファイルをアップロードしないとバリデーションが通らないのだ。
これは困る。ファイル以外の項目を編集したいのにできないからだ。
仕方ないので、jquery-validateに独自のvalidationを定義することにする。

jquery-validateに独自バリデーションの追加

準備として、functions.phpで js ファイルを読み込むようにして、そちらのjsファイルに記述する。

1
2
3
add_action('admin_head', function(){
echo '<script type="text/javascript" src="'.get_bloginfo('template_directory').'/admin.js"></script>';
});

以下、jsファイル内の記述。今回、独自の定義として requiredFile を定義する。

1
2
3
4
5
6
7
8
9
10
11
12
(function($){
$(function(){
//ファイル用に独自のvalidationを追加
$.validator.addMethod("requiredFile", function(value, element) {
if(value !== '') return true;
//CFT では FILEが保存済みの場合、兄弟要素のhiddenのinputフィールドに値が入力されているので、それをチェックする。
if($(element).siblings('input:eq(0)').val() !== '')return true;
return false;
}, "必須項目です。");
});
})(jQuery);

これで、あとは作った定義のclassをくっつける。

[image]
type = file
label=写真
class= requiredFile

管理画面のいらないものを消す

wordpressの管理画面で使わないものを消したい。個人で使うならいいが、お客さんに納品するときなど、触れてほしくない機能は見せたくないからだ。
機能を止めることによって項目を消すこともできるが、細かいところはcssで消していくしかない。
まず、消す用のcssを読み込む。

1
2
3
4
5
6
//functions.php
function my_admin_head(){
echo '<link rel="stylesheet" type="text/css" href="' .get_bloginfo('template_directory'). '/admin-style.css' . '" />';
}
add_action('admin_head', 'my_admin_head');

functions.phpと同じフォルダに admin-style.css を置いておいて、それを読み込む。get_bloginfoで現在のテンプレートのディレクトリを参照できる。
これで管理ページで共通のcssを読み込めるようになった。

あとはhtmlのidやclassを見て、それをdisplay:none;で消せばOK。

1
2
3
4
/* プレビューボタンを消す*/
#post-preview{
display: none;
}