atomutilを使ってrubyでアメブロに投稿する方法

これまで、はてなダイアリーatomutilを使ってrubyではてなダイアリーに投稿する方法 - 水清無魚(すいせいむぎょ))に引き続き、ライブドアのブログ投稿(atomutilを使ってrubyでライブドアのブログに投稿する方法 - 水清無魚(すいせいむぎょ))しました。

こんどは本丸というべきアメブロに投稿してみたいと思います。というのが、結構皆さん苦労されているみたいなんです。

はてなダイアリーライブドアのブログと同じようにAtomPubの仕様ではあるのですが、ちょっと癖があって、パスワードをMD5ハッシュに変換しないといけないとか、nonceに使用できる文字列に制限があったりします。

しかし、カテゴリの設定に関しては結局わかりませんでした。Twitterのつぶやきを自動投稿するツールで設定されていたような気がするのですが・・・

とりあえず、タイトルと本文の投稿のみの現状を公開しておきます。

# -*- coding: utf-8 -*-

# @see : http://d.hatena.ne.jp/lyokato/20071211/1197353609
# gem install atomutil
require 'atomutil'

# Livedoorブログやアメブロ対策のためオーバーライドし、戻り値としてLocationではなくステータスコードを返却するようにする
class Atompub::Client
  def create_entry(post_uri, entry, slug=nil)
    unless entry.kind_of?(Atom::Entry)
      entry = Atom::Entry.new :stream => entry
    end
    service = @service_info.get(post_uri)
    # Livedoorブログの場合、serviceが取得できなくてservice.allows_category?でエラーになるので、if serviceでくくる
    if service
      unless entry.categories.all?{ |c| service.allows_category?(c) }
        raise RequestError, "Forbidden Category"
      end
    end
    create_resource(post_uri, entry.to_s, Atom::MediaType::ENTRY.to_s, slug)
    return @res.code
  rescue Atompub::ResponseError #=> rs
    # アメブロでは正常に投稿できても@res['Location']が空になってResponseErrorになるので捕獲する
    return @res.code
  end
end

# アメブロでnonceに英数以外が含まれるとエラーになるのでオーバーライド
class Atompub::Auth::Wsse
  def gen_token
    # 以下で生成される文字列ではAmebloの場合エラーとなる
    #nonce = Array.new(10){rand(0x100000000)}.pack('I*')
    nonce = [*1..9, *'A'..'Z', *'a'..'z'].sample(16).join
    nonce_base64 = [nonce].pack('m').chomp
    now = Time.now.utc.iso8601
    digest = [Digest::SHA1.digest(nonce + now + @password)].pack('m').chomp
    sprintf(%Q<UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s">,
      @username, digest, nonce_base64, now)
  end
end
    
