Archive for the 'NSMutableURLRequest' Category

2017/05/15 感情推定(極性判定) v2

apitoreのREST API「感情推定(極性判定) v2」を呼び出すAppleScriptです。

400文字以下のテキストを解析して、極性(感情)を判定します。ただし、文章が短すぎると判定しづらくなる傾向があるようです。これまでの感情推定APIではpositive/negativeとして判定する傾向があったため、このv2 APIではneutralとして判定する幅を広めにとってもらいました。

本Scriptをテストするためには、apitoreにサインアップしてAccess Tokenを取得し、Script末尾の伏字部分にコピー&ペーストしてください(掲載リストをそのまま実行してもエラーになります)。

AppleScript名:感情推定(極性判定) v2
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4639

set aString to "このePubの考え方にそぐわない文章要素がいろいろある。代表的なものは「表」だ。データを掲載しておくのに、「表」は便利な存在だ。書く方からしても、いちいち長々とした文章で説明しなくていいし、読む方からしても整理された情報を読めるわけで、とくにお年寄りに好まれる。ところが、この「表」がePubの出版物にそぐわない。表の幅は変わってほしくないし、文字サイズが大きくなって数ページにわたって表示されるといったことは好ましくない。"
set a1Res to getSentimentFromString(aString) of me
–>  "positive"(なのか?)

on getSentimentFromString(aString)
  set reqURLStr to "https://api.apitore.com/api/39/sentiment-v2/predict"
  
set accessToken to retAccessToken() of me
  
set aRec to {access_token:accessToken, |text|:aString}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
  
set aRESCode to (responseCode of aRes) as integer
  
if aRESCode is not equal to 200 then return false
  
  
set aRESTres to ((json of aRes)’s valueForKeyPath:"predict.sentiment") as string
  
return aRESTres
end getSentimentFromString

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessToken()
  return "xxXXXxxX-XxXx-XXXX-xXXX-XXxXXxxXxxXx" –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2017/05/06 Bing Web Search APIでWebキーワード検索

MicrosoftのBing Web Search APIを呼び出してWebのキーワード検索を行うAppleScriptです。

Microsoft Cognitive Servicesのサイトで、開発者アカウント登録を行えば、本APIについては1か月に1,000回まで無料で使用できます(1秒間に7回までという制限もあります)。

アカウント登録を行い、Bing Web SearchをEnableに設定して、本AppleScriptの末尾のretAPIKey()ハンドラ内にAPI Key 1を入力してください(API Keyを記入したScriptを決してそのまま第三者に配布しないでください。あくまでテストと確認用です)。

個人的にBingは検索エンジンとして常用していません。Google検索にくらべて見つかる情報量が少ないと実感していることがその理由です。そのため、Bingの検索エンジンを呼び出せてもあまりメリットを見出せないところ。あくまで実験の一環です。

AppleScript名:Bing Web Search APIでWebキーワード検索
– Created 2017-05-03 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4634

set aStr to “戦場の絆”

set reqURLStr to “https://api.cognitive.microsoft.com/bing/v5.0/search” –Microsoft Project Oxford
set myAPIkey to retAPIkey() of me –API Primary Key

set aRec to {q:aStr, |count|:“5″, |offset|:“0″, mkt:“ja-JP”}
set bURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPI(bURL, myAPIkey) of me
set aRESTres to json of aRes
set aRESCode to responseCode of aRes
set aRESHeader to responseHeader of aRes

return (webPages of aRESTres)

–POST methodのREST APIを画像をアップロードしつつ呼ぶ
on callRestGETAPI(aURL, anAPIkey)
  –Request
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:anAPIkey forHTTPHeaderField:“Ocp-Apim-Subscription-Key”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
if dRes = missing value then
    set resCode to -1
    
set resHeaders to {}
  else
    set resCode to (dRes’s statusCode()) as integer
    
–Get Response Header
    
set resHeaders to (dRes’s allHeaderFields()) as record
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPI

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAPIkey()
  return “XxXxXXxXxXxXXxXXxXXXxXXXxxxxXxxX” –API Key 1
end retAPIkey

★Click Here to Open This Script 

2017/05/04 Analyze Imageで画像認識

MicrosoftのCognitive ServicesのREST APIのひとつ、Computer Vision APIの「Analyze Image」を呼び出して画像認識するAppleScriptです。

Microsoft Cognitive Servicesのサイトで、開発者アカウント登録を行えば、本APIについては1か月に5,000回まで無料で使用できます(1分間に20回までという制限もあります)。

アカウント登録を行い、Analyze ImageをEnableに設定して、本AppleScriptの末尾のretAPIKey()ハンドラ内にAPI Key 1を入力してください(API Keyを記入したScriptを決してそのまま第三者に配布しないでください。あくまでテストと確認用です)。

指定した画像のカテゴリ(Categories)、タグ情報(Tags)、詳細内容(Description)の情報を取得しています。

精度については、実際にテスト画像と得られた認識データを見比べていただくしかありません。カタツムリとか誕生日ケーキとか夕日や花火、ワインボトルなど(!)、驚くほど正確に認識されています。夕日の手前にあるのは飛行機ではないのですが、そのぐらいの誤差はあります(イルカを「犬」と判定されたりもしました)。

ためしに、この結果(Description)をそのままGoogle Tlanstlate APIに渡して日本語訳させ画像のFinderコメント欄に入れる実験などもやってみたところ、面白い結果が得られました(実用性はまだまだですが、言いたいことはわかる、というレベル。個人的には英語のままのほうがわかりやすいかも)。

こうしたサービスを利用して、写真.app(Photos.app)内の写真にすべてタグ付けして、タグをもとに風景の写真だけを新規アルバムに入れて分類するといった使い方はできそうです(すでにやってるし)。そして、AppleのアプリケーションとMicrosoftやGoogleのWebサービスを連携させるといった使い方はAppleが提供するわけがないので、こういう用途こそAppleScriptで勝手に連携させるべきだと思います。

r0010704_resized.png
{{metadata:{width:2592, |format|:”Jpeg”, height:1944}, tags:{{|name|:”fireworks”, confidence:0.998994648457}, {|name|:”outdoor object”, confidence:0.998748064041}}, categories:{{|name|:”dark_fireworks”, score:0.99609375}}, |description|:{tags:{”fireworks”, “object”}, captions:{{|text|:“a close up of fireworks”, confidence:0.233880494749}}}, requestId:”ce5e5c15-f68f-4647-9694-5fb8ede9cd31″}}

r0015213_resized.png
{{metadata:{width:2592, |format|:”Jpeg”, height:1944}, tags:{{|name|:”ground”, confidence:0.999917149544}, {|name|:”animal”, confidence:0.993541717529}, {|name|:”invertebrate”, hint:”animal”, confidence:0.952201843262}, {|name|:”outdoor”, confidence:0.887740492821}, {|name|:”mollusk”, hint:”animal”, confidence:0.814713895321}, {|name|:”snail”, hint:”animal”, confidence:0.649717211723}}, categories:{{|name|:”abstract_texture”, score:0.6015625}}, |description|:{tags:{”animal”, “outdoor”, “shellfish”, “snail”, “piece”, “laying”, “food”, “sitting”, “top”, “surface”, “lying”, “banana”, “close”, “fruit”, “bird”, “beach”, “plate”, “board”, “street”}, captions:{{|text|:“a snail on the ground”, confidence:0.480042590526}}}, requestId:”b290dc83-0e33-41b0-8a39-76c067bcffb8″}}

r0015918_resized.png
{{metadata:{width:2048, |format|:”Jpeg”, height:1536}, tags:{{|name|:”grass”, confidence:0.99923813343}, {|name|:”outdoor”, confidence:0.997150361538}, {|name|:”ground”, confidence:0.972813665867}, {|name|:”standing”, confidence:0.93672734499}, {|name|:”animal”, confidence:0.917161226273}, {|name|:”bird”, confidence:0.824012756348}}, categories:{{|name|:”animal_horse”, score:0.98046875}}, |description|:{tags:{”grass”, “outdoor”, “standing”, “bird”, “animal”, “water”, “field”, “white”, “small”, “walking”, “front”, “sitting”, “parrot”, “brown”, “large”, “grassy”, “green”, “body”, “dirt”, “red”, “river”}, captions:{{|text|:“a bird that is standing in the grass”, confidence:0.859258793309}}}, requestId:”bc5b8778-cf96-4d3c-8ba9-be22b38c36dd”}}

img_2502_resized.png
{{metadata:{width:3264, |format|:”Jpeg”, height:2448}, tags:{{|name|:”sky”, confidence:0.999066531658}, {|name|:”outdoor”, confidence:0.99786490202}, {|name|:”sunset”, confidence:0.880310297012}, {|name|:”distance”, confidence:0.229086950421}}, categories:{{|name|:”outdoor_”, score:0.0078125}, {|name|:”outdoor_waterside”, score:0.5234375}}, |description|:{tags:{”outdoor”, “sunset”, “airplane”, “plane”, “sitting”, “building”, “runway”, “large”, “front”, “water”, “pier”, “top”, “sun”, “track”, “orange”, “light”, “road”, “bridge”, “standing”, “train”, “man”, “jet”, “white”, “city”, “riding”, “red”, “flying”, “bird”, “blue”, “night”, “river”, “tower”, “tarmac”}, captions:{{|text|:“a plane that is in front of a sunset”, confidence:0.493561860724}}}, requestId:”49705b7d-99cb-4234-9af6-b30a32f02ad5″}}

img_0313_resized.png
{{metadata:{width:4032, |format|:”Jpeg”, height:3024}, tags:{{|name|:”indoor”, confidence:0.929384291172}, {|name|:”candle”, confidence:0.877458691597}, {|name|:”birthday”, confidence:0.817751348019}, {|name|:”lit”, confidence:0.53784763813}}, categories:{{|name|:”others_”, score:0.01171875}}, |description|:{tags:{”table”, “indoor”, “cake”, “birthday”, “food”, “sitting”, “lit”, “plate”, “front”, “small”, “top”, “bowl”, “fruit”, “filled”, “chocolate”, “holding”, “man”, “woman”}, captions:{{|text|:“a birthday cake with lit candles”, confidence:0.8700279282}}}, requestId:”62b58a19-2d3a-4f9a-bd54-5aa4460d8385″}}

img_2187_resized.png
{{metadata:{width:3264, format:”Jpeg”, height:2448}, tags:{{name:”bottle”, confidence:0.999316096306}, {name:”table”, confidence:0.987863183022}, {name:”indoor”, confidence:0.968602716923}, {name:”wine”, confidence:0.928377449512}, {name:”alcohol”, confidence:0.846504926682}, {name:”food”, confidence:0.785823404789}, {name:”glass”, confidence:0.782037138939}, {name:”beverage”, confidence:0.776733756065}}, categories:{{name:”drink_”, score:0.90234375}}, description:{tags:{”bottle”, “table”, “indoor”, “wine”, “sitting”, “alcohol”, “food”, “glass”, “beverage”, “cup”, “banana”, “empty”, “top”, “sandwich”, “counter”, “beer”, “phone”, “orange”, “wooden”, “computer”, “laying”}, captions:{{text:“a bottle of wine”, confidence:0.858091829408}}}, requestId:”d2db3a05-fcb0-43bb-8191-89707904918a”}}

r0020016_resized.png
{{metadata:{width:1280, format:”Jpeg”, height:960}, tags:{{name:”sky”, confidence:0.999883055687}, {name:”outdoor”, confidence:0.997511506081}, {name:”person”, confidence:0.910886585712}, {name:”toy”, confidence:0.878364562988}}, categories:{{name:”others_”, score:0.00390625}, {name:”outdoor_”, score:0.01171875}}, description:{tags:{”outdoor”, “person”, “toy”, “thing”, “man”, “white”, “grass”, “standing”, “people”, “field”, “riding”, “jumping”, “doing”, “air”, “holding”, “group”, “trick”, “board”, “statue”, “dog”, “player”, “ramp”}, captions:{{text:“a statue of a man jumping in the air”, confidence:0.153422169506}}}, requestId:”ec5dc466-76c5-47df-b858-2e418ce891a8″}}

r0016164_resized.png
{{metadata:{width:2048, format:”Jpeg”, height:1536}, tags:{{name:”water”, confidence:0.999519586563}, {name:”animal”, confidence:0.993490874767}, {name:”outdoor”, confidence:0.992024421692}, {name:”aquatic mammal”, hint:”animal”, confidence:0.978799343109}, {name:”mammal”, hint:”animal”, confidence:0.914148926735}, {name:”ocean”, confidence:0.804374277592}, {name:”whale”, hint:”animal”, confidence:0.533892810345}, {name:”wave”, confidence:0.527211129665}, {name:”dolphin”, hint:”animal”, confidence:0.340564578772}}, categories:{{name:”outdoor_”, score:0.00390625}}, description:{tags:{”water”, “animal”, “outdoor”, “mammal”, “ocean”, “wave”, “laying”, “brown”, “riding”, “surfing”, “top”, “body”, “lying”, “board”, “large”, “beach”, “floating”, “swimming”, “standing”, “dog”, “young”, “white”, “man”}, captions:{{text:“a dog swimming in the ocean”, confidence:0.604725984086}}}, requestId:”161b6c0f-f3fd-4e06-b4be-d5baa9516e53″}}

AppleScript名:Analyze Image APIで画像認識
– Created 2017-05-03 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4625

set imgFilePath to POSIX path of (choose file of type {“public.jpeg”} with prompt “Select an Image to Analyze”)
set aRes to recogImage(imgFilePath) of me

on recogImage(imgFilePath)
  set reqURLStr to “https://api.projectoxford.ai/vision/v1.0/analyze”
  
set myAPIkey to retAPIkey() of me –API Key 1
  
  
set aRec to {visualFeatures:“Categories,Tags,Description”, details:“Celebrities”, language:“en”}
  
set bURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestPOSTAPIAndParseResultsWithImage(bURL, imgFilePath, myAPIkey) of me
  
set aRESTres to json of aRes
  
set aRESCode to responseCode of aRes
  
set aRESHeader to responseHeader of aRes
  
  
return (aRESTres as list)
end recogImage

–POST methodのREST APIを画像をアップロードしつつ呼ぶ
on callRestPOSTAPIAndParseResultsWithImage(aURL, imgFilePath, myAPIkey)
  –Get Image Contents from file
  
set imgPathStr to current application’s NSString’s stringWithString:imgFilePath
  
set imgData to current application’s NSData’s dataWithContentsOfFile:imgPathStr
  
set postBody to current application’s NSMutableData’s |data|()
  
postBody’s appendData:imgData
  
  
–Request
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setHTTPBody:postBody
  
aRequest’s setValue:“application/octet-stream” forHTTPHeaderField:“Content-Type”
  
aRequest’s setValue:myAPIkey forHTTPHeaderField:“Ocp-Apim-Subscription-Key”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
if dRes = missing value then
    set resCode to -1
    
set resHeaders to {}
  else
    set resCode to (dRes’s statusCode()) as integer
    
–Get Response Header
    
set resHeaders to (dRes’s allHeaderFields()) as record
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPOSTAPIAndParseResultsWithImage

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString())
  
  
return aURL
end retURLwithParams

on retAPIkey()
  return “xXXxXXXXxXXxXXXxXXXXXXXXxXXXXXXx” –API Key 1
end retAPIkey

★Click Here to Open This Script 

2017/04/30 Computer Vision APIで文字認識(OCR)

MicrosoftのCognitive ServicesのREST APIのひとつ、Computer Vision APIを呼び出すAppleScriptです。

MicrosoftのAPIは割とシンプルでオンラインドキュメントも読みやすいため、書くのに3分ぐらいしかかかっていません(既存の別のAPI用のものをend pointとAPI keyとパラメータを書き換えただけ)。

Microsoft Cognitive Servicesのサイトで、開発者アカウント登録を行えば、本APIについては1か月に5,000回まで無料で使用できます(1分間に20回までという制限もあります)。アカウント登録を行い、OCR ServiceをEnableに設定して、本AppleScriptの末尾のretAPIKey()ハンドラ内にAPI Key 1を入力してください(API Keyを記入したScriptを決してそのまま第三者に配布しないでください。あくまでテストと確認用です)。

cognitive_key.png
▲ここの「Key 1」

Vision APIでは、対応画像ファイル形式はJPEG、PNG、GIF、BMP(!)。ファイル容量は4MB以下、50×50ピクセル以上の大きさである必要があります。

img_0320_resized.png

こんな「戦場の絆」のリプレイIDをゲームセンターで撮影して、このIDをもとにYouTubeのリプレイムービーのURLを検索することになるわけですが、このリプレイIDのOCRにComputer Vision APIを使ってみました。

この用途(ランダムに近い英数字の固定桁の組み合わせ、画面上のイメージの認識)については、かなり使える印象です。認識用に使用した画像は、iPhone 7で撮影して写真.appにiCloud経由で転送された写真をそのまま利用しており、ファイルサイズは2.6MB、画像の大きさは4032×3024ピクセルありました。このぐらいだと、認識のためにMicrosoftのクラウドにアップロードするのに少々待たされます。

{boundingBox:”929,1171,746,134″, text:”fy57nt2f“}
{boundingBox:”920,1438,770,135″, text:”3kt5y72v“}

この用途においては、とても誤認識が少ないと感じています。本来取り出したい目的のデータが日本語(ja)ではないので、言語を英数字(en)に指定して呼び出しています。

縦書きの日本語の印刷物の認識だと、もう少し結果が異なってくると思います。一応、この画面についても当初は日本語(ja)で認識していましたが、書体の問題もあり(ちょっと太すぎ?)日本語の文字については誤認識されまくっていました。

AppleScript名:Computer Vision APIで文字認識(OCR)
– Created 2017-04-30 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4622

set imgFilePath to POSIX path of (choose file of type {“public.image”} with prompt “Select an Image to OCR”)

set reqURLStr to “https://api.projectoxford.ai/vision/v1.0/ocr” –Microsoft Cognitive Services OCR endpoint
set myAPIkey to retAPIkey() of me –API Primary Key

–Request parameters
set aRec to {|language|:“en”, detectOrientation:“true”}
set bURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestPOSTAPIAndParseResultsWithImage(bURL, myAPIkey, imgFilePath) of me
set aRESTres to json of aRes

set aRESCode to responseCode of aRes
if aRESCode is not equal to 200 then return false
set aRESHeader to responseHeader of aRes

return ((regions of aRESTres) as list)
–>  {{language:”en”, regions:{{boundingBox:”728,366,1497,2042″, lines:{{boundingBox:”1655,366,186,28″, words:{{boundingBox:”1655,366,186,28″, text:”pea-a-r”}}}, {boundingBox:”1223,962,467,89″, words:{{boundingBox:”1223,962,467,89″, text:”UäLCOD”}}}, {boundingBox:”753,1134,922,171″, words:{{boundingBox:”753,1134,64,156″, text:”1″}, {boundingBox:”929,1171,746,134″, text:”fy57nt2f”}}}, {boundingBox:”1761,1167,458,64″, words:{{boundingBox:”1761,1175,80,53″, text:”20″}, {boundingBox:”1862,1169,169,62″, text:”17/0″}, {boundingBox:”2045,1167,174,60″, text:”4/26″}}}, {boundingBox:”2005,1231,215,52″, words:{{boundingBox:”2005,1231,215,52″, text:”17:55″}}}, {boundingBox:”742,1403,948,170″, words:{{boundingBox:”742,1403,86,160″, text:”2″}, {boundingBox:”920,1438,770,135″, text:”3kt5y72v”}}}, {boundingBox:”1765,1432,459,65″, words:{{boundingBox:”1765,1441,81,53″, text:”20″}, {boundingBox:”1866,1434,170,63″, text:”17/0″}, {boundingBox:”2050,1432,174,61″, text:”4/26″}}}, {boundingBox:”2010,1495,215,54″, words:{{boundingBox:”2010,1495,215,54″, text:”17:47″}}}, {boundingBox:”736,1672,88,176″, words:{{boundingBox:”736,1672,88,176″, text:”3″}}}, {boundingBox:”728,2240,96,168″, words:{{boundingBox:”728,2240,96,168″, text:”5″}}}}}, {boundingBox:”2817,1217,186,320″, lines:{{boundingBox:”2817,1217,175,53″, words:{{boundingBox:”2817,1217,175,53″, text:”6vs6″}}}, {boundingBox:”2826,1483,177,54″, words:{{boundingBox:”2826,1483,177,54″, text:”6vs6″}}}}}}, textAngle:0.0, orientation:”Up”}}

–POST methodのREST APIを画像をアップロードしつつ呼ぶ
on callRestPOSTAPIAndParseResultsWithImage(aURL, anAPIkey, imgFilePath)
  
  
–Get Image Contents from file
  
set imgPathStr to current application’s NSString’s stringWithString:imgFilePath
  
set imgData to current application’s NSData’s dataWithContentsOfFile:imgPathStr
  
set postBody to current application’s NSMutableData’s |data|()
  
postBody’s appendData:imgData
  
  
–Request
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setHTTPBody:postBody
  
aRequest’s setValue:“application/octet-stream” forHTTPHeaderField:“Content-Type”
  
aRequest’s setValue:anAPIkey forHTTPHeaderField:“Ocp-Apim-Subscription-Key”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to (dRes’s statusCode()) as integer
  
  
–Get Response Header
  
set resHeaders to (dRes’s allHeaderFields()) as record
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPOSTAPIAndParseResultsWithImage

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) –as text
  
  
return aURL
end retURLwithParams

on retAPIkey()
  return “xXXXXxXxXxXXXXxxxXXxXXXxxXxxXxxx” –API Primary Key
end retAPIkey

★Click Here to Open This Script 

2017/04/27 テックサイト ごちゃまぜフィードを呼び出す

apitoreREST API「テックサイト ごちゃまぜフィード」を呼び出すAppleScriptです。

apitore側で、以下のテック系Blogを自動巡回して(30分に一度)更新情報を蓄積、新しい順番にソートしたものがREST API経由で提供されています。

巡回サイトは、ライフハッカー、メディア・パブ、スラッシュドット、ギズモード、ゆかしメディア、TechWave、TechDoll.jp、TechCrunch、Reuters、Google Japan Blog、GIGAZINE、Engadget、CNET、All About(オールアバウト) [新着記事]、男子ハック、Techable、ReadWrite Japan、MdN Design Interactive、WIRED.jp、アンドロイドアプリが見つかる!スマホ情報ならオクトバ、ITmedia 総合、ITmedia トップストーリー

となっています(記事執筆時)。

apitoreでは、この「テックサイト ごちゃまぜフィード」のほか、「旅行系」「ニュース」「ブログ 」「デザイン系」などの情報源のフィード系REST APIを提供しています。

本Scriptをテストするためには、apitoreにサインアップしてAccess Tokenを取得して、Script末尾の伏字部分にコピー&ペーストしてください(掲載リストをそのまま実行してもエラーになります)。

Webクローラーを自前で作って定期実行しなくても、Web API経由でクローリングした結果がもらえるというのは、とてもメリットが大きいと思います。AppleScriptではGUIアプリケーションの内部機能からOS内部のCocoa API、shell script、そしてWeb上のREST APIまで直接呼べるので、こんな「なんでもアリ」な環境はなかなかないでしょう。

AppleScript名:テックサイト ごちゃまぜフィード
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4616

set allFeeds to {}

repeat with i from 1 to 100
  set {aRes, maxNum} to getAFeeds(i) of me
  
  
if aRes = false then exit repeat
  
set maxNum to maxNum as number
  
set allFeeds to allFeeds & aRes
  
if (maxNum div 10) i then
    exit repeat
  end if
end repeat

return allFeeds
–>  
(*
{{author:”Ittousai”, sourceTitle:”Engadget Japanese RSS Feed”, title:” 速報:サムスンGalaxy S8発表イベント UNPACKED 2017 (ライブ更新ページ)
“, link:”http://japanese.engadget.com/2017/03/29/galaxy-s8-unpacked-2017/”, pubDate:1.49079606E+12, description:”

“, sourceLink:”http://japanese.engadget.com/rss.xml”},
*)

on getAFeeds(aNum)
  set reqURLStr to “https://api.apitore.com/api/35/feeds/tech”
  
set accessToken to retAccessToken() —Access Token
  
set aRec to {access_token:accessToken, page:(aNum as string)}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
  
set aRESCode to (responseCode of aRes) as integer
  
if aRESCode is not equal to 200 then return {false, false}
  
  
set aRESTres to (json of aRes) as record
  
  
set sentiRes to entries of aRESTres
  
set allNum to num of aRESTres
  
log allNum
  
  
return {sentiRes, allNum}
end getAFeeds

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessToken()
  return “XXXXxxxX-xxxx-XXXx-xxxX-XxxxXxXxxXXx” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2017/03/31 簡単ツイート収集_search

Apitoreの「簡単ツイート収集」REST APIを呼び出して、指定キーワードによるTweet内容の検索を行うAppleScriptです。

実行前にApitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

また、Twitterのサービスとの連携をオンにするために、Apitoreのマイページから「Twitterと連携する」をクリックし、ApitoreをTwitterとアプリ連携してください。

AppleScript名:簡単ツイート収集_search
– Created 2017-03-29 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4572

set aQuery to “#07Itakura”
set aResList to twitterSearchByQuery(aQuery) of me
–> {tweets:{{sentiment:missing value, favoritedCount:409, source:”Echofon“, retweetCount:392, userId:371790917, userName:”機動戦士ガンダム第07板倉小隊”, userScreenName:”07itakura”, text:”【お知らせ】本日放送した板倉小隊特番のアーカイブを明日26日の昼12時から板倉小隊のHPにて1ヵ月限定で配信決定!見逃してしまった方、もう一度見たいという方、ぜひお楽しみに! https://t.co/Q9q6VhiNGU #07itakura”, statusId:8.45606316664021E+17, sentimentScore:missing value, retweeted:false, favorited:false, createdAt:1.490443231E+12, userProfileImageURL:”http://pbs.twimg.com/profile_images/2578804231/hmzlhl1aaxaen8nf8i5b_normal.png”},….

on twitterSearchByQuery(aQuery)
  set reqURLStr to “https://api.apitore.com/api/23/twitter/search”
  
set accessToken to retAccessToken() —Access Token
  
set aRec to {access_token:accessToken, q:aQuery, sinceId:“-1″, maxId:“-1″, iter:“1″}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
set aRESCode to (responseCode of aRes) as integer
  
set aRESTres to (json of aRes) as record
  
  
return aRESTres
end twitterSearchByQuery

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessToken()
  return “XXXXxxxX-xxxx-XXXx-xxxX-XxxxXxXxxXXx” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2016/12/09 gooの形態素解析APIを呼び出す

gooラボが公開している各種APIのうちの、形態素解析APIを呼び出して日本語をparseするAppleScriptです。


supported by goo

利用にあたっては、gooラボAPI利用方法のページからのリンクで、Githubのアカウントを用いて(先に、Githubのアカウントを取得してある必要がある)ひもづけして(リンクをクリックするとひもづけ完了)、Application IDを取得。取得したIDをScript中に記入しておく必要があります。

gooのAPIは見た限りではみんなPOST methodを使って情報をAPIに受け渡す必要があり、少々クセがあります。ただし1つ攻略できてしまえば全部攻略できたも同じ。難易度はそれほど高くはありません(全API攻略済み)。

gooが提供しているAPIの機能レベルについては「他より頑張っている」印象。

 キーワード抽出API:面白いけど、固有名詞辞書の内容次第

 ひらがな化API:ただしい「読み」のひらがなにできるかは固有名詞辞書次第

 固有表現抽出API:

 語句類似度算出API:ウィンドウズとWindows程度の類似度は分かるが、実際に関連性がありそうな単語同士の関連性がそれほど高く評価されない。Apitoreの「単語ベクトル変換【新語対応】」(word2vec)の方が使える印象

 時刻情報正規化API:10年以上前にAppleScriptで作った気がする。ただ、こうして提供されているのは便利だし意義深い

 商品評判要約API:実用性の高そうな要約エンジンは必要。どの程度の長文の要約に耐えられるかがみどころ。実用性は未知数

当の形態素解析APIについては、Webサービスの常で、イレギュラーな人名などの固有名詞を正確に認識することは困難なようです。逆に、Yahoo!の形態素解析辞書に「長野谷」という名前が登録されていること自体が異例といえるでしょう。

AppleScript名:Gooの形態素解析APIを呼び出す
– Created 2016-12-08 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–https://labs.goo.ne.jp/api/jp/morphological-analysis/
–http://piyocast.com/as/archives/4354

set anID to retAPIKey() of me

set reqURLStr to “https://labs.goo.ne.jp/api/morph”
set aPostData to {request_id:“record001″, sentence:“私の名前は長野谷です。”, app_id:anID}
set aRes to callRestPOSTAPIAndParseResults(reqURLStr, aPostData) of me
set aRESCode to (responseCode of aRes) as integer
if aRESCode is not equal to 200 then return false

set aRESHeader to responseHeader of aRes
set aRESTres to json of aRes
–>  (NSDictionary) {request_id:”record001″, word_list:{{{”私”, “名詞”, “ワタシ”}, {”の”, “格助詞”, “ノ”}, {”名前”, “名詞”, “ナマエ”}, {”は”, “連用助詞”, “ハ”}, {”長野”, “名詞”, “ナガノ”}, {”谷”, “名詞接尾辞”, “ダニ”}, {”です”, “判定詞”, “デス”}, {”。”, “句点”, “$”}}}}

–POST methodのREST APIを呼ぶ
on callRestPOSTAPIAndParseResults(aURL, aPostData)
  set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aPostData options:0 |error|:(missing value)
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setHTTPBody:dataJson
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Content-Type”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestPOSTAPIAndParseResults

on retAPIKey()
  return “XXxXXxXXxXxxxXXXxXXxXxXxXXxXxXXXxXxXxxxXxXXXXxXxxXXXxXXXxXXXXxXX” –Goo API Key
end retAPIKey

★Click Here to Open This Script 

2016/12/05 IPIFYで自分のグローバルIPアドレスを取得

ipfy.orgを呼び出して、グローバルIPアドレスを取得するAppleScriptです。

以前に掲載した「自分の(インターネットアクセス時の)IPアドレスを調べる」と同じ働きをするものです。

同じ結果が得られることを確認していますが、こちらの方が高速にアドレスを取得できています。

AppleScript名:IPIFYで自分のグローバルIPアドレスを取得
– Created 2016-12-04 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4343

set reqURLStr to “https://api.ipify.org”
set aRec to {|format|:“json”}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me
set aRESCode to (responseCode of aRes) as integer
if aRESCode is not equal to 200 then error “Server Error”

set aRESHeader to responseHeader of aRes
set aRESTres to |ip| of ((json of aRes) as record)

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

2016/11/30 Livedoorお天気WebサービスAPIで指定地点の天気予報を取得する

livedoorのお天気WebサービスAPIを呼び出して、指定地点コードで指定した地点の天気予報を取得するAppleScriptです。

本サービスを呼び出すのに、開発者登録を行う必要はありません。

例として東京都の東京地方のコード(130010)を指定しています。

現在の緯度・軽度情報を取得して、その情報から住所コードを取得する(逆住所ジオコーディング)と、このようなサービスを利用して「現在位置の天気予報を取得する」という処理ができます。

AppleScript名:Livedoorお天気WebサービスAPIで指定地点の天気予報を取得する
– Created 2016-10-29 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://weather.livedoor.com/weather_hacks/webservice
–http://piyocast.com/as/archives/4337

set reqURLStr to “http://weather.livedoor.com/forecast/webservice/json/v1″

set aRec to {city:“130010″}
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESCode to responseCode of aRes
if aRESCode is not equal to 200 then error “Server Error”

set aRESHeader to responseHeader of aRes

set aRESTres to (json of aRes) as record
return aRESTres
(*
{location:{prefecture:”東京都”, city:”東京”, area:”関東”}, publicTime:”2016-11-30T17:00:00+0900″, title:”東京都 東京 の天気”, copyright:{provider:{{link:”http://tenki.jp/”, |name|:”日本気象協会”}}, title:”(C) LINE Corporation”, image:{height:26, title:”livedoor 天気情報”, width:118, |url|:”http://weather.livedoor.com/img/cmn/livedoor.gif”, link:”http://weather.livedoor.com/”}, link:”http://weather.livedoor.com/”}, link:”http://weather.livedoor.com/area/forecast/130010″, forecasts:{{|date|:”2016-11-30″, dateLabel:”今日”, temperature:{min:missing value, max:missing value}, image:{title:”曇り”, width:50, |url|:”http://weather.livedoor.com/img/icon/8.gif”, height:31}, telop:”曇り”}, {|date|:”2016-12-01″, dateLabel:”明日”, temperature:{min:{celsius:”6″, fahrenheit:”42.8″}, max:{celsius:”14″, fahrenheit:”57.2″}}, image:{title:”曇時々雨”, width:50, |url|:”http://weather.livedoor.com/img/icon/10.gif”, height:31}, telop:”曇時々雨”}, {|date|:”2016-12-02″, dateLabel:”明後日”, temperature:{min:missing value, max:missing value}, image:{title:”晴時々曇”, width:50, |url|:”http://weather.livedoor.com/img/icon/2.gif”, height:31}, telop:”晴時々曇”}}, |description|:{|text|:” 高気圧が三陸沖を東へ移動しています。一方、黄海付近は気圧の谷となっ
ています。

【関東甲信地方】
関東甲信地方は、気圧の谷や湿った空気の影響で曇りとなっています。

30日は、曇りで、気圧の谷や湿った空気の影響で、夜には雨の降る所が
あるでしょう。

12月1日は、気圧の谷の影響により、曇りで、朝にかけて雨の所が多い
見込みです。伊豆諸島では朝にかけて雷を伴う所があるでしょう。

関東近海では、30日から12月1日にかけて波が高いでしょう。船舶は
高波に注意してください。

【東京地方】
30日は、曇りで、夜遅くは雨の降る所があるでしょう。
12月1日は、曇りで、明け方まで雨となる見込みです。”, publicTime:”2016-11-30T16:34:00+0900″}, pinpointLocations:{{link:”http://weather.livedoor.com/area/forecast/1310100″, |name|:”千代田区”}, {link:”http://weather.livedoor.com/area/forecast/1310200″, |name|:”中央区”}, {link:”http://weather.livedoor.com/area/forecast/1310300″, |name|:”港区”}, {link:”http://weather.livedoor.com/area/forecast/1310400″, |name|:”新宿区”}, {link:”http://weather.livedoor.com/area/forecast/1310500″, |name|:”文京区”}, {link:”http://weather.livedoor.com/area/forecast/1310600″, |name|:”台東区”}, {link:”http://weather.livedoor.com/area/forecast/1310700″, |name|:”墨田区”}, {link:”http://weather.livedoor.com/area/forecast/1310800″, |name|:”江東区”}, {link:”http://weather.livedoor.com/area/forecast/1310900″, |name|:”品川区”}, {link:”http://weather.livedoor.com/area/forecast/1311000″, |name|:”目黒区”}, {link:”http://weather.livedoor.com/area/forecast/1311100″, |name|:”大田区”}, {link:”http://weather.livedoor.com/area/forecast/1311200″, |name|:”世田谷区”}, {link:”http://weather.livedoor.com/area/forecast/1311300″, |name|:”渋谷区”}, {link:”http://weather.livedoor.com/area/forecast/1311400″, |name|:”中野区”}, {link:”http://weather.livedoor.com/area/forecast/1311500″, |name|:”杉並区”}, {link:”http://weather.livedoor.com/area/forecast/1311600″, |name|:”豊島区”}, {link:”http://weather.livedoor.com/area/forecast/1311700″, |name|:”北区”}, {link:”http://weather.livedoor.com/area/forecast/1311800″, |name|:”荒川区”}, {link:”http://weather.livedoor.com/area/forecast/1311900″, |name|:”板橋区”}, {link:”http://weather.livedoor.com/area/forecast/1312000″, |name|:”練馬区”}, {link:”http://weather.livedoor.com/area/forecast/1312100″, |name|:”足立区”}, {link:”http://weather.livedoor.com/area/forecast/1312200″, |name|:”葛飾区”}, {link:”http://weather.livedoor.com/area/forecast/1312300″, |name|:”江戸川区”}, {link:”http://weather.livedoor.com/area/forecast/1320100″, |name|:”八王子市”}, {link:”http://weather.livedoor.com/area/forecast/1320200″, |name|:”立川市”}, {link:”http://weather.livedoor.com/area/forecast/1320300″, |name|:”武蔵野市”}, {link:”http://weather.livedoor.com/area/forecast/1320400″, |name|:”三鷹市”}, {link:”http://weather.livedoor.com/area/forecast/1320500″, |name|:”青梅市”}, {link:”http://weather.livedoor.com/area/forecast/1320600″, |name|:”府中市”}, {link:”http://weather.livedoor.com/area/forecast/1320700″, |name|:”昭島市”}, {link:”http://weather.livedoor.com/area/forecast/1320800″, |name|:”調布市”}, {link:”http://weather.livedoor.com/area/forecast/1320900″, |name|:”町田市”}, {link:”http://weather.livedoor.com/area/forecast/1321000″, |name|:”小金井市”}, {link:”http://weather.livedoor.com/area/forecast/1321100″, |name|:”小平市”}, {link:”http://weather.livedoor.com/area/forecast/1321200″, |name|:”日野市”}, {link:”http://weather.livedoor.com/area/forecast/1321300″, |name|:”東村山市”}, {link:”http://weather.livedoor.com/area/forecast/1321400″, |name|:”国分寺市”}, {link:”http://weather.livedoor.com/area/forecast/1321500″, |name|:”国立市”}, {link:”http://weather.livedoor.com/area/forecast/1321800″, |name|:”福生市”}, {link:”http://weather.livedoor.com/area/forecast/1321900″, |name|:”狛江市”}, {link:”http://weather.livedoor.com/area/forecast/1322000″, |name|:”東大和市”}, {link:”http://weather.livedoor.com/area/forecast/1322100″, |name|:”清瀬市”}, {link:”http://weather.livedoor.com/area/forecast/1322200″, |name|:”東久留米市”}, {link:”http://weather.livedoor.com/area/forecast/1322300″, |name|:”武蔵村山市”}, {link:”http://weather.livedoor.com/area/forecast/1322400″, |name|:”多摩市”}, {link:”http://weather.livedoor.com/area/forecast/1322500″, |name|:”稲城市”}, {link:”http://weather.livedoor.com/area/forecast/1322700″, |name|:”羽村市”}, {link:”http://weather.livedoor.com/area/forecast/1322800″, |name|:”あきる野市”}, {link:”http://weather.livedoor.com/area/forecast/1322900″, |name|:”西東京市”}, {link:”http://weather.livedoor.com/area/forecast/1330300″, |name|:”瑞穂町”}, {link:”http://weather.livedoor.com/area/forecast/1330500″, |name|:”日の出町”}, {link:”http://weather.livedoor.com/area/forecast/1330700″, |name|:”檜原村”}, {link:”http://weather.livedoor.com/area/forecast/1330800″, |name|:”奥多摩町”}}}
*)

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

★Click Here to Open This Script 

2016/11/30 Yahoo! 形態素解析APIで日本語テキストを解釈

Yahoo!の形態素解析APIで、日本語テキストを形態素解析するAppleScriptです。

Yahoo!に開発者登録(無料)して、アプリケーションIDを取得し、リスト中のretAccessKey()ハンドラにアプリケーションIDを記入すると実行可能です。

単語ごとに「品詞」「よみがな」などを取得できます。辞書が充実しているためか、自分の名前も正しく単語として認識されました。

形態素解析エンジンはローカルに置いて、辞書をカスタマイズするべきだと思っていますが、Yahoo!のAPI(が備えている辞書)だとそれなりに使える感じがします。

Yahoo!のテキスト解析系APIはひととおり試してみましたが、

 校正支援API:漢字の誤変換は指摘してくれるが、助詞の間違いなどは指摘してくれない
 キーフレーズ抽出API:使えるかどうか評価が難しい
 かな漢字変換API:呼んで使えるが、使い道が難しい

この形態素解析APIが一番実用度が高そうな感じがします。

AppleScript名:Yahoo! 形態素解析APIで日本語テキストを解釈
– Created 2016-11-25 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”

–http://developer.yahoo.co.jp/webapi/jlp/ma/v1/parse.html

–日本語形態素解析Web APIは、24時間以内で1つのアプリケーションIDにつき50000件のリクエストが上限となっています。また、1リクエストの最大サイズを100KBに制限 しています。

property dictStack : missing value – stack to hold array of dictionaries
property textInProgress : “” – string to collect text as it is found
property anError : missing value – if we get an error, store it here

set japaneseText to “私の名前は長野谷です。”

set reqURLStr to “http://jlp.yahooapis.jp/MAService/V1/parse”

set aKey to retAccessKey() of me

set aRec to {|key|:aKey, sentence:japaneseText, results:“ma”, page:“1″, output:“xml”, appid:aKey}
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseXMLResults(aURL) of me

set aRESCode to responseCode of aRes
if aRESCode is not equal to 200 then return false

set aRESHeader to responseHeader of aRes
set aXMLres to (xml of aRes)

set parsedList to (aXMLres’s valueForKeyPath:“ResultSet.ma_result.word_list.word.surface.contents”) as list
–>  {”私”, “の”, “名前”, “は”, “長野谷”, “です”, “。”}

set yomiganaList to (aXMLres’s valueForKeyPath:“ResultSet.ma_result.word_list.word.reading.contents”) as list
–>  {”わたし”, “の”, “なまえ”, “は”, “ながのや”, “です”, “。”}

set kindList to (aXMLres’s valueForKeyPath:“ResultSet.ma_result.word_list.word.pos.contents”) as list
–>  {”名詞”, “助詞”, “名詞”, “助詞”, “名詞”, “助動詞”, “特殊”}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseXMLResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set aXmlRec to my makeRecordWithXML:resStr
  
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {xml:aXmlRec, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseXMLResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessKey()
  return “xxXxxxXxXXxxxXXXXXXXXXXXXXXxXXXxxxXXxXXxxXXxxxXXXxxXXXX-” –Yahoo! API Key
end retAccessKey

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

——–XMLParse Lib

on makeRecordWithXML:xmlString
  set my dictStack to current application’s NSMutableArray’s array() – empty mutable array
  
set anEmpty to current application’s NSMutableDictionary’s |dictionary|()
  (
my dictStack)’s addObject:anEmpty – add empty mutable dictionary
  
set my textInProgress to current application’s NSMutableString’s |string|() – empty mutable string
  
  
set anNSString to current application’s NSString’s stringWithString:xmlString
  
set theData to anNSString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
  
set theNSXMLParser to current application’s NSXMLParser’s alloc()’s initWithData:theData
  
  
theNSXMLParser’s setDelegate:me
  
  
set theResult to theNSXMLParser’s parse()
  
if theResult then – went OK, get first item on stack
    return ((my dictStack)’s firstObject()) –as record
  else
    error (my anError’s localizedDescription() as text)
  end if
end makeRecordWithXML:

– this is an XML parser delegate method. Called when new element found
on parser:anNSXMLParser didStartElement:elementName namespaceURI:aString qualifiedName:qName attributes:aRecord
  set parentDict to my dictStack’s lastObject()
  
set childDict to current application’s NSMutableDictionary’s |dictionary|()
  
if aRecord’s |count|() > 0 then
    childDict’s setValue:aRecord forKey:“attributes”
  end if
  
  
set existingValue to parentDict’s objectForKey:elementName
  
  
if existingValue is not missing value then
    if (existingValue’s isKindOfClass:(current application’s NSMutableArray)) as boolean then
      set theArray to existingValue
    else
      set theArray to current application’s NSMutableArray’s arrayWithObject:existingValue
      
parentDict’s setObject:theArray forKey:elementName
    end if
    
    
theArray’s addObject:childDict
  else
    parentDict’s setObject:childDict forKey:elementName
  end if
  
  (
my dictStack)’s addObject:childDict
end parser:didStartElement:namespaceURI:qualifiedName:attributes:

– this is an XML parser delegate method. Called at the end of an element
on parser:anNSXMLParser didEndElement:elementName namespaceURI:aString qualifiedName:qName
  if my textInProgress’s |length|() > 0 then
    set dictInProgress to my dictStack’s lastObject()
    
dictInProgress’s setObject:textInProgress forKey:“contents”
    
set my textInProgress to current application’s NSMutableString’s |string|()
  end if
  
  
my dictStack’s removeLastObject()
end parser:didEndElement:namespaceURI:qualifiedName:

– this is an XML parser delegate method. Called when string is found. May be called repeatedly
on parser:anNSXMLParser foundCharacters:aString
  if (aString’s stringByTrimmingCharactersInSet:(current application’s NSCharacterSet’s whitespaceAndNewlineCharacterSet()))’s |length|() > 0 then
    (my textInProgress)’s appendString:aString
  end if
end parser:foundCharacters:

– this is an XML parser delegate method. Called when there’s an error
on parser:anNSXMLParser parseErrorOccurred:anNSError
  set my anError to anNSError
end parser:parseErrorOccurred:

★Click Here to Open This Script 

2016/11/17 ぐるなびの「レストラン検索API」でレストランを現在位置から3km以内でキーワード検索する

ぐるなびの「レストラン検索API」で、レストランを現在位置(CoreLocation経由で取得)から3km以内でキーワードを指定して検索するAppleScriptです。

実行のためには、ぐるなびAPIの「新規アカウント発行」より申請を行い、アクセスキーを取得してください(申請無料)。取得したアクセスキーをプログラム中のretAccessKey()ハンドラ中に記述しておいてください。また、現在位置取得のためにWiFiをオンにして実行する必要があります。初回実行時になかなか位置取得機能がイネーブルにならずに焦りました。

ぐるなびでは、「レストラン検索API」「多言語版レストラン検索API」「応援口コミAPI」「エリアマスタ取得API」「都道府県マスタAPI」「エリアLマスタAPI」「エリアMマスタAPI」「エリアSマスタAPI」「大業態マスタ取得API」「小業態マスタ取得API」などのAPIを公開しているため、さまざまなアプリケーション上のデータと組み合わせて有効に利用できると思います。

下世話なところでは、Webサイトから検索すると無駄なデータが多い割に一度に検索できるデータ件数が少ないので、(Webブラウザではなく)スクリプトエディタ上でしぼりこみ検索を行っていたりします。

プログラムの難易度は高くないのですが、ふだんライブラリ化している部品を掲載のために1リスト中に展開しています。内容が素朴な割にプログラムが長くなってしまっていますが、AppleScriptObjCの宿命といったところでしょうか。

AppleScript名:ぐるなびの「レストラン検索API」でレストランを現在位置から3km以内でキーワード検索する
– Created 2016-10-29 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “CoreLocation”
–use curLocLib : script “curLocationLib”
–http://api.gnavi.co.jp/api/manual/restsearch/

–http://piyocast.com/as/archives/4320

–from curLocationLib
property locationManager : missing value
property curLatitude : 0
property curLongitude : 0
–from curLocationLib

set reqURLStr to “http://api.gnavi.co.jp/RestSearchAPI/20150630/”

–現在地の緯度、経度情報を取得する
set {aLat, aLong} to getCurrentLocation() of me
set aKey to retAccessKey() of me

–指定位置から3km以内の、キーワード”とんかつ”でヒットするレストランをピックアップ
set aRec to {keyid:aKey, |format|:“json”, latitude:aLat as string, longitude:aLong as string, range:“5″, freeword:“とんかつ”}
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseResults(aURL) of me
set aRESCode to responseCode of aRes
if aRESCode is not equal to 200 then return false
set aRESHeader to responseHeader of aRes
set aRESTres to (json of aRes)
–>  {@attributes:{api_version:”20150630″}, total_hit_count:”24″, page_offset:”1″, rest:{{name_kana:”アサノ”, address:”〒179-0074 東京都練馬区春日町6-12-5 “, party:{}, credit_card:{}, url:”http://r.gnavi.co.jp/nhefra550000/?ak=Q%2BN8L78dCT2RgZUYqtECBTRS3%2BEtZ0qY0cmsoQMxWqU%3D”, code:{category_name_l:{”和食”, {@attributes:{order:”1″}}}, areaname:”関東”, areacode:”AREA110″, prefname:”東京都”, prefcode:”PREF13″, areacode_s:”AREAS2225″, areaname_s:”光が丘”, category_code_s:{”RSFST01005″, {@attributes:{order:”1″}}}, category_code_l:{”RSFST01000″, {@attributes:{order:”1″}}}, category_name_s:{”とんかつ(トンカツ)”, {@attributes:{order:”1″}}}}, tel:”03-3999-4099″, parking_lots:{}, lunch:{}, fax:{}, @attributes:{order:”0″}, latitude:”35.747856″, category:”とんかつ”, url_mobile:”http://mobile.gnavi.co.jp/shop/5421186/?ak=Q%2BN8L78dCT2RgZUYqtECBTRS3%2BEtZ0qY0cmsoQMxWqU%3D”, name:”あさの “, holiday:{}, flags:{mobile_site:”1″, mobile_coupon:”0″, pc_coupon:”0″}, id:”5421186″, coupon_url:{mobile:{}, pc:{}}, access:{walk:”徒歩7″, line:”都営大江戸線(放射部)”, station_exit:”A3口”, note:{}, station:”練馬春日町駅”}, tel_sub:{}, longitude:”139.637081″, pr:{pr_long:{}, pr_short:{}}, budget:{}, e_money:{}, opentime:{}, update_date:”2015-10-14 14:14:02″, image_url:{shop_image1:{}, shop_image2:{}, qrcode:”http://r.gnst.jp/tool/qr/?id=5421186&q=6″}}, ….

set aNameRes to (aRESTres’s valueForKeyPath:“rest.name”) as list
–>  {”あさの “, “CoCo壱番屋 西武中村橋駅前通店”, “とんかつ かつ富士 “, “華屋与兵衛 豊島園店”, “華屋与兵衛 春日町店”, “とんかつ和幸 西武練馬駅店 “, “とんかつ和幸 IMA光が丘店 “, “松乃家 練馬店”, “とん陣 “, “よしだ “}

set aAddressRes to (aRESTres’s valueForKeyPath:“rest.address”) as list
–>  {”〒179-0074 東京都練馬区春日町6-12-5 “, “〒176-0023 東京都練馬区中村北3-22-10 友伸ビル1F”, “〒176-0021 東京都練馬区貫井3-14-5 “, “〒179-0085 東京都練馬区早宮4-39″, “〒179-0074 東京都練馬区春日町2-7-18″, “〒176-0001 東京都練馬区練馬1-3-5 西武池袋線練馬駅下 2F”, “〒179-0072 東京都練馬区光が丘5-1-1 光が丘IMA内 3F”, “〒176-0012 東京都練馬区豊玉北5-19-12″, “〒176-0012 東京都練馬区豊玉北5-18-7 “, “〒179-0073 東京都練馬区田柄1-4-24 “}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessKey()
  return “xxXxXXxxXxxxXxxXXxXXxXXxXxXXxxXX” –ぐるなびAPI アカウントのアクセスキー
end retAccessKey

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

——————————————————–
— curLocationLib

on getCurrentLocation()
  
  
set locationManager to current application’s CLLocationManager’s alloc()’s init()
  
  
set locE to locationManager’s locationServicesEnabled()
  
if (locE as boolean) = true then
    locationManager’s setDelegate:me
    
locationManager’s setDesiredAccuracy:(current application’s kCLLocationAccuracyNearestTenMeters)
    
locationManager’s setDistanceFilter:500
    
locationManager’s startUpdatingLocation()
  else
    return false –error in init
  end if
  
  
set hitF to false
  
repeat 3000 times
    if {curLatitude, curLongitude} is not equal to {0, 0} then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
  end repeat
  
  
if hitF = false then return false
  
return {curLatitude, curLongitude}
  
end getCurrentLocation

on locationManager:manager didUpdateLocations:locations
  –Listing 1-3 Processing an incoming location event
  
set location to (locations’s lastObject())
  
set eventDate to (location’s timestamp())
  
set howRecent to (eventDate’s timeIntervalSinceNow())
  
  
–Calc ABS
  
set howRecent to howRecent as real
  
set howRecent to absNum(howRecent)
  
  
if howRecent < 15.0 then
    set alt to location’s altitude
    
set aSpeed to location’s speed
    
set aCourse to location’s course –North:0, East:90, South:180, West:270
    
set theDescription to location’s |description|()
    
set anNSScanner to current application’s NSScanner’s scannerWithString:theDescription
    
anNSScanner’s setCharactersToBeSkipped:(current application’s NSCharacterSet’s characterSetWithCharactersInString:“< ,")
    
set {theResult, aLat} to anNSScanner’s scanDouble:(reference)
    
set {theResult, aLng} to anNSScanner’s scanDouble:(reference)
    
    
copy {aLat, aLng} to {my curLatitude, my curLongitude}
  else
    locationManager’s stopUpdatingLocation()
  end if
end locationManager:didUpdateLocations:

on locationManager:anCLLocationManager didFailWithError:anNSError
  display dialog (anNSError’s localizedDescription() as text)
end locationManager:didFailWithError:

on absNum(aNum)
  if aNum > 0 then
    return aNum
  else
    return (aNum * -1)
  end if
end absNum

★Click Here to Open This Script 

2016/11/04 Wikipedia APIで記事の問い合わせを行う

WikipediaのAPIを呼び出して、指定記事の内容を取得するAppleScriptです。

自分で書いた記事の本文を取得して、本文中のURLを抽出し、それらが継続して存在しているかどうかを自動でチェックする、といった用途に使えると思います。

AppleScript名:Wikipedia APIで記事の問い合わせを行う
– Created 2016-11-04 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
–https://www.mediawiki.org/wiki/API:Main_page/ja
–http://piyocast.com/as/archives/4302

–set reqURLStr to "https://en.wikipedia.org/w/api.php"–English Version
set reqURLStr to "https://jp.wikipedia.org/w/api.php" –Japanese Version

set aRec to {action:"query", titles:"AppleScript", |prop|:"revisions", rvprop:"content", |format|:"json"}
–set aRec to {action:"query", titles:"AppleScript|Mac OS X|Objective-C", |prop|:"revisions", rvprop:"content", |format|:"json"}
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–> {query:{pages:{2954:{pageid:2954, title:"AppleScript", revisions:{{contentformat:"text/x-wiki", *:"{{Infobox プログラミング言語|名前 = AppleScript ……., contentmodel:"wikitext"}}, ns:0}}}, batchcomplete:""}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

★Click Here to Open This Script 

2016/11/02 connpassイベントサーチAPIで検索を行う

connpassイベントサーチAPIで検索を行うAppleScriptです。

エンジニアをつなぐIT勉強会支援プラットフォームであるconnpassのサイトでは、イベントサーチAPIを用意しており、

  event_id(イベントID)
  keyword(キーワード (AND))
  keyword_or(キーワード (OR))
  ym(イベント開催年月)
  ymd(イベント開催年月日)
  nickname(参加者のニックネーム)
  owner_nickname(管理者のニックネーム)
  series_id(グループID)

などの検索キーをもとにイベントを検索できます。あー、自分の登録したイベントが見つかってよかったー、という確認です。

# 先日、connpassイベントサーチAPIがhttps経由でのアクセスに変更されたため、本リストも修正しておきました

AppleScript名:connpassイベントサーチAPIで検索を行うv2
– Created 2016-10-29 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
–http://connpass.com/about/api/
–http://piyocast.com/as/archives/4300

set reqURLStr to "https://connpass.com/api/v1/event/"

set aRec to {keyword:"AppleScript", ym:"201611"} –サーチクエリーと対象月
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>
(*
{results_available:1, results_start:1, |events|:{{place:"マイ・スペース MS&BB 池袋西武横店 1号室", event_url:"http://ashole.connpass.com/event/44103/", accepted:2, title:"AppleScript本フィードバック会", limit:7, event_type:"participation", owner_id:64136, ended_at:"2016-11-26T20:30:00+09:00", updated_at:"2016-11-01T09:22:15+09:00", lon:"139.711383200000", waiting:0, event_id:44103, hash_tag:"AppleScript,Mac,macOS,Mac OS X", owner_nickname:"Piyomaru", lat:"35.726486900000", started_at:"2016-11-26T18:30:00+09:00", owner_display_name:"Piyomaru", catch:"「AppleScript最新リファレンス」「AppleScript最新10大技術」についての解説", series:{|url|:"http://ashole.connpass.com/", |id|:3041, title:"AppleScriptの穴"}, address:"〒171-0022 東京都豊島区南池袋1-16-20(ぬかりやビル2階)", |description|:"<p>macOS標準装備で、GUIアプリケーションを操作できるマクロ言語「AppleScript」、その20年以上の歴史をまとめ、最新情報を盛り込んだ電子書籍「AppleScript最新リファレンス」「AppleScript 最新10大技術」を発行いたしました。</p>\n<p>・電子書籍オンライン販売URL\n<a href=\"https://piyomarusoft.booth.pm\" rel=\"nofollow\">https://piyomarusoft.booth.pm</a></p>\n<p>これらの本について、分からない点やもっと知りたい点について、筆者本人と直接お話できる場を設けました。</p>\n<p>参加資格は、AppleScriptを実際に使っている方、興味を持っている方で、筆者の書籍を実際に購入した、あるいは購入しようと考えている方です。事前に内容を読んであることが望ましいです。</p>\n<p>筆者Blog「AppleScriptの穴」\n<a href=\"http://piyocast.com/as/\" rel=\"nofollow\">http://piyocast.com/as/</a></p>"}}, results_returned:1}
*)

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

★Click Here to Open This Script 

2016/11/01 日本語形態素解析【新語対応】

Apitoreの「日本語形態素解析【新語対応】」REST APIを呼び出して、指定の日本語の形態素解析を行うAppleScriptです。使用している形態素解析エンジンはJavaベースの「Kuromoji」とのこと。

IPADICを辞書に使うバージョンと、IPADIC NEologdを辞書に使うバージョンの2つのAPIがあり、それぞれ同じ文章で形態素解析を行っています。NEologdのほうは「きゃりーぱみゅぱみゅ」などの新しめの固有名詞が登録されており、単語として認識します。

その一方で、やはり人名などの固有名詞(例:自分のなまえ)が正しく単語として認識されないと困るので、形態素解析についてはローカルの日本語入力IMやアドレスブックに登録してある人名との連携は欠かせないと思うものであります(IMの学習は「間違っている」ケースもあるので難しいところですが)。

実行前にapitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

AppleScript名:日本語形態素解析【新語対応】_ipadic
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4299

set reqURLStr to “https://api.apitore.com/api/7/kuromoji-ipadic/tokenize”
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |text|:“私の名前はきゃりーぱみゅぱみゅです。”}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {startTime:”1477627346754″, tokens:{{partOfSpeechLevel1:”名詞”, baseForm:”私”, pronunciation:”ワタシ”, position:0, partOfSpeechLevel3:”一般”, reading:”ワタシ”, surface:”私”, known:true, allFeatures:”名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ”, conjugationType:”*”, partOfSpeechLevel2:”代名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “代名詞”, “一般”, “*”, “*”, “*”, “私”, “ワタシ”, “ワタシ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”の”, pronunciation:”ノ”, position:1, partOfSpeechLevel3:”*”, reading:”ノ”, surface:”の”, known:true, allFeatures:”助詞,連体化,*,*,*,*,の,ノ,ノ”, conjugationType:”*”, partOfSpeechLevel2:”連体化”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “連体化”, “*”, “*”, “*”, “*”, “の”, “ノ”, “ノ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”名前”, pronunciation:”ナマエ”, position:2, partOfSpeechLevel3:”*”, reading:”ナマエ”, surface:”名前”, known:true, allFeatures:”名詞,一般,*,*,*,*,名前,ナマエ,ナマエ”, conjugationType:”*”, partOfSpeechLevel2:”一般”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “一般”, “*”, “*”, “*”, “*”, “名前”, “ナマエ”, “ナマエ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”動詞”, baseForm:”はく”, pronunciation:”ハキャ”, position:4, partOfSpeechLevel3:”*”, reading:”ハキャ”, surface:”はきゃ”, known:true, allFeatures:”動詞,自立,*,*,五段・カ行イ音便,仮定縮約1,はく,ハキャ,ハキャ”, conjugationType:”五段・カ行イ音便”, partOfSpeechLevel2:”自立”, conjugationForm:”仮定縮約1”, allFeaturesArray:{”動詞”, “自立”, “*”, “*”, “五段・カ行イ音便”, “仮定縮約1”, “はく”, “ハキャ”, “ハキャ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助動詞”, baseForm:”り”, pronunciation:”リ”, position:7, partOfSpeechLevel3:”*”, reading:”リ”, surface:”り”, known:true, allFeatures:”助動詞,*,*,*,文語・リ,基本形,り,リ,リ”, conjugationType:”文語・リ”, partOfSpeechLevel2:”*”, conjugationForm:”基本形”, allFeaturesArray:{”助動詞”, “*”, “*”, “*”, “文語・リ”, “基本形”, “り”, “リ”, “リ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”*”, pronunciation:”*”, position:8, partOfSpeechLevel3:”一般”, reading:”*”, surface:”ー”, known:false, allFeatures:”名詞,固有名詞,一般,*,*,*,*,*,*”, conjugationType:”*”, partOfSpeechLevel2:”固有名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “固有名詞”, “一般”, “*”, “*”, “*”, “*”, “*”, “*”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”*”, pronunciation:”*”, position:9, partOfSpeechLevel3:”*”, reading:”*”, surface:”ぱみゅぱみゅです”, known:false, allFeatures:”名詞,一般,*,*,*,*,*,*,*”, conjugationType:”*”, partOfSpeechLevel2:”一般”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “一般”, “*”, “*”, “*”, “*”, “*”, “*”, “*”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”記号”, baseForm:”。”, pronunciation:”。”, position:17, partOfSpeechLevel3:”*”, reading:”。”, surface:”。”, known:true, allFeatures:”記号,句点,*,*,*,*,。,。,。”, conjugationType:”*”, partOfSpeechLevel2:”句点”, conjugationForm:”*”, allFeaturesArray:{”記号”, “句点”, “*”, “*”, “*”, “*”, “。”, “。”, “。”}, partOfSpeechLevel4:”*”}}, endTime:”1477627346755″, log:”", processTime:”1″}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json;charset=UTF-8″, Access-Control-Allow-Origin:”*”, Pragma:”no-cache”, X-XSS-Protection:”1; mode=block, 1; mode=block”, Server:”nginx/1.10.1″, Transfer-Encoding:”Identity”, Expires:”0″, Cache-Control:”no-cache, no-store, max-age=0, must-revalidate”, Date:”Thu, 27 Oct 2016 03:19:17 GMT”, Strict-Transport-Security:”max-age=31536000; includeSubDomains;”, Connection:”keep-alive”, X-Content-Type-Options:”nosniff, nosniff”, X-Frame-Options:”DENY, SAMEORIGIN”}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessToken()
  return “XXxXXXxx-XXxX-XXXx-XXxX-XXxxXxXXXxXX” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

AppleScript名:日本語形態素解析【新語対応】_ipadic_neologd
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4299

set reqURLStr to “https://api.apitore.com/api/7/kuromoji-ipadic-neologd/tokenize”
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |text|:“私の名前はきゃりーぱみゅぱみゅです。”}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {startTime:”1477998343747″, tokens:{{partOfSpeechLevel1:”名詞”, baseForm:”私”, pronunciation:”ワタシ”, position:0, partOfSpeechLevel3:”一般”, reading:”ワタシ”, surface:”私”, known:true, allFeatures:”名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ”, conjugationType:”*”, partOfSpeechLevel2:”代名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “代名詞”, “一般”, “*”, “*”, “*”, “私”, “ワタシ”, “ワタシ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”の”, pronunciation:”ノ”, position:1, partOfSpeechLevel3:”*”, reading:”ノ”, surface:”の”, known:true, allFeatures:”助詞,連体化,*,*,*,*,の,ノ,ノ”, conjugationType:”*”, partOfSpeechLevel2:”連体化”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “連体化”, “*”, “*”, “*”, “*”, “の”, “ノ”, “ノ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”名前”, pronunciation:”ナマエ”, position:2, partOfSpeechLevel3:”*”, reading:”ナマエ”, surface:”名前”, known:true, allFeatures:”名詞,一般,*,*,*,*,名前,ナマエ,ナマエ”, conjugationType:”*”, partOfSpeechLevel2:”一般”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “一般”, “*”, “*”, “*”, “*”, “名前”, “ナマエ”, “ナマエ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”は”, pronunciation:”ワ”, position:4, partOfSpeechLevel3:”*”, reading:”ハ”, surface:”は”, known:true, allFeatures:”助詞,係助詞,*,*,*,*,は,ハ,ワ”, conjugationType:”*”, partOfSpeechLevel2:”係助詞”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “係助詞”, “*”, “*”, “*”, “*”, “は”, “ハ”, “ワ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”きゃりーぱみゅぱみゅ”, pronunciation:”キャリーパミュパミュ”, position:5, partOfSpeechLevel3:”一般”, reading:”キャリーパミュパミュ”, surface:”きゃりーぱみゅぱみゅ”, known:true, allFeatures:”名詞,固有名詞,一般,*,*,*,きゃりーぱみゅぱみゅ,キャリーパミュパミュ,キャリーパミュパミュ”, conjugationType:”*”, partOfSpeechLevel2:”固有名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “固有名詞”, “一般”, “*”, “*”, “*”, “きゃりーぱみゅぱみゅ”, “キャリーパミュパミュ”, “キャリーパミュパミュ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助動詞”, baseForm:”です”, pronunciation:”デス”, position:15, partOfSpeechLevel3:”*”, reading:”デス”, surface:”です”, known:true, allFeatures:”助動詞,*,*,*,特殊・デス,基本形,です,デス,デス”, conjugationType:”特殊・デス”, partOfSpeechLevel2:”*”, conjugationForm:”基本形”, allFeaturesArray:{”助動詞”, “*”, “*”, “*”, “特殊・デス”, “基本形”, “です”, “デス”, “デス”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”記号”, baseForm:”。”, pronunciation:”。”, position:17, partOfSpeechLevel3:”*”, reading:”。”, surface:”。”, known:true, allFeatures:”記号,句点,*,*,*,*,。,。,。”, conjugationType:”*”, partOfSpeechLevel2:”句点”, conjugationForm:”*”, allFeaturesArray:{”記号”, “句点”, “*”, “*”, “*”, “*”, “。”, “。”, “。”}, partOfSpeechLevel4:”*”}}, endTime:”1477998343748″, |log|:”", processTime:”1″}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json;charset=UTF-8″, Access-Control-Allow-Origin:”*”, Pragma:”no-cache”, X-XSS-Protection:”1; mode=block, 1; mode=block”, Server:”nginx/1.10.1″, Transfer-Encoding:”Identity”, Expires:”0″, Cache-Control:”no-cache, no-store, max-age=0, must-revalidate”, Date:”Thu, 27 Oct 2016 03:19:17 GMT”, Strict-Transport-Security:”max-age=31536000; includeSubDomains;”, Connection:”keep-alive”, X-Content-Type-Options:”nosniff, nosniff”, X-Frame-Options:”DENY, SAMEORIGIN”}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessToken()
  return “XXxXXXxx-XXxX-XXXx-XXxX-XXxxXxXXXxXX” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2016/10/29 同義語辞書【新語対応】

Apitoreの「同義語辞書【新語対応】」APIを呼び出して、指定の日本語の単語の同義語(っぽいもの)を返すAppleScriptです。

実行前にapitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

一般的なシソーラス的な動作を行うわけではなく、固有名詞に特化しているとのこと。そこで、「ガンダム」を渡してみたところ、

{input:”ガンダム”, endTime:”1477742279389″, processTime:”1019″, log:”Success.”, distances:{{word:”ζガンダム”, distance:0.819100677967}, {word:”rx-78″, distance:0.798426866531}, {word:”ζζガンダム”, distance:0.794555306435}, {word:”ザク”, distance:0.783695220947}, {word:”zガンダム”, distance:0.776543617249}, {word:”フルアーマー”, distance:0.757733106613}, {word:”gアーマー”, distance:0.75621265173}, {word:”νガンダム”, distance:0.754522383213}, {word:”ガンキャノン”, distance:0.752012193203}, {word:”モビルスーツ”, distance:0.744036734104}}, startTime:”1477742278370″, num:”10″}

やや、ゴミ(ζガンダム、ζζガンダム)が入っているようです。また、「グフ・カスタム」を入力してみると、

{input:”グフ・カスタム”, endTime:”1477742501687″, processTime:”934″, log:”Success.”, distances:{{word:”sideral”, distance:0.922877013683}, {word:”北海道道104号網走端野線”, distance:0.922159075737}, {word:”北海道道966号十勝岳温泉美瑛線”, distance:0.921318411827}, {word:”kuttner”, distance:0.916471898556}, {word:”北海道道102号網走川湯線”, distance:0.915675938129}, {word:”北海道道42号八雲北檜山線”, distance:0.915441274643}, {word:”三浦隆”, distance:0.914838135242}, {word:”桧山泰浩”, distance:0.914380848408}, {word:”北海道道120号美深中頓別線”, distance:0.914329528809}, {word:”knipex”, distance:0.913379848003}}, startTime:”1477742500753″, num:”10″}

と、関係ない言葉が返ってくるようです。Wikipediaに項目が単独で存在しているような単語と、その関連語では本サービス上での扱いが異なるように感じられます。

AppleScript名:同義語辞書【新語対応】
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4294

set reqURLStr to “https://api.apitore.com/api/9/word2vec-neologd-jawiki/distance”
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |word|:“ガンダム”, num:“10″}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {input:”ガンダム”, endTime:”1477742279389″, processTime:”1019″, log:”Success.”, distances:{{word:”ζガンダム”, distance:0.819100677967}, {word:”rx-78″, distance:0.798426866531}, {word:”ζζガンダム”, distance:0.794555306435}, {word:”ザク”, distance:0.783695220947}, {word:”zガンダム”, distance:0.776543617249}, {word:”フルアーマー”, distance:0.757733106613}, {word:”gアーマー”, distance:0.75621265173}, {word:”νガンダム”, distance:0.754522383213}, {word:”ガンキャノン”, distance:0.752012193203}, {word:”モビルスーツ”, distance:0.744036734104}}, startTime:”1477742278370″, num:”10″}

–>  {input:”グフ・カスタム”, endTime:”1477742501687″, processTime:”934″, log:”Success.”, distances:{{word:”sideral”, distance:0.922877013683}, {word:”北海道道104号網走端野線”, distance:0.922159075737}, {word:”北海道道966号十勝岳温泉美瑛線”, distance:0.921318411827}, {word:”kuttner”, distance:0.916471898556}, {word:”北海道道102号網走川湯線”, distance:0.915675938129}, {word:”北海道道42号八雲北檜山線”, distance:0.915441274643}, {word:”三浦隆”, distance:0.914838135242}, {word:”桧山泰浩”, distance:0.914380848408}, {word:”北海道道120号美深中頓別線”, distance:0.914329528809}, {word:”knipex”, distance:0.913379848003}}, startTime:”1477742500753″, num:”10″}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
set bLen to length of aValList
  
if aLen is not equal to bLen then return false
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on retAccessToken()
  return “XXxXXXxx-XXxX-XXXx-XXxX-XXxxXxXXXxXX” –API Tore Access Token
end retAccessToken

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

★Click Here to Open This Script 

2016/10/27 感情推定【極性判定】

Apitore「感情推定」APIを呼び出して、指定の日本語の文章がPositive(肯定的)かNegative(否定的)かを判定するAppleScriptです。

実行前にapitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

用途は割といろいろあって、ちょっと考えただけでも、

「メールの文面をチェックして、日本語であれば(NSLinguisticTaggerを使って判定)感情推定APIを呼び出し、Negativeと判定されたらメールの一覧に赤く色をつける」

とかいうAppleScriptはかんたんに書けますし、便利だと思います(色付きメールを読みたくなくなる、とかいう心理的なフィードバックが発生することについてはさておき)。

また、

Safariの閲覧履歴を取得して、各URLにアクセスして本文のみ取得。読んだ内容がPositveかNegativeかの内訳をグラフで表示」

とかいうのも面白そうです。

テストしてみたところ、たまたまサーバー側で問題を起こしていた最中のようで、サンプルプログラム中に記述してある「かならずPositive(肯定的)と判定される例文」がNegative(否定的)と出てきて焦りましたが、じきに安定することでしょう。

AppleScript名:感情推定【極性判定】
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4289

set aText to "おめでとう!カブスが4勝2敗でドジャースを下し、2016年ナ・リーグの覇者に!次は水曜日(10月26日)に行われるワールドシリーズでア・リーグの覇者インディアンスと対決!"

set reqURLStr to "https://api.apitore.com/api/11/sentiment/predict"
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |text|:aText}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {endTime:"1477617363491", processTime:"44", text:"おめでとう!カブスが4勝2敗でドジャースを下し、2016年ナ・リーグの覇者に!次は水曜日(10月26日)に行われるワールドシリーズでア・リーグの覇者インディアンスと対決!", log:"Success.", predict:{score:0.520746946335, sentiment:"positive"}, startTime:"1477617363447", sentimens:{{score:0.520746946335, sentiment:"positive"}, {score:0.479253053665, sentiment:"negative"}}}

–set aRESCode to (responseCode of aRes) as integer
–>  200

–set aRESHeader to (responseHeader of aRes) as record
–>  {Content-Type:"application/json;charset=UTF-8", Access-Control-Allow-Origin:"*", Pragma:"no-cache", X-XSS-Protection:"1; mode=block, 1; mode=block", Server:"nginx/1.10.1", Transfer-Encoding:"Identity", Expires:"0", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Date:"Thu, 27 Oct 2016 03:22:11 GMT", Strict-Transport-Security:"max-age=31536000; includeSubDomains;", Connection:"keep-alive", X-Content-Type-Options:"nosniff, nosniff", X-Frame-Options:"DENY, SAMEORIGIN"}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retAccessToken()
  return "xxxXxxXx-XXXX-XXXX-XxXX-XXxXXxxXXxxx" –API Tore Access Token
end retAccessToken

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

2016/05/11 ShangriLa Anime API V1のデータを取得する

技術書典の一般向けサイトで、参加サークルの詳細な説明文が見られるようになったので、ひととおり見てみました。すると、ノーマークだったサークルが面白いことをやっていることが分かったので、ちょっと見てみました。

ブースB-11の「秋葉原IT戦略研究所」さんが「SNSデータ解析で見る2016年アニメ界の展望」という本を出されるそうで、それだけだと何のことかわからなかったのですが、Twiter上でハッシュタグをつけてつぶやいている膨大なデータを分析してみた、という話だと理解しました。

その活動の一環として、「秋葉原IT戦略研究所」さんではRESTful APIで呼べるアニメ情報データベースを公開されており、とくに認証も何もかかっていないので気楽に呼べそうです。

そこで、実際にAppleScriptから呼んでみることにしました。実行にはShane StanleyのAppleScript Libraries「Bridge Plus」のインストールを必要とします。

まずは、このデータベースが対象にしているクール(1クール13話、1年を52週と仮定したときに1年は4クール)の情報を取得してみました。各クールが何年何月何日から何年何月何日までなのか、という情報は提供してくれないため、各自でカレンダー計算を行う必要がありそうです(4/1なのに前クールの最終回を放映していたというパターンもあるので、そのあたりどうなるのかルールが少々不明)。

AppleScript名:GET method REST API_Anime API_get cours
– Created 2016-05-11 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

set reqURLStr to “http://api.moemoe.tokyo/anime/v1/master/cours”

set aRes to callRestGETAPIAndParseResults(reqURLStr) of me

set aRESTres to json of aRes
set aRESCode to responseCode of aRes
–>  200
set aRESHeader to responseHeader of aRes
–>  {Connection:”keep-alive”, Access-Control-Allow-Origin:”*”, Content-Type:”application/json; charset=utf-8″, Content-Length:”353″, Server:”nginx/1.8.0″, Date:”Wed, 11 May 2016 01:14:49 GMT”}

return aRESTres
–>  (NSDictionary) {7:{id:7, year:2015, cours:3}, 3:{id:3, year:2014, cours:3}, 8:{id:8, year:2015, cours:4}, 4:{id:4, year:2014, cours:4}, 9:{id:9, year:2016, cours:1}, 5:{id:5, year:2015, cours:1}, 1:{id:1, year:2014, cours:1}, 6:{id:6, year:2015, cours:2}, 10:{id:10, year:2016, cours:2}, 2:{id:2, year:2014, cours:2}}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  load framework
  
–Request  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
–Parse Results
  
set resList to aRes as list
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

★Click Here to Open This Script 

次に、指定した年のアニメ作品に関する情報を取得。

AppleScript名:GET method REST API_Anime API_getInfo_in_a_year
– Created 2016-05-11 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

set reqURLStr to “http://api.moemoe.tokyo/anime/v1/master/” & “2016″

set aRes to callRestGETAPIAndParseResults(reqURLStr) of me

set aRESTres to json of aRes
set aRESCode to responseCode of aRes
–>  200
set aRESHeader to responseHeader of aRes
–>  {Connection:”keep-alive”, Access-Control-Allow-Origin:”*”, Content-Type:”application/json; charset=utf-8″, Content-Length:”353″, Server:”nginx/1.8.0″, Date:”Wed, 11 May 2016 01:14:49 GMT”}

return aRESTres
–>  (NSArray) {{id:281, title:”機動戦士ガンダム サンダーボルト”}, {id:282, title:”プリンス・オブ・ストライド オルタナティブ”}, {id:283, title:”無彩限のファントム・ワールド”}, {id:284, title:”ハルチカ〜ハルタとチカは青春する〜”}, {id:285, title:”ノルン+ノネット”}, {id:286, title:”アクティヴレイド −機動強襲室第八係−”}, {id:287, title:”少女たちは荒野を目指す”}, {id:288, title:”僕だけがいない街”}, {id:289, title:”おじさんとマシュマロ”}, {id:290, title:”ファンタシースターオンライン2 ジ アニメーション”}, {id:291, title:”だがしかし”}, {id:292, title:”暗殺教室(第2期)”}, {id:293, title:”ディバインゲート”}, {id:294, title:”おしえて!ギャル子ちゃん”}, {id:295, title:”石膏ボーイズ”}, {id:296, title:”霊剣山 星屑たちの宴”}, {id:297, title:”GATE 自衛隊 彼の地にて、斯く戦えり(2期)”}, {id:298, title:”昭和元禄落語心中”}, {id:299, title:”紅殻のパンドラ”}, {id:300, title:”ブブキ・ブランキ”}, {id:301, title:”ラクエンロジック”}, {id:302, title:”デュラララ!!×2 結”}, {id:303, title:”ナースウィッチ小麦ちゃんR”}, {id:304, title:”虹色デイズ”}, {id:305, title:”大家さんは思春期!”}, {id:306, title:”Dimension W”}, {id:307, title:”灰と幻想のグリムガル”}, {id:308, title:”シュヴァルツェスマーケン”}, {id:309, title:”最弱無敗の神装機竜(バハムート)”}, {id:310, title:”赤髪の白雪姫(第2期)”}, {id:311, title:”てーきゅう(第7期)”}, {id:312, title:”魔法少女なんてもういいですから。”}, {id:313, title:”蒼の彼方のフォーリズム”}, {id:314, title:”この素晴らしい世界に祝福を!”}, {id:315, title:”亜人”}, {id:316, title:”FAIRY TAIL ZERO”}, {id:317, title:”ももくり”}, {id:318, title:”この男子、魔法がお仕事です。”}, {id:319, title:”SUSHI POLICE”}, {id:320, title:”血液型くん!4″}, {id:321, title:”迷家‐マヨイガ‐”}, {id:322, title:”宇宙パトロールルル子”}, {id:323, title:”機動戦士ガンダムユニコーン RE:0096″}, {id:324, title:”影鰐-KAGEWANI-承”}, {id:325, title:”ぼのぼの”}, {id:326, title:”フューチャーカード バディファイト トリプルディー”}, {id:327, title:”逆転裁判”}, {id:328, title:”学戦都市アスタリスク 2nd SEASON”}, {id:329, title:”僕のヒーローアカデミア”}, {id:330, title:”マクロス”}, {id:331, title:”コンクリート・レボルティオ〜超人幻想〜THE LAST SONG”}, {id:332, title:”くまみこ”}, {id:333, title:”怪盗ジョーカー(シーズン3)”}, {id:334, title:”ばくおん!!”}, {id:335, title:”聖戦ケルベロス 竜刻のファタリテ”}, {id:336, title:”ハンドレッド”}, {id:337, title:”薄桜鬼〜御伽草子〜”}, {id:338, title:”ジョーカー・ゲーム”}, {id:339, title:”双星の陰陽師”}, {id:340, title:”SUPER LOVERS”}, {id:341, title:”鬼斬”}, {id:342, title:”文豪ストレイドッグス”}, {id:343, title:”あんハピ♪”}, {id:344, title:”クロムクロ”}, {id:345, title:”ネトゲの嫁は女の子じゃないと思った?”}, {id:346, title:”甲鉄城のカバネリ”}, {id:347, title:”少年メイド”}, {id:348, title:”坂本ですが?”}, {id:349, title:”田中くんはいつもけだるげ”}, {id:350, title:”キズナイーバー”}, {id:351, title:”はいふり”}, {id:352, title:”ふらいんぐうぃっち”}, {id:353, title:”とんかつDJアゲ太郎”}, {id:354, title:”三者三葉”}, {id:355, title:”うさかめ”}, {id:356, title:”マギ シンドバッドの冒険”}, {id:357, title:”Re:ゼロから始める異世界生活”}, {id:358, title:”うしおととら(第3クール)”}, {id:359, title:”ワガママハイスペック”}, {id:360, title:”ジョジョの奇妙な冒険 ダイヤモンドは砕けない”}, {id:361, title:”テラフォーマーズ リベンジ”}, {id:362, title:”プリパラ(3rdシーズン)”}, {id:363, title:”エンドライド”}, {id:364, title:”ビッグオーダー”}}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  load framework
  
–Request  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
–Parse Results
  
set resList to aRes as list
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

★Click Here to Open This Script 

最後に、年およびクール(1〜4)を指定して作品情報を取得するものです。

AppleScript名:GET method REST API_Anime API_getInfo_in_a_year_and_cour
– Created 2016-05-11 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

set aYear to 2016
set aCour to 1

set reqURLStr to “http://api.moemoe.tokyo/anime/v1/master/” & (aYear as string) & “/” & (aCour as string)

set aRes to callRestGETAPIAndParseResults(reqURLStr) of me

set aRESTres to json of aRes
set aRESCode to responseCode of aRes
–>  200
set aRESHeader to responseHeader of aRes
–>  {Connection:”keep-alive”, Access-Control-Allow-Origin:”*”, Content-Type:”application/json; charset=utf-8″, Content-Length:”353″, Server:”nginx/1.8.0″, Date:”Wed, 11 May 2016 01:14:49 GMT”}

return aRESTres
–>  (NSArray) {{id:281, title_short3:”", sex:0, sequel:0, created_at:”2016-01-01 23:40:06.0″, public_url:”http://gundam-tb.net/”, twitter_hash_tag:”gundam_tb”, title:”機動戦士ガンダム サンダーボルト”, updated_at:”2016-01-01 23:40:06.0″, twitter_account:”gundam_tb”, title_short1:”サンダーボルト”, title_short2:”", cours_id:9}, …….

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  load framework
  
–Request  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
–Parse Results
  
set resList to aRes as list
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

★Click Here to Open This Script 

放送されている番組の情報を提供する情報発信元としては、新聞などにテレビ番組のラテ欄情報を提供している東京ニュース通信社あるいは日刊編集センターか、EPGのメタデータを提供している(株)エムデータあたりがBtoB向け専門でやっています。BtoC向けにデータを出すかどうかは不明ですが、話をしてみるといいんじゃないでしょうか?

2016/05/02 Google APIを用いてURLを短縮してより小さいQRコードを作成

Google APIを利用して指定のURLを短縮し、QRコードを作成するAppleScriptです。

各種WebサービスをAppleScriptから呼び出して、日々便利に使っています。その中でまったく興味が湧かなかったURL短縮サービスAPI(URL Shortening API)。

たまたま、WebのURLからQRコードを作成して印刷することを検討していたときに、印刷面積を減らしたいというニーズが出てきました(TEPRAで印刷しようとしていたので)。

単純に縮小して印刷する物理的な大きさを小さくすれば、印刷できないこともないのですが、ゴミなどが付着したり経年劣化で退色した場合などに、むりやり小さく印刷するとエラーに遭遇する確率が上がってしまいます。また、解像度の低いプリンターで印刷するときには、エラー発生リスクが上がります。

そこで、長くなりがちなWebのURLを、短縮URLサービスを用いて短くしたうえでQRコード化することを思いつきました(Googleで探してみると、同様の先行事例多数 ^ー^;)。

qrcodes.png

上の図で、左がオリジナルのURLをQRコード化したもの。右がURL短縮してQRコード化したものです。URL短縮がQRコードのサイズの縮小に貢献することが見て取れます。ここで用いた元URLは、

 Original URL—-http://piyocast.com/as/archives/4067
 Shorten URL—-http://goo.gl/kT372B

クラウドストレージ上にあるファイル(Dropboxなど)やGoogle Map上の位置情報を示すURLは長くなりがちですが、いったんURL短縮サービスを経由することで、QRコードに印刷するのに抵抗感のない程度の長さの文字列に圧縮でき、たいへんけっこうなことです(Google Mapsにも短縮URL変換の機能がついていますね、、、)。

実行時には、Googleアカウントを作成してGoogle APIの利用申請を行い、API Keyを取得してAppleScript中に指定してください。また、実行にあたって実行環境にShane StanleyのAppleScript Libraries「Bridge Plus」がインストールしてあることが条件となります。

AppleScript名:POST method REST API_Google Shortener URL and make QR code
– Created 2016-05-01 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

property APIKey : “XXxxXxXXXxXxX-XxXXxXXXxxxxXXXXxXxXXxXXX” –Google API Key

set aLongURL to “http://piyocast.com/as/archives/4067″ –Target Long URL
set aShortURL to shortenURL(aLongURL) of me
if aShortURL = “” then return –Error

set dtPath to POSIX path of (path to desktop) & ((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)
set aRes to writeQRimageAsPNG(aShortURL, dtPath) of me

–指定パスにQRコードをPNG画像で出力
on writeQRimageAsPNG(aTargStr, aTargPath)
  set aStr to current application’s NSString’s stringWithString:aTargStr
  
set strData to aStr’s dataUsingEncoding:(current application’s NSISOLatin1StringEncoding)
  
set qrFilter to current application’s CIFilter’s filterWithName:“CIQRCodeGenerator”
  
qrFilter’s setValue:strData forKey:“inputMessage”
  
qrFilter’s setValue:“H” forKey:“inputCorrectionLevel”
  
set anImage to qrFilter’s outputImage()
  
saveNSImageAtPathAsPNG(anImage, aTargPath) of me
end writeQRimageAsPNG

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveNSImageAtPathAsPNG

–与えられたURL文字列を短縮する
on shortenURL(aLongURL)
  set myAPIKey to my APIKey
  
set reqURLStr to “https://www.googleapis.com/urlshortener/v1/url?key=” & myAPIKey
  
set aRec to {longUrl:aLongURL}
  
set aRes to callRestPOSTAPIAndParseResults(reqURLStr, aRec) of me
  
  
set aRESTres to json of aRes
  
set aRESCode to responseCode of aRes
  
set aRESHeader to responseHeader of aRes
  
  
if aRESCode is not equal to 200 then return “”
  
set aShort to (aRESTres’s valueForKey:“id”) as string
  
return aShort
end shortenURL

–POST methodのREST APIを呼ぶ
on callRestPOSTAPIAndParseResults(aURL, aPostData)
  
  
load framework
  
  
–Request  
  
set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aPostData options:0 |error|:(missing value)
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setHTTPBody:dataJson
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Content-Type”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPOSTAPIAndParseResults

★Click Here to Open This Script 

2016/03/13 Google Translate APIでサポート言語一覧を指定言語で取得する

Google Translate API(REST API)を呼び出して、翻訳可能な言語の名称一覧を指定言語(Japanese)で取得するAppleScriptです。

実行するには、Shane StanleyのBridgePlus Script Libraryを実行するMacの~/Library/Script Librariesにインストールし、GoogleのAPI利用登録を行ってAPI Keyを取得しておく必要があります。ご自分のAPI Keyを下記リストのmyAPIKeyに代入(リスト中では伏字)してから実行してください。

実行結果から、Google Translate APIが104の言語をサポートしていることがわかります。

この程度の問い合わせなら問題なく実行できているのですが、いざ翻訳させようとするとまだクリアーできていない困難が(汗) Googleのサービス側のログとかを見られると、どこで間違っているのか分かりそうですが、、、、というか、そういうサービス自体が存在していそうな、、、、

AppleScript名:GET method REST API_Google Translate API サポート言語一覧を取得
– Created 2016-03-03 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus” –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

set myAPIKey to “XXxxXxXXXxXxX-XxXXxXXXxxxxXXXXxXxXXxXXX”
set reqURLStr to “https://www.googleapis.com/language/translate/v2/languages?key=” & myAPIKey & “&target=ja”

set aRes to callRestGETAPIAndParseResults(reqURLStr) of me

set aRESTres to json of aRes
–>  (NSDictionary) {error:{message:”Bad Request”, errors:{{reason:”keyInvalid”, message:”Bad Request”, domain:”usageLimits”}}, code:400}}–エラー時

–>  (NSDictionary) {data:{languages:{{name:”アイスランド語”, language:”is”}…… {name:”英語”, language:”en”}, {name:”韓国語”, language:”ko”}, {name:”中国語(簡体)”, language:”zh”}, {name:”中国語(繁体)”, language:”zh-TW”}, {name:”日本語”, language:”ja”}}}}

–return (aRESTres’s valueForKeyPath:”data.languages.name”)’s |count|()
–>  104

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json; charset=UTF-8″, alt-svc:”quic=\”:443\”; ma=2592000; v=\”31,30,29,28,27,26,25\”", alternate-protocol:”443:quic,p=1″, Content-Encoding:”gzip”, Server:”GSE”, x-xss-protection:”1; mode=block”, Expires:”Sun, 13 Mar 2016 00:45:39 GMT”, Cache-Control:”private, max-age=0″, Date:”Sun, 13 Mar 2016 00:45:39 GMT”, Content-Length:”132″, x-content-type-options:”nosniff”, x-frame-options:”SAMEORIGIN”, Vary:”Origin, X-Origin”}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  load framework
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

★Click Here to Open This Script 

2016/03/06 REST APIに対してGET、POST、PUT、DELETEのmethodを呼び出す

AppleScriptでWeb上のREST APIを呼び出すじっけんです。Web上にあるREST APIの実験用サービスJSONPlaceholderをAppleScriptから呼び出して各種メソッド呼び出しの実証を行ってみました。

できてしまえばたいしたことはありませんが、地道に調査しておかないと今日明日でいきなりやれと言われても困ってしまいます。

実際に、NTTdocomoの形態素解析のREST APIをmethod=POSTでAppleScriptから呼び出してみたところ、

–> (NSDictionary) {request_id:”record001″, word_list:{{{”私”}, {”の”}, {”名前”}, {”は”}, {” ”}, {”長野”}, {”谷”}, {”です”}, {”。”}}}, info_filter:”form”}

となりました(words ofの実行結果と変わり映えしない、、、、)。固有名詞としてあらかじめ人名を登録しておきたいケースがほとんどなので、ちょっとこれだと使えない感じではあります。ただ、実際に稼働しているAPIを呼べることは実証できました。

AppleScript名:GET method REST API
– Created 2016-03-03 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

set reqURLStr to “http://jsonplaceholder.typicode.com/posts”

set aRes to callRestGETAPIAndParseResults(reqURLStr) of me

set aRESTres to json of aRes
–>  (NSArray) {{body:”quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto”, id:1, title:”sunt aut facere repellat provident occaecati excepturi optio reprehenderit”, userId:1},…

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json; charset=utf-8″, Pragma:”no-cache”, X-Powered-By:”Express”, Via:”1.1 vegur”, Server:”Cowboy”, Expires:”-1″, Cache-Control:”no-cache”, Date:”Sun, 06 Mar 2016 07:27:26 GMT”, Access-Control-Allow-Credentials:”true”, Content-Length:”27520″, Connection:”keep-alive”, X-Content-Type-Options:”nosniff”, Etag:”W/\”6b80-uPwhAkDat3Fl5TugzmyYpQ\”", Vary:”Origin”}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  load framework
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

★Click Here to Open This Script 

AppleScript名:POST method REST API
– Created 2016-03-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

set reqURLStr to “http://jsonplaceholder.typicode.com/posts”
set aPostData to {title:“foo”, body:“bar”, userId:1}

set aRes to callRestPOSTAPIAndParseResults(reqURLStr, aPostData) of me

set aRESTres to json of aRes
–>  (NSDictionary) {body:”bar”, id:101, title:”foo”, userId:1}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json; charset=utf-8″, Pragma:”no-cache”, X-Powered-By:”Express”, Via:”1.1 vegur”, Server:”Cowboy”, Expires:”-1″, Cache-Control:”no-cache”, Date:”Sun, 06 Mar 2016 07:47:56 GMT”, Access-Control-Allow-Credentials:”true”, Content-Length:”65″, Connection:”keep-alive”, X-Content-Type-Options:”nosniff”, Etag:”W/\”41-DL1IzEbjanDFwm6hF2BfJw\”", Vary:”Origin, X-HTTP-Method-Override”}

–POST methodのREST APIを呼ぶ
on callRestPOSTAPIAndParseResults(aURL, aPostData)
  load framework
  
set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aPostData options:0 |error|:(missing value)
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setHTTPBody:dataJson
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Content-Type”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPOSTAPIAndParseResults

★Click Here to Open This Script 

AppleScript名:PUT method REST API
– Created 2016-03-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

set reqURLStr to “http://jsonplaceholder.typicode.com/posts/1″
set aPostData to {title:“ぴよまるソフトウェア”, body:“PUTのじっけん”, userId:1}
–set aPostData to {title:”foo”, body:”bar”, userId:1}

set aRes to callRestPUTAPIAndParseResults(reqURLStr, aPostData) of me

set aRESTres to json of aRes
–>  (NSDictionary) {body:”PUTのじっけん”, id:1, title:”ぴよまるソフトウェア”, userId:1}
return aRESTres
set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json; charset=utf-8″, Pragma:”no-cache”, X-Powered-By:”Express”, Via:”1.1 vegur”, Server:”Cowboy”, Expires:”-1″, Cache-Control:”no-cache”, Date:”Sun, 06 Mar 2016 07:47:56 GMT”, Access-Control-Allow-Credentials:”true”, Content-Length:”65″, Connection:”keep-alive”, X-Content-Type-Options:”nosniff”, Etag:”W/\”41-DL1IzEbjanDFwm6hF2BfJw\”", Vary:”Origin, X-HTTP-Method-Override”}

–PUT methodのREST APIを呼ぶ
on callRestPUTAPIAndParseResults(aURL, aPostData)
  load framework
  
set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aPostData options:0 |error|:(missing value)
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“PUT”
  
aRequest’s setHTTPBody:dataJson
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Content-Type”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPUTAPIAndParseResults

★Click Here to Open This Script 

AppleScript名:DELETE method REST API
– Created 2016-03-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

set reqURLStr to “http://jsonplaceholder.typicode.com/posts/1″

set aRes to callRestDELETEAPIAndParseResults(reqURLStr) of me

set aRESTres to json of aRes
–>  (NSDictionary) {}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json; charset=utf-8″, Pragma:”no-cache”, X-Powered-By:”Express”, Via:”1.1 vegur”, Server:”Cowboy”, Expires:”-1″, Cache-Control:”no-cache”, Date:”Sun, 06 Mar 2016 07:53:51 GMT”, Access-Control-Allow-Credentials:”true”, Content-Length:”2″, Connection:”keep-alive”, X-Content-Type-Options:”nosniff”, Etag:”W/\”2-mZFLkyvTelC5g8XnyQrpOw\”", Vary:”Origin”}

–DELETE methodのREST APIを呼ぶ
on callRestDELETEAPIAndParseResults(aURL)
  load framework
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
set respF to false
  
  
aRequest’s setHTTPMethod:“DELETE”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestDELETEAPIAndParseResults

★Click Here to Open This Script