Ruby+Mechanize : Seesaaブログのアクセス解析データをDBに更新する


  概要

Seesaa のブログは複数作成できるのですが、それぞれのアクセス解析をチェックするのは、大変な
作業になります。そこで、Ruby+Mechanize で、直接アクセス解析のページを取得して、必要なデータ
を取り出して DB に更新します。
( Ruby からの DB 更新は行わず、慣れた PHP で作成して Ruby から呼び出すようにしています。 )

定期呼び出しは、CRON を使い、5分毎に呼び出していますが、DBにカウンタを持たして、一回の呼び出し
に対して、二つのブログを呼び出すようにしています。

メインは、Seesaa ですが、さくらのブログとココログも呼び出しています。但し、Seesaa に関しては、ただ
アクセス数を取得するのでは無く、OS の解析ページを使って、「不明」となっているものを差し引いて取り出し
ています。
「不明」は、通常一ユーザのアクセスでは無く、各サイトのプログラムであると考えられるからです。

  Ruby のソースコード




Seesaa は SHIFT_JIS で、自分の環境のDB が EUC なので、Ruby も EUC で書いていますが、
「不明」という文字を検索する為にバイナリで検索しています。
そのため、Ruby の内部キャラクタセットは設定していません。
( このような環境では、-Ke としてもうまく行きませんでしたので )

seesaaAction メソッドの第一引数は、ブログのID です。
( 名称はデバッグ用なので無くてもかまいません。 )

Ruby は変数の頭に $ が付くと、グローバル変数になります。

"0".to_i や 0.to_s で変換してから計算または結合を行わないとエラーとなります。
( 特に文字列結合で、暗黙の変換はありません )

正規表現時のみキャラクタセットを指定する方法が ( /文字列/e 等 ) ありますが、
あまり、信頼できそうに無いのでバイナリで検索したほうがいいと思います

※ ブログ単位のデバッグは exit で Ruby を終わらせて、一つ一つ行いました。

#!/usr/local/bin/ruby
# 内部キャラクタセットを変更したい場合は、上記の ruby に引数を -Ke のように追加する
# 正しく設定されたかどうかは、print $KCODE で確認
#http://doc.okkez.net/static/187/method/Kernel/v/KCODE.html
print "Content-type: text/html; Charset=euc-jp\n\n"

# **********************************************************
# 環境設定
# **********************************************************
$stderr = $stdout

require "cgi"
cgi = CGI.new

require 'uri'

ENV['GEM_HOME']="/home/lightbox/gems"
$LOAD_PATH.push('/home/lightbox/lib')

require 'rubygems'
require 'mechanize'

# グローバル変数( オブジェクト )
$agent = WWW::Mechanize.new

$agent.open_timeout = 600
$agent.read_timeout = 600

# **********************************************************
# DB よりカウンタを取得
# **********************************************************
page = $agent.get("http://winofsql.jp/ruby/countup.php")
$cnt = (page.body).to_i
$cnt_t = 5

print "更新カウンタ対象値 : " + $cnt.to_s + " | グループカウンタ : " + ($cnt % $cnt_t).to_s + "<br>\n"

# **********************************************************
# ログイン関数
# agent は引数渡し
# **********************************************************
def seesaaLogin(agent) 
	page = agent.get("https://ssl.seesaa.jp/www/pages/welcome/login/input")
	form = page.forms.first
	form["member__email"] = ""
	form["member__password"] = ""
	form.submit
end

def niftyLogin(agent) 
	page = agent.get("https://login.nifty.com/service/login")
	form = page.forms.first
	form["username"] = ''
	form["password"] = ''
	page = form.submit
end

def sakuraLogin(agent) 

#	page = agent.get("http://winofsql.jp/ruby/sakura_blog.htm")
# shift_jis ページなのに meta で EUC-JP になっているので解析できずに
# オブジェクトを取得できていない
	page = agent.get("https://secure.sakura.ad.jp/rscontrol/")
	form = page.forms.first
	form["domain"] = ''
	form["password"] = ''
	page = form.submit
#fp = open("./log_01.txt", "w") 
#fp.puts(page.body) 
#fp.close 
	page = agent.get('https://secure.sakura.ad.jp/rscontrol/rs/blog')
end