def entry(id, password, title, content, category=nil)
  # アメブロに限り、パスワード文字列のmd5ハッシュ値化必要
  # @see : http://senpai4.blog29.fc2.com/blog-entry-452.html
  password = Digest::MD5.hexdigest(password)
  auth = Atompub::Auth::Wsse.new :username => id, :password => password
  client = Atompub::Client.new :auth => auth
  
  service = client.get_service("http://atomblog.ameba.jp/servlet/_atom/blog")
  ns = Atom::Namespace.new(:uri => 'http://purl.org/atom/ns#')
  links = service.getlist(ns, 'link')
  href = nil
  links.each do |link|
    if link.attributes['rel'] == 'service.post'
      href = link.attributes['href']
      break
    end
  end
  # 自動改行にはならないので(ブログ側の設定次第?)
  content = content.gsub(/\n/, '<br/>');

  # カテゴリの設定方法は不明
  new_entry =<<EOM
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#">
  <title>#{title}</title>
  <content type="application/xhtml+xml">
    <![CDATA[#{content}]]>
  </content>
</entry>
EOM
  return client.create_entry(href, new_entry)
end

title = "テスト"
content =<<EOM
<b>太字ですか?</b>
改行されていますか?
EOM

puts entry('<ログインID>', '<パスワード>', title, content)

以下のサイトを参考にしました。ありがとうございました。

atomutilを使ってrubyでライブドアのブログに投稿する方法

前回は、rubyはてなダイアリーに投稿しました(atomutilを使ってrubyではてなダイアリーに投稿する方法 - 水清無魚(すいせいむぎょ))。

なので、こんどはライブドアのブログに投稿してみたいと思います。

ちなみに、ライブドアのブログもAtomPubで投稿ができるので、atomutilを使用します。

基本的には、はてなダイアリーの時と同じなんですが、カテゴリの設定などのために、見る人から見れば突っ込みどころ満載のことをしていますが、そのあたりは適宜好みの方法に変更してください。

# -*- coding: utf-8 -*-

# @see : http://d.hatena.ne.jp/lyokato/20071211/1197353609
# gem install atomutil
require 'atomutil'
require 'cgi'

# Livedoorブログやアメブロ対策のためオーバーライドし、戻り値としてLocationではなくステータスコードを返却するようにする
class Atompub::Client
  def create_entry(post_uri, entry, slug=nil)
    unless entry.kind_of?(Atom::Entry)
      entry = Atom::Entry.new :stream => entry
    end
    service = @service_info.get(post_uri)
    # Livedoorブログの場合、serviceが取得できなくてservice.allows_category?でエラーになるので、if serviceでくくる
    if service
      unless entry.categories.all?{ |c| service.allows_category?(c) }
        raise RequestError, "Forbidden Category"
      end
    end
    create_resource(post_uri, entry.to_s, Atom::MediaType::ENTRY.to_s, slug)
    return @res.code
  rescue Atompub::ResponseError #=> rs
    # アメブロでは正常に投稿できても@res['Location']が空になってResponseErrorになるので捕獲する
    return @res.code
  end
end

# カテゴリを設定するためにオーバーライド
class REXML::Attribute
  alias :_to_s :to_s
  def to_s
    value = _to_s
    value = value.encode("BINARY", "BINARY") if value.encoding != "UTF-8"
    return value
  end
end
    
def entry(id, password, title, content, category=nil)
  auth = Atompub::Auth::Wsse.new :username => id, :password => password
  client = Atompub::Client.new :auth => auth    

  # ライブドアブログの場合は、自動改行にはならない(ブログ側の設定次第?)
  content = content.gsub(/\n/, '<br/>');
  
  # ライブドアブログの場合は、htmlのescapeも必要
  content = CGI.escapeHTML(content)
  
  new_entry = Atom::Entry.new
  new_entry.title = title.encode("BINARY", "BINARY")
  new_entry.content = content.encode("BINARY", "BINARY")

  if category
    new_category = Atom::Category.new
    new_category.term = category
    new_entry.category = new_category
  end
  puts new_entry
  return client.create_entry("http://livedoor.blogcms.jp/atom/blog/#{id}/article", new_entry)  
end

title = "テスト"
content =<<EOM
<b>太字ですか?</b>
改行されていますか?
EOM
category = 'ツール'

puts entry('<ログインID>', '<API KEY(※1)>', title, content, category)

※1)API KEYはブログ管理画面のブログ設定>その他>API Keyから確認できます。API KEYは半角英数字10字です。

以下のサイトを参考にしました。ありがとうございました。

atomutilを使ってrubyではてなダイアリーに投稿する方法

これまでのrubyでのブログの投稿では、mechanizeを使用して実際のWebでの画面をシュミレートして投稿をするようにしていましたが、どこのブログも結構仕様変更が多くて、そのたびに修正をしていました。

XMLやAtomPubでの投稿ができるのは知ってはいたのですが、AB型の変なこだわりでmechanizeでの方法を貫いていました(笑)。

とはいっても、どう考えてもスマートな方法ではないので、はてなのAtomPubの方法も少し変わったみたい(はてなブログAtomPub - Hatena Developer Center)ですので、これを機会にAtomPubでの投稿に切り替えたいと思います。

そこで、atomutil(atomutil - RubyでAtomPubを操作するパッケージをリリースしました - Codin’ In The Free World)なるものを発見しましたので、それではてなダイアリーrubyから投稿を行ってみました。

# -*- coding: utf-8 -*-

# @see : http://d.hatena.ne.jp/lyokato/20071211/1197353609
# gem install atomutil
require 'atomutil'

# Livedoorブログやアメブロ対策のためオーバーライドし、戻り値としてLocationではなくステータスコードを返却するようにする
class Atompub::Client
  def create_entry(post_uri, entry, slug=nil)
    unless entry.kind_of?(Atom::Entry)
      entry = Atom::Entry.new :stream => entry
    end
    service = @service_info.get(post_uri)
    # Livedoorブログの場合、serviceが取得できなくてservice.allows_category?でエラーになるので、if serviceでくくる
    if service
      unless entry.categories.all?{ |c| service.allows_category?(c) }
        raise RequestError, "Forbidden Category"
      end
    end
    create_resource(post_uri, entry.to_s, Atom::MediaType::ENTRY.to_s, slug)
    return @res.code
  rescue Atompub::ResponseError #=> rs
    # アメブロでは正常に投稿できても@res['Location']が空になってResponseErrorになるので捕獲する
    return @res.code
  end
end

def entry(id, password, title, content, category=nil)
  auth = Atompub::Auth::Wsse.new :username => id, :password => password
  client = Atompub::Client.new :auth => auth    

  new_entry = Atom::Entry.new
  # 下の方法でカテゴリの設定をすることができないみたいなので、はてな記法でカテゴリを設定する
  if category
    title = "*[#{category}]#{title}"
  end
  new_entry.title = title.encode("BINARY", "BINARY")
  new_entry.content = content.encode("BINARY", "BINARY")
  #if category
  #  new_category = Atom::Category.new
  #  new_category.term = category
  #  new_entry.category = new_category
  #end
  return client.create_entry("http://d.hatena.ne.jp/#{id}/atom/blog", new_entry)  
end

title = "タイトル"
content =<<EOM
ここは本文です。
<b>太字ですか?</b>
改行されていますか?
EOM
category = 'ツール'

puts entry('<はてなのID>', '<パスワードもしくはAPIキー(※1)>', title, content, category)

※1)現在はパスワードでもいいみたいですが、そのうちAPIキーでなくてはいけなくなります。(はてなダイアリーAtomPubのWSSE認証の認証方法を変更します(開発者向け) - はてなダイアリー日記

以下のサイトを参考にしました。ありがとうございました。

rake バージョンが新しすぎるって怒られた

久々に改修のrailsアプリで、DBのフィールドの変更があったので、migrateのファイルを作成して、

$ rake db:migrate

ってすると、

$ rake db:migrate
rake aborted!
ERROR: 'rake/rdoctask' is obsolete and no longer supported. Use 'rdoc/task' (available in RDoc 2.4.2+) instead.

(以下省略)

ググってみると、どうやらrake バージョンが新しすぎるってことみたいです。

このエラーは rake のバージョンが新しすぎるのが原因。
基本的にRails3.0.5より前のRailsでは、rakeのバージョンは0.8.7を使う

引用元:Rails 2.*系で「rake/rdoctask is deprecated. Use rdoc/task instead (in RDoc 2.4.2+)」エラー | GENDOSU@NET

で、以下のようにしてアンインストールしようとしてもできないみたい。

$ gem uninstall rake -v=10.0.4
ERROR:  While executing gem ... (Gem::InstallError)
    cannot uninstall, check `gem list -d rake`

いわれるままに、`gem list -d rake`をしてみる

$ gem list -d rake

*** LOCAL GEMS ***

rake (10.0.4, 0.9.2.2)
    Author: Jim Weirich
    Rubyforge: http://rubyforge.org/projects/rake
    Homepage: http://rake.rubyforge.org
    License: MIT
    Installed at (10.0.4): /Users/hoge/.rvm/gems/ruby-1.8.7-p302@global
                 (0.9.2.2): /Users/hoge/.rvm/gems/ruby-1.8.7-p302@global

    Ruby based make-like utility.
trachurus:univplan eiichi$ gem uninstall rake
Remove executables:
	rake

in addition to the gem? [Yn]  y       
Removing rake

You have requested to uninstall the gem:
	rake-0.9.2.2
rvm-1.11.3.7 depends on [rake (>= 0)]
rvm-1.11.3.3 depends on [rake (>= 0)]
rails-2.3.5 depends on [rake (>= 0.8.3)]
rubygems-bundler-1.0.2 depends on [rake (>= 0)]
If you remove this gems, one or more dependencies will not be met.
Continue with Uninstall? [Yn]  y                 
Successfully uninstalled rake-0.9.2.2

でも、アンインストールしたい10.0.4ではないし、そもそも0.9.2.2もアンインストールできていない。

$ gem list

*** LOCAL GEMS ***

(省略)
rails (2.3.5)
rake (10.0.4, 0.9.2.2)
(省略)

そこで、再度ググって、見つけたサイトと同じようにまねしてみた。

gem uninstall のときに -i オプションを使ってディレクトリを指定して消している。なるほどね。早速、まねして実行してみましょ。

引用元:今度は rake/rdoctask is deprecated. - 日々是笑心

$ gem uninstall rake -i /Users/hoge/.rvm/gems/ruby-1.8.7-p302@global

Select gem to uninstall:
 1. rake-0.9.2.2
 2. rake-10.0.4
 3. All versions
> 2
Successfully uninstalled rake-10.0.4

で、見事成功。よかったよかった。

注意!忍者ブログで「URLカスタマイズ」を「使用する」の場合は、短めのタイトルにしなくちゃ

macro pixels url cliche
macro pixels url cliche / Cubosh

ここ最近は、忍者ブログでとあるサイトをセコセコと作っています。
日時的な旬のあるテーマなので、それに追われるように1日10〜30位の記事を書いています。

とあるところで、はてブに登録するとSEO的に効果が期待できるので、それなりに登録したほうがいいというのと、まーはやりということで、Twitterのツイートボタン、Facebookのいいねボタン、Google+の+1ボタン、はてなブックマークはてブボタン、Googleリーダーの登録ボタンなどありとあらゆるボタンを設置してみました。

で、試しにはてブに1件登録して、はてブ側からリンクがちゃんと貼れているか確認したところ、「404 NOT FOUND」になってしまいます。

なぜなのか調べたところ、はてなブックマークはてブボタンで登録されるURLには長さの制限があるみたいで、勝手に短くされたアドレスが登録されていたみたいです。これは、忍者おまとめボタンでも、zenbackのものでも同じで、はてブの仕様みたいで、256文字で切られてしまうみたいです。

他の、FacebookのいいねボタンやTwitterのツイートボタンでは試していませんが、同様のことが起きる可能性はあると思いますので、URLは短めのほうが安全といこうことになると思います。

そこで、忍者ブログで「URLカスタマイズ」を「使用する」にした場合、タイトルを元にした日本語を含むURLになるのですが、それをURLエンコードすると256文字なんてすぐに超えてしまします。忍者ブログでも、タイトルが長い場合は適当に短くしてURLにしているのですが、それでもURLエンコードすると256文字を超えてしまっています。

忍者ブログでこの辺りを考慮して、同じ短くするのならURLエンコードすると256文字になるようしてくれればいいのですが、現状ではそのようにはなっていません。もちろん、自分で短くして登録すればいいのですが手間がかかりますよね。

と、いうことで、忍者ブログで「URLカスタマイズ」を「使用する」にせず、 xxx.xxx.com/Entry/999/のような元のアドレスを使用したほうが安全ということになります。

また、一部では日本語でキーワードを含むURLはSEO的に有効であるいわれますが、その反面URLは短いほういいともいわれています。どちらがいいかは、結局Googleのその時々の仕様によるので一概に判断はできないのですが、URLの永続化もSEO的に大切な要素なので、変動しにくい xxx.xxx.com/Entry/999/の形式の方がいいと思います。

とは、いいつつも、Google Analysticsでは、日本語URLのほうが各ページを把握しやすいので、ちょっと迷ってはいるのですが・・・

参考にしたサイト

「博多祇園山笠」もいいけど、「甘木祇園山笠」ってのもあるよ

戸畑祇園大山笠
Photo:戸畑祇園大山笠 By Ippei Ogiwara

この時期の博多といえば、やっぱり「博多祇園山笠」ってことになるんだけど、追い山が深夜なんで、録画したものしか子供にみせることができません。もちろん、夜中に連れ出せばいいんだろうけど・・学校もあるし。

そこで、本家「博多祇園山笠」までの盛り上がりはないかもしれないけど、甘木の須賀神社で行われる「甘木祇園山笠」はどうでしょうか?追い山も昼の2時からみたいなので、十分子供と見に行くことができます。

福岡県朝倉市甘木の須賀神社で行なわれる「甘木祇園山笠」約300年の伝統を持つ須賀神社祇園祭で、夏祭りの一環として行われています。疫病が流行した際、神輿を造り、ご神体を移して町中を練り回したことが始まりといわれ、高さ3mのひき山笠2台の勇壮さは圧巻です。13日が子ども神輿、15日が本山笠として東西へ追い山が出て町中を練り回します。甘木の代表的な夏の風物詩であり、露店が並び、暑い夏が始まります。

引用元:福岡の祭り|祭りいくよ!

他にも、福岡県内で時期はいろいろですが44もの山笠があるようなので、ちょっと探せば隣町あたりでやってるかもしれませんね。ちなみに上の写真は「戸畑祇園山笠」です。

netBeansにて、rvmでインストールしたRubyのGemがrequireできない場合の対応について

Mr. James Gosling & NekoBean T-Shirt, General Session, Sun Tech Days 2008 in Tokyo Day1, 2008.12.02
Photo:Mr. James Gosling & NekoBean T-Shirt, General Session, Sun Tech Days 2008 in Tokyo Day1, 2008.12.02 By Yuichi Sakuraba

いまさらながら、ちょっとしたRubyのプログラムを書く時にnetBeansにおおいに嵌っています。
実行する時に[Shift]+[F6](Macの場合、[F6]がちょっと押しにくいけど・・)はとっても便利です。

しかし、netbeansが自動検出したプラットフォームの設定では、Gemがrequireできない場合がよくあります。この場合は、netbeansRubyプラットフォームマネージャーで設定されているgem環境が、使用しているrvmのRubyプラットフォームのgem環境と違う場合が考えられます。(そもそも設定していない場合も)

まずは、netbeansにrvmのプラットフォームを自動検出してもらう。

  1. netbeansのメニューバーの[ツール]→[Rubyプラットフォーム](Ruby Platform)を開く
  2. Rubyプラットフォームマネージャーを立ち上げる
  3. [プラットフォームを自動検出](Autodetect Platforms)をクリック


コマンドラインにて使用したいrvmに設定して(rvm use XXX)「gem env」にて、環境を表示します。

$ gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 1.8.25
  - RUBY VERSION: 1.9.2 (2012-04-20 patchlevel 320) [x86_64-darwin10.8.0]
  - INSTALLATION DIRECTORY: /Users/user_name/.rvm/gems/ruby-1.9.2-p320
  - RUBY EXECUTABLE: /Users/user_name/.rvm/rubies/ruby-1.9.2-p320/bin/ruby
  - EXECUTABLE DIRECTORY: /Users/user_name/.rvm/gems/ruby-1.9.2-p320/bin
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86_64-darwin-10
  - GEM PATHS:
     - /Users/user_name/.rvm/gems/ruby-1.9.2-p320
     - /Users/user_name/.rvm/gems/ruby-1.9.2-p320@global
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :benchmark => false
     - :backtrace => false
     - :bulk_threshold => 1000
     - :sources => ["http://rubygems.org/", "http://gems.github.com/"]
  - REMOTE SOURCES:
     - http://rubygems.org/
     - http://gems.github.com/

netbeansRubyプラットフォームマネージャーの右側のリストにて、対象となるRubyプラットフォームを洗濯して、各設定値が正しいか?パスなどに誤りがない確認して、違う場合は修正します。とくにコマンドラインの「GEM PATHS:」のRubyプラットフォームマネージャーの「Gem Path:」とパスが正しいか確認します。

それでも、Gemがrequireできないなどのエラーの場合は、「netbeans.conf」に環境変数の設定を追加すればできる場合が多いので試してみてください。

netbeans.conf」は「/Applications/NetBeans/NetBeans\ 7.3.1.app/Contents/Resources/NetBeans/etc」みたいなところにあります。