2009/02/16


さらに朗報は続く
Google App Engine Blog: The sky's (almost) the limit! "High CPU" is no more.

We're very excited today to announce that we've raised limits on several App Engine operations:

  • No more "High CPU Requests"! App Engine Apps were once allowed no more than 2 CPU-intensive requests per minute. We've made some adjustments to the way we handle requests, and have eliminated this limitation altogether. To learn more about how this works and the implications for your app, see our documentation.
  • Response deadline raised to 30 seconds. The amount of time an App Engine app can take to respond to an incoming request has been raised from 10 to 30 seconds! There are limits on the number of simultaneous active requests an application can process at any given moment--see our docs to learn more.
  • Size limits on code files, static files, and requests/responses raised to 10MB! App Engine apps can now receive requests and send responses of up to 10MB in size, and users can upload 10MB code and static files as well. Note that API requests (e.g. memcache.set(), db.put()) are still limited to 1MB in size.
http://googleappengine.blogspot.com/2009/02/skys-almost-limit-high-cpu-is-no-more.html
Google App Engineに1分あたり2CPU以上負荷を掛ける様なリクエストが許される事になりました。
またレスポンスのデッドラインが10秒から30秒にまで引き上げられました。
さらにコード、静的ファイル、および要求/応答におけるサイズ制限が10MBに引き上げられました(但しmemcache.set()、db.put()はまだ1MBに制限されています)。

これで例えば、デカいクエリを投げる様な処理でもエラーで落ちるって事が少なくなるんじゃないですかね。
もうすぐすると、Google App Engineでタイマ発動処理をサポートするという噂もあるので、よりインタラクティブな処理が作れるんじゃないですかね。
Posted at by



2009/02/14


Luaも動的にメンバが追加出来る言語ですので、データ構造を動的に作り上げる事が出来ます。今日はなんとなく、「LuaでWebScraper作ったら、どんなんになるんだろう...」と思いつきで...
用意するのは
  • LuaからXPathを操作出来るltxml
  • LuaからSocketを操作出来るLuaSocket
あくまでサンプルですので、CSSセレクタも使えなければ最新のWebScraperの様に相対/絶対URL展開や、フィルタ等はサポートしていません。
またresultも動作させていない為、結果が全て戻ります。
さらにltxmlが内部で使っているTinyXML/TinyXPathの仕様からか、XPathの途中に「//」をめり込ます事が出来ませんでした。
まずLua版WebScraperのソース。

luascraper.lua
local http = require("socket.http")
local xml = require("xml")

-- return process structure
function process(t)
  return {name="process",process={xpath=t[1], name=t[2], scraper=t[3]}}
end
-- not supported
function result(p)
  return p
