2011年6月29日水曜日

anemoneの使用時のメモリ問題解決法

anemoneを使ってページ全体をクロールしようとするとメモリをやたら食います。
どうやらこれはデータをメモリにキャッシュしているかららしい。

というわけで、キャッシュをmongodbに保存するようにして、解決する。

まずはyumリポジトリを追加
# sudo vim /etc/yum.repos.d/10gen-mongodb.repo

name=10gen Repository
baseurl=http://downloads.mongodb.org/distros/centos/5.4/os/x86_64/
gpgcheck=0
enabled=0
これを書きこんで保存。

で、必要なものをインストール。
# sudo yum install mongo-10gen mongo-10gen-server
# sudo gem install bson_ext SystemTimer

で、起動する。
# sudo /etc/init.d/mongod start

mongodbを使うように書きなおす。

require 'rubygems'
require 'anemone'

# mongodbを使うのとquery_stringsは取得しないように設定。またアクセス間隔を2秒にする。
  opts = {
   :storage => Anemone::Storage.MongoDB,
   :skip_query_strings => true,
   :delay => 2,
  }

Anemone.crawl("http://example.com/", opts) do |anemone|
 anemone.on_every_page do |page|
   puts page.url
  end
 end
end

参考;
http://work.blog.eggplant.org.uk/2011/03/web-anemone.html

2011年6月28日火曜日

anemoneを使って、サイト内のURLをすべて取得する。

anemoneさん便利すぎでしょ・・・

#sudo gem install anemone


require 'rubygems'
require 'anemone'

Anemone.crawl("http://example.com/") do |anemone|
 anemone.on_every_page do |page|
   puts page.url
  end
 end
end

2011年6月27日月曜日

face.comのAPIをrubyのライブラリを使って遊んでみる

face.comのAPIを使って、flickrのinterestingに掲載された画像のうち、顔の画像だけ選択し、顔の部分には笑い男の画像をつけてみます。
なお笑い男の画像は自分で用意してください。
あとAPIはhttp://developers.face.com/で簡単に登録できます。
画像の修正にはrmagickを使ってますので、昨日の記事を参考にインストールしといてください。

rubyにface.comを扱えるライブラリがあるので、インストール
#sudo gem install face

以下のコードに、api部分を入力する、

require 'rubygems'
require 'face'
require 'open-uri'
require 'nokogiri'
require 'RMagick'
include Magick


client = Face.get_client(:api_key => 'api_key', :api_secret => 'api_secret')
url = "http://www.flickr.com/explore/interesting/2011/06/"
laughingman_image = Magick::Image.read('laughingman.gif').first
url_list = Array.new
img_url_list = Array.new

#flickrからURLを取得
data = open( url )
doc = Nokogiri::HTML( data )

doc.css('a').each do |f|
 begin
  if /\/explore\/interesting\/(\d+)\/(\d+)\/(\d+)\// =~ f.attribute('href').value
   url_list << f.attribute('href').value
  end
 rescue
  next
 end 
end

puts 'flickrの日付URL取得完了'

url_list.each do |f|
 img_url = URI.join(url, f)
 img_data = open( img_url )
 img_data = Nokogiri::HTML( img_data )
 img_data.css('img.pc_img').each do |img|
  img_url_list << img.attribute('src').value
 end
end

puts 'imgの個別URL取得完了'

#face.comのAPIにURLをわたして画像を認識させ、顔があれば、顔の部分に笑い男を貼り付ける。
img_url_list.each do |img_url|
 data = client.faces_detect(:urls => img_url )
 filename = File.basename( img_url )

 photo = data['photos']
 photo.each do |photo|
  if photo['tags'].first #tagsは配列形式で帰ってくるので、firstを付けてます。
   image = Magick::Image.read( img_url ).first #RMagickで読み込んだファイルも配列なので、firstを付ける。
   begin
    photo['tags'].each do |tag|
     width = photo['width'] * (tag['width'] / 100)
     height = photo['height'] * (tag['height'] / 100)
     x = photo['width'] * (tag['center']['x'] / 100)
     y = photo['height'] * (tag['center']['y'] / 100)
     overlay_image = laughingman_image.resize_to_fit(width, height)
     image.composite!(overlay_image, x-width/2, y-height/2, OverCompositeOp)
    end
    image.write("./img/#{filename}")
    puts filename
   rescue
    puts '処理に失敗しました。'
    next
   end
  end
 end
end

参考;http://labs.appshelf.info/category/face-com/

2011年6月26日日曜日

flickrから人気の画像を取得し、rmagickを使って、サムネイルとしてリサイズする

flickrにはその日人気になった写真みたいなのをだしているので、その画像を取得し、150×150の画像にリサイズするプログラムです。
写真のサイズはそれぞれバラバラなので、大きい方の辺を150にし、足りない部分は背景を黒にしています。

一応サーバ上で動かすこと前提としています。

まずはサーバにImagemagickとRmagick、必要なライブラリをインストール

#画像編集に必要なライブラリをインストール(先にいれといたほうがいいらしいです)
# sudo yum install libjpeg-devel libpng-devel


#Image magickのインストール
# wget ftp://ftp.kddlabs.co.jp/graphics/ImageMagick/ImageMagick-6.7.0-8.tar.gz
# tar xvzf ImageMagick-6.7.0-8.tar.gz
# cd ImageMagick-6.7.0-8
# ./configure
# sudo make & make install