# **********************************************************
# Seesaa 処理関数
# $agent はグローバル変数
# **********************************************************
def seesaaAction(blog_id,blog_nm,opt) 


	# ブログ選択
	page = $agent.get($seesaa_select_blog + blog_id)
	# アクセス解析デフォルトページ( ページ別 )
	page = $agent.get($seesaa_access_default)

	# 合計の 訪問者数 と ページビュー を取得する正規表現( m は "." が改行にマッチ )
	/log\-total\-text.+log\-total\-num">.+?>(.+?)<.+log\-total\-num">.+?>(.+?)</m =~ page.body
	# Ruby 側確認用表示
	$ucnt = $1
	$vcnt = $2

	if opt == '1' then
		# 実際のアクセス数の計算用
		page = $agent.get($seesaa_access_os)
		# SHIFT_JIS で不明の先頭コードである \x95 を処理
		/log\-total\-num">(.+?)<.+?\x95.+?align="right".+?nbsp;(.+?)</m =~ page.body

		$realcnt = ($1.to_i-$2.to_i).to_s
	else
		$realcnt = 0.to_s
	end

	print blog_nm + "   " +  $ucnt + "/" + $vcnt + "<br>\n"
	print "realaccess : " +  $realcnt + "<br>\n"

	# DB 更新用 php 呼び出し
	$agent.get($seesaa_dbupdate+blog_id+'&ucnt='+$ucnt+'&vcnt='+$vcnt+'&realcnt='+$realcnt)


end

# **********************************************************
# Seesaa 定数
# **********************************************************
$seesaa_select_blog	= "http://blog.seesaa.jp/pages/my/blog/home/?blog_id="
$seesaa_access_default	= "http://blog.seesaa.jp/pages/my/blog/access_log/report/index?log_type=file"
$seesaa_access_os	= "http://blog.seesaa.jp/pages/my/blog/access_log/report/index?log_type=os"
$seesaa_dbupdate	= "http://.../seesaa_create_log.php?blog_id="


# デバッグ用
#exit


# **********************************************************
# グループ( 1 )
# **********************************************************
if ($cnt % $cnt_t) == 0 then

	# ログイン
	seesaaLogin($agent)

	seesaaAction('9999999','logical error','1')
	seesaaAction('9999999','ARGUS','0')

end


# **********************************************************
# グループ( 2 )
# **********************************************************
if ($cnt % $cnt_t) == 1 then

	# ログイン
	seesaaLogin($agent)

	seesaaAction('9999999','カスタムパレットツール','1')
	seesaaAction('9999999','画狼','1')

end

# **********************************************************
# グループ( 3 )
# **********************************************************
if ($cnt % $cnt_t) == 2 then

	# ログイン
	seesaaLogin($agent)

	seesaaAction('9999999','琴線に触れる','1')
	seesaaAction('9999999','アプリケーション作成','1')

end


# **********************************************************
# グループ( 4 )
# **********************************************************
if ($cnt % $cnt_t) == 3 then

	niftyLogin($agent)
# アクセス解析ページへアクセス
	page = $agent.get('http://app.cocolog-nifty.com/t/app/control/stats')
	page = $agent.get('http://app.cocolog-nifty.com/t/app/control/stats?nwsThough=1')

	/class="tt" align="right">(\d+?)<\/td>.+class="tt" align="right">(\d+?)<\/td>/m =~ page.body 
	access_num = ($1).to_s
	visit_num = ($2).to_s
	if access_num != '' then
		print access_num + "," + visit_num  + "<br>\n"
	else
		print "集計データがありません<br>\n"
	end 

	$agent.get('http://.../seesaa_create_log.php?blog_id=600886&ucnt='+visit_num+'&vcnt='+access_num+'&title='+URI.escape('ココログ'))

	sakuraLogin($agent)
# 対象ブログのページ
	page = $agent.get('http://blog.sakura.ne.jp/pages/my/blog/home/?blog_id=13678')
	page = $agent.get('http://blog.sakura.ne.jp/pages/my/blog/access_log/report/index?log_type=file&id=13678')

	/log\-total\-text.+log\-total\-num">.+?>(.+?)<.+log\-total\-num">.+?>(.+?)</m =~ page.body
	print "ARGUS(さくら)   " +  $1 + "/" + $2 + "\n"
	$agent.get('http://.../seesaa_create_log.php?blog_id=13678&ucnt='+$1+'&vcnt='+$2+'&title='+URI.escape('ARGUS(さくら)'))

end

# **********************************************************
# グループ( 5 )
# **********************************************************
if ($cnt % $cnt_t) == 4 then

	sakuraLogin($agent)
# 対象ブログのページ
	page = $agent.get('http://blog.sakura.ne.jp/pages/my/blog/home/?blog_id=7364')
	page = $agent.get('http://blog.sakura.ne.jp/pages/my/blog/access_log/report/index?log_type=file&id=7364')

	/log\-total\-text.+log\-total\-num">.+?>(.+?)<.+log\-total\-num">.+?>(.+?)</m =~ page.body
	print "SQLの窓(さくら)   " +  $1 + "/" + $2 + "<br>\n"
	$agent.get('http://.../seesaa_create_log.php?blog_id=7364&ucnt='+$1+'&vcnt='+$2+'&title='+URI.escape('SQLの窓(さくら)'))


end


=begin
print "</pre>"

print "最新アクセスリスト一覧"
=end

print "<br>\nOK"



  PHP : カウンタコントロール

カウンタ表示 は、カウンタを集計する列を持っておれば何でもかまいません
( このテーブルはアクセスカウンタ用で、ページを "_cron" で登録しています

<?
header( "Content-Type: text/html; Charset=euc-jp" );
header( "pragma: no-cache" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "Cache-control: no-cache" );

foreach( $_GET as $Key => $Value ) {
	$_POST[$Key] = $_GET[$Key];
}
foreach( $_POST as $Key => $Value ) {
	$_POST[$Key] = str_replace("\\\\", "\\", $Value );
	$_POST[$Key] = str_replace("\\'", "'", $_POST[$Key] );
	$_POST[$Key] = str_replace("\\\"", "\"", $_POST[$Key] );
}

mb_language( "ja" );
mb_internal_encoding("EUC-JP");

$Server = '';
$DbName = '';
$User = '';
$Password = '';

// 接続解除
$Connect = @mysql_connect( $Server, $User, $Password );
if ( !$Connect ) {
	print "接続エラーです";
	exit();
}

// DB選択
mysql_select_db( $DbName, $Connect );

// クエリ
$query = "update `カウンタ表示` set `カウンタ` = `カウンタ` + 1";
$query .= " where ページ = '_cron'";
mysql_query($query, $Connect);

$query = "select `カウンタ` from `カウンタ表示`";
$query .= " where ページ = '_cron'";
$result = mysql_query($query, $Connect);
$row = mysql_fetch_row($result);

print $row[0];

if ( ($row[0]+0) > 1000 ) {
	$query = "update `カウンタ表示` set `カウンタ` = 0";
	$query .= " where ページ = '_cron'";
	mysql_query($query, $Connect);
}

// メモリを開放ですが、通常は必要ありません
mysql_free_result($result);

// 接続解除
mysql_close($Connect);

?>


  PHP : DB 更新

テーブルには、「現在の値」「一つ前の値」「前日の値」がありますが、「前日の値」は厳密では
ありません。最後のサイクルに1時間かかったとしたら、その期間に増加した値は無視される仕様です。
( だいたい解ればいいので )

<?
// ***********************************************
// 環境設定
// ***********************************************
header( "Content-Type: text/html; Charset=euc-jp" );
header( "pragma: no-cache" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "Cache-control: no-cache" );

foreach( $_GET as $Key => $Value ) {
	$_POST[$Key] = $_GET[$Key];
}
foreach( $_POST as $Key => $Value ) {
	$_POST[$Key] = str_replace("\\\\", "\\", $Value );
	$_POST[$Key] = str_replace("\\'", "'", $_POST[$Key] );
	$_POST[$Key] = str_replace("\\\"", "\"", $_POST[$Key] );
}

mb_language( "ja" );
mb_internal_encoding("EUC-JP");

$Server = '';
$DbName = '';
$User = '';
$Password = '';

// ***********************************************
// 接続
// ***********************************************
$Connect = @mysql_connect( $Server, $User, $Password );
if ( !$Connect ) {
	print "接続エラーです";
	exit();
}

// ***********************************************
// DB選択
// ***********************************************
mysql_select_db( $DbName, $Connect );

// ***********************************************
// seesaa_log のフォーマット
// blog_id
// ucnt
// vcnt
// rcnt

// title varchar(255)
// upd datetime

// p_ucnt
// p_vcnt
// p_rcnt

// b_ucnt
// b_vcnt
// b_rcnt
// ***********************************************

// *************************************************************
// 前回の更新と今回で日付が変わっていたら、テーブル全体の
// 前回の値を b_ へ更新する
// 
// blog_id = 0 は前回の更新したタイムスタンプ用 なので
// 最初は手動で作成して、その日の日付を設定しておく
// *************************************************************
$query = "select * from  seesaa_log where blog_id = 0";
$result = mysql_query($query, $Connect);
$row = mysql_fetch_array($result);
$dt = substr( $row['upd'], 0, 10 );
$dt = str_replace( "-", "", $dt );
//file_put_contents( "_seesaa_log".".log", $dt );

if ( $dt < date("Ymd") ) {
	$query = "update `seesaa_log` ";
	$query .= "set b_ucnt = ucnt, b_vcnt = vcnt,b_rcnt = rcnt, upd = NOW()";
	mysql_query($query, $Connect);
}

// *************************************************************
// 今回の更新と、一つ前( p_ ) の更新
// *************************************************************
$query = "update `seesaa_log` ";
$query .= "set p_ucnt = ucnt, p_vcnt = vcnt,p_rcnt = rcnt";

// タイトルを設定しているのは、Seesaa 以外なので、realcnt を 0 にする
if ( $_POST['title'] != '' ) {
	$query .= " ,title = '{$_POST['title']}'";
	$_POST['realcnt'] = "0";
}
$query .= ",ucnt = {$_POST['ucnt']}, vcnt = {$_POST['vcnt']}, rcnt = {$_POST['realcnt']},upd = NOW()";
$query .= " where blog_id = {$_POST['blog_id']}";
mysql_query($query, $Connect);

// 更新対象行が無い場合は、新規に作成する
if ( mysql_affected_rows($Connect) == 0 ) {
	if ( $_POST['title'] != '' ) {
		$query = "insert into `seesaa_log` (blog_id,ucnt,vcnt,rcnt,title,upd) ";
		$query .= "values({$_POST['blog_id']},{$_POST['ucnt']},{$_POST['vcnt']},0,'{$_POST['title']}',NOW())";
	}
	else {
		$query = "insert into `seesaa_log` (blog_id,ucnt,vcnt,rcnt,upd) ";
		$query .= "insert into `values({$_POST['blog_id']},{$_POST['ucnt']},{$_POST['vcnt']},{$_POST['realcnt']},NOW())";
	}
	mysql_query($query, $Connect);
}

// 接続解除
mysql_close($Connect);

?>
OK





yahoo  google  MSDN  MSDN(us)  WinFAQ  Win Howto  tohoho  ie_DHTML  vector  wdic  辞書  天気 


[sh_web]
CCBot/2.0 (http://commoncrawl.org/faq/)
17/10/19 23:31:11
InfoBoard Version 1.00 : Language=Perl

BatchHelper COMprog CommonSpec Cprog CprogBase CprogSAMPLE CprogSTD CprogSTD2 CprogWinsock Cygwin GameScript HTML HTMLcss InstallShield InstallShieldFunc JScript JScriptSAMPLE Jsfuncs LLINK OldProg OracleGold OracleSilver PRO PRObrowser PROc PROconePOINT PROcontrol PROftpclient PROjscript PROmailer PROperl PROperlCHAT PROphp PROphpLesson PROphpLesson2 PROphpLesson3 PROphpfunction PROphpfunctionArray PROphpfunctionMisc PROphpfunctionString PROsql PROvb PROvbFunction PROvbString PROvbdbmtn PROvbonepoint PROwebapp PROwin1POINT PROwinSYSTEM PROwinYOROZU PROwindows ProjectBoard RealPHP ScriptAPP ScriptMaster VBRealtime Vsfuncs a1root access accreq adsi ajax amazon argus asp aspSample aspVarious aspdotnet aw2kinst cappvariety centura ckeyword classStyle cmaterial cmbin cmdbapp cmenum cmlang cmlistbox cmstd cmstdseed cmtxt cs daz3d db dbCommon dbaccess dnettool dos download flex2 flex3 flex4 framemtn framereq freeWorld freesoft gimp ginpro giodownload google hdml home hta htmlDom ie9svg install java javaSwing javascript jetsql jquery jsp jspTest jspVarious lightbox listasp listmsapi listmsie listmsiis listmsnt listmspatch listmsscript listmsvb listmsvc memo ms msde mysql netbeans oraPlsql oracle oracleWiper oraclehelper orafunc other panoramio pear perl personal pgdojo pgdojo_cal pgdojo_holiday pgdojo_idx pgdojo_ref pgdojo_req php phpVarious phpguide plsql postgres ps r205 realC realwebapp regex rgaki ruby rule sboard sc scprint scquest sdb sdbquest seesaa setup sh_Imagick sh_canvas sh_dotnet sh_google sh_tool sh_web shadowbox shgm shjquery shvbs shweb sjscript skadai skywalker smalltech sperl sqlq src systemdoc tcpip tegaki three toolbox twitter typeface usb useXML vb vbdb vbsfunc vbsguide vbsrc vpc wcsignup webanymind webappgen webclass webparts webtool webwsh win8 winofsql wmi work wp youtube