end
-- return scraper structure
function scraper(self)
  self.name = "scraper"
  -- scrape method
  function self.scrape(url, ctx)
    -- create http session and parse HTML
    if ctx == nil then
      local chunk = {}
      local b, c = http.request {
        method = "GET",
        url = url,
        sink = ltn12.sink.table(chunk)
      }
      if not c == 200 then
        return nil
      end
      local html = table.concat(chunk)
      ctx = {op = self, doc = xml.parse(html)}
    end
    -- scraping...
    self.res = {}
    if not ctx.doc then
      return nil
    end
    for k,v in pairs(self) do
      if (type(v) == "table" and v.name == "process") then
        if (type(v.process.scraper) == "table") then
          for k1,v1 in pairs(ctx.doc:select(v.process.xpath)) do
            local newctx = {top=ctx.top, doc=v1}
            self.res[#(self.res)+1] = v.process.scraper.scrape(url, newctx)
          end
        else
          local node = ctx.doc:select(v.process.xpath)
          if node then
            local attr = v.process.scraper
            if attr == "TEXT" then
              self.res[v.process.name] = node[1]:text()
            elseif string.sub(attr, 1, 1) == "@" then
              attr = string.sub(attr, 2)
              self.res[v.process.name] = node[1]:attribute(attr)
            end
          end
        end
      end
    end
    return self.res
  end
  return self
end
案外ボリューム無く書けました。
このモジュールを使って私のtwitter/with_friendsの発言リストをスクレイピングするLuaスクリプトがコレ

twitter_scraper.lua
require "luascraper"

local s = scraper {
  process {'//tr[@class="hentry"]',
    'status', scraper {
      process {'//td[@class="content"]/strong/a', 'nick', 'TEXT'},
      process {'//td[contains(@class,"author")]/a/img', 'name', '@alt'},
      process {'//td[contains(@class,"author")]/a/img', 'image', '@src'},
      process {'//span[contains(@class,"entry-title")]', 'description', 'TEXT'},
      process {'//a[@rel="bookmark"]', 'url', '@href'},
    }},
  result = 'friends';
}

function dump(r)
  print('-')
  for k,v in pairs(r) do
    if type(v) == "table" then
      dump(v)
    else
      print(k,v)
    end
  end
end
r = s.scrape('http://twitter.com/mattn_jp/with_friends/')
dump(r)
そして結果がコレ
image   http://s3.amazonaws.com/twitter_production/profile_images/24072332/negipo_normal.png
name    Yoshiteru Negishi
url http://twitter.com/negipo/statuses/371889282
description fooo.nameのおかげで自分が入り忘れてるウェブサービスがわかるようになった
nick    negipo
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34076402/crestock-221345-1024x768_normal.jpg
name    ハラヘ(´・ω・`)
url http://twitter.com/mobcov/statuses/371888702
description 今見るとシローアマダはかっこ悪いけどアイナサハリンは(ry
nick    mobcov
-
image   http://s3.amazonaws.com/twitter_production/profile_images/33598712/wt_normal.png
name     暴君
url http://twitter.com/VoQn/statuses/371888452
description 授業終わった。やっとご飯食べられる
nick    VoQn
-
image   http://s3.amazonaws.com/twitter_production/profile_images/24072332/negipo_normal.png
name    Yoshiteru Negishi
url http://twitter.com/negipo/statuses/371887582
description はてなperlグループに入った
nick    negipo
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34078402/cat_888_normal.gif
name    (c)yabkoji
url http://twitter.com/yabkoji/statuses/371887022
description 激スイマー襲来中。
nick    yabkoji
-
image   http://s3.amazonaws.com/twitter_production/profile_images/22560082/nobita_normal.jpg
name    kimidora
url http://twitter.com/kimidora/statuses/371886072
description ねむいねむいねむいねむいねむいねむいねむいねむいねむいねむい。。。。。。。。。。ぐぅ *Tw*
nick    kimidora
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34253552/twfoot_normal.gif
name    highness
url http://twitter.com/smokeymonkey/statuses/371885732
description うぅ、ムラサメで部長とカブった。
nick    smokeymonkey
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34253552/twfoot_normal.gif
name    highness
url http://twitter.com/smokeymonkey/statuses/371885022
description はてなグループって排他制御あるのかしら。
nick    smokeymonkey
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34076402/crestock-221345-1024x768_normal.jpg
name    ハラヘ(´・ω・`)
url http://twitter.com/mobcov/statuses/371884382
description TextMateアップデートキターーーーー!!
nick    mobcov
-
image   http://s3.amazonaws.com/twitter_production/profile_images/32257122/basara_normal.jpg
name    japo
url http://twitter.com/japo/statuses/371884052
description ハマーン様万歳だろJK
nick    japo
-
image   http://s3.amazonaws.com/twitter_production/profile_images/19383642/ore_normal.jpg
name    Sugano Yoshihisa(E)
url http://twitter.com/koshian/statuses/371883862
description 「あのPerlモジュールなんてったっけ?」とぐぐったら、自分のはてなブックマークがひっかかって見事に発見
nick    koshian
-
image   http://s3.amazonaws.com/twitter_production/profile_images/22022432/plagger_logo_purple_normal.png
name    plagger.org
url http://twitter.com/plagger/statuses/371883772
description Safariの『Webクリップ』を試してみる。 - sta la sta
nick    plagger
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34253552/twfoot_normal.gif
name    highness
url http://twitter.com/smokeymonkey/statuses/371882682
description うわ、 GFF でペーネロペー出てるのか。超欲しい。
nick    smokeymonkey
-
image   http://s3.amazonaws.com/twitter_production/profile_images/33078022/icon_normal.gif
name    Miki@7500
url http://twitter.com/7500/statuses/371881092
description 午後の部にとりかかりまっしゅ!夕方までしゃいなら?ノシ
nick    7500
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34253552/twfoot_normal.gif
name    highness
url http://twitter.com/smokeymonkey/statuses/371879692
description 初代からν→ F91 まで + アレックスと 08 小隊とデンドロビウムは把握してる。その後はさっぱりだな。
nick    smokeymonkey
-
image   http://s3.amazonaws.com/twitter_production/profile_images/15059862/al3x_normal.jpg
name    Alex Payne
url http://twitter.com/al3x/statuses/371879502
description Oh, how I wanted to be rid of MacPorts. Curse you, Image/Rmagick.
nick    al3x
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34297902/kamon_normal.png
name    wrongbee
url http://twitter.com/wrongbee/statuses/371878872
description ペーネロペーの画像検索結果
nick    wrongbee
-
image   http://s3.amazonaws.com/twitter_production/profile_images/33078022/icon_normal.gif
name    Miki@7500
url http://twitter.com/7500/statuses/371878362
description @
nick    7500
-
image   http://s3.amazonaws.com/twitter_production/profile_images/15927972/otsune_hanaji_purple_normal.jpg
name    ??uns?o ??n??s??
url http://twitter.com/otsune/statuses/371877452
description Pukkaのすばらしい所はdel.icio.usのアカウント切り替えが一瞬でプルダウンメニューで選べる所だ。bookmarkletなんかでソーシャルブックマークしてたらログアウト・ログインの時間分だけ人生を無駄にする lang:ja
nick    otsune
-
image   http://s3.amazonaws.com/twitter_production/profile_images/34253552/twfoot_normal.gif
name    highness
url http://twitter.com/smokeymonkey/statuses/371876992
description 閃光のハサウェイはガンダムサイドストーリーでは一番好きだ。
nick    smokeymonkey
-
-
Luaでもやれない事はない!

追記
result処理、相対/絶対URL展開処理を加えて、CodeReposに入れておきました。
Posted at by



2009/02/12


hexdigestでなくdigestですね。:-)
mod_access_tokenを入れてみた - まめ畑