#Rmagickのインストール
# sudo gem install rmagick

このままだとなぜかlibMagickCore.so.2を読めないとか出てくるので、bash_profileに以下を追加
# vim .bash_profile
export LD_LIBRARY_PATH=/lib/
↑これを追加する。

これでインストールは完了。

次にこんな感じのファイルを作って、保存して、実行。

require 'rubygems'
require "RMagick"
require 'open-uri'
require 'nokogiri'
require 'uri'
include Magick #多分必要。


def flickr_img_download
 url = "http://www.flickr.com/explore/interesting/2011/06/"
 url_list = Array.new
 img_url_list = Array.new

 data = open( url )
 doc = Nokogiri::HTML( data )

#URLのリストを取得してます。
 doc.css('a').each do |f|
  begin
   if /\/explore\/interesting\/(\d+)\/(\d+)\/(\d+)\// =~ f.attribute('href').value
    url_list << f.attribute('href').value
   end
  rescue
   next
  end 
 end

 url_list.each do |f|
  img_url = URI.join(url, f)
  img_data = open( img_url )
  img_data = Nokogiri::HTML( img_data )
  img_data.css('img.pc_img').each do |img|
   img_url_list << img.attribute('src').value
  end
 end

 #画像を保存してます。
 img_url_list.each do |f|
  begin
   filename = File.basename( f )
   open("img/#{filename}", 'wb') do |file|
    open( f ) do |doc|
     file.write(doc.read)
     puts filename
    end
   end
  rescue
   next
  end
 end
end

def resize
 #背景の画像を作成
 whitefil = Magick::Image.new(150,150){self.background_color = 'none'}

 #フォルダ内の画像リストを作る。
 dir = Dir.glob(["./img/*.jpg", "./img/*.png"])

 dir.each do |filename|
  begin
   image = Magick::Image.read( filename ).first
   if image.columns < 150 or image.rows < 150 #サイズが150以下ならリサイズせずに余白だけ付ける。
     image = whitefil.composite(image, Magick::CenterGravity, Magick::OverCompositeOp)
   else image.columns > 150 or image.rows > 150 #サイズが150以上なら最大の幅を150になるよう、ファイルの比率は変えずに変換。
     image = image.resize_to_fit!(150,150)
     image = whitefil.composite(image, Magick::CenterGravity, Magick::OverCompositeOp)
   end
     image.write( filename )
  rescue Magick::ImageMagickError
   File.delete( filename )
   puts filename
  end
 end
end

flickr_img_download
resize

メソッド二回に分けてリサイズしているけど、本当は一回のメソッドで、かつ、リサイズ前のバックアップ用ファイルを別フォルダに保存しておきたい。
なぜか一回のメソッド中にやろうとすると、保存に失敗するので、こんな感じにしてます。
やり方知っている人がいたら助けてください。。。

2011年6月5日日曜日

検索からきた人に向けて、関連記事のリンクを出す

ITmediaとかで使われてる↓これのことです。正式名称なんていうんでしょうか?


面倒なのでとりあえずGoogleだけ対応。
あと複数キーワードがあったら、最初のキーワードだけ優先するようにしています。

リファラーの情報から、検索キーワードの部分だけを正規表現で取ってきて、

複数ヶ所で呼び出すことも考えて、applicationhelperに記述。

 def search_result(request)
  @request_name = Array.new
  @request_num = 0
   unless request == nil
    ref = request
    ref = URI.decode(ref).to_s
    if /google\./ =~ ref && ref != nil
     ref = ref.scan(/&q=(.*?)$|\?q=(.*?)$/).to_s
     ref = ref.scan(/^(.*?)&/).to_s if /&/ =~ ref
     ref = ref.gsub(/\+| /, ':?').to_s if /\+| / =~ ref
     ref = ref.to_s.split(':?') if /:?/ =~ ref
     @request_name = ref[0]
     ref = "%" + ref[0] + "%"
     @request_num = Entry.find(:all, :conditions => ["title like ? or discription like ?", ref, ref]).size
   end
  end
  end

コントローラーで呼び出す。
このときヘルパーのメソッドを呼び出せるようにincludeする。
request.refererにリファラー情報がある。

class EntriesController < ApplicationController
 include ApplicationHelper
 def index
 search_result(request.referer)
 @entries = Entry.all
 end
end

最後にビュー
<% if @request_num > 0 %>
 <%= link_to "#{@request_name}の関連記事:#{@request_num}件。", :controller => 'search', :id=>"#{@request_name}" %>
<% end %>

こんな感じです。

2011年6月3日金曜日

railsでsitemapを動的に生成する

#コントローラー
class SitemapController < ApplicationController
 def sitemap
  @entries = Entry.find(:all)
  headers["Content-Type"] = "text/xml; charset=utf-8"
  respond_to do |format|
   format.xml {render :layout => false}
  end
 end
end

#view(sitemap.xml.builder)
xml.instruct!
xml.urlset(:xmlns => "http://www.sitemaps.org/schemas/sitemap/0.9") do
 xml.url do
  xml.loc(url_for(:controller => :entries, :only_path => false))
 end

 @entries.each do |entry|
  xml.url do
   xml.loc(url_for(:controller => :entries, :action => :show, :id => entry.id, :only_path => false))
  end
 end
end

#routes.rb
map.xml 'sitemap.xml' , :controller => 'sitemap', :action => 'sitemap'

参考
http://higelog.brassworks.jp/?p=56