ここまでは良かったのですが、Signatureを生成するスクリプトを作ろうと思ったのですが、Rubyで上手くいかない・・・。

http://d.hatena.ne.jp/con_mame/20090209
あとはbase64に付く改行とターミネータをカットすればOKですね。
require 'openssl'
require 'base64'
require 'uri'
require 'time'

access_key = 'foo'
secret = 'bar'
url = 'http://localhost:8080/access_token/example.jpg'
exp = (Time.new+300).to_i.to_s
uri = URI.parse(url)
plain = "GET#{uri.path}#{exp}#{access_key}"
hmac = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA1.new, secret, plain)
sig = Base64.encode64(hmac).chomp.sub(/=*$/, '')
puts "#{url}?Signature=#{URI.escape(sig)}&AccessKey=#{URI.escape(access_key)}&Expires=#{URI.escape(exp.to_s)}"
結果はこんな感じ。
http://localhost:8080/access_token/example.jpg?Signature=Rt2cKnnOYuDiE/XYKTLTaOuY4Wg&AccessKey=foo&Expires=1234417692 ちなみにBase64.b64encodeはエンコード結果を表示してしまうのでencode64が良さそうですね。
  def b64encode(bin, len = 60)
    encode64(bin).scan(/.{1,#{len}}/) do
      print $&, "\n"
    end
  end 
Posted at by