Archive for the 'NSURLRequest' Category

2017/10/16 並列ダウンロードのじっけん v2

AppleScriptによる狂気のthreadごっこ。並列ダウンロードの実験AppleScriptです。

昨日のScriptを実際に何度も実行してみて「Threadを生成しても順次実行されているようにしか見えないのはなぜだろう?」などと思いつつ、スレッドのオブジェクトを配列に突っ込んでおいて、一括で実行命令(start:)を行うように改良してみました。

また、スレッド内で実行する内容に単なるカウントという(安全ではあるものの)無意味な処理ではなく、ファイルのダウンロード実行を行なっています。

自分的にはいろいろとブレークスルーな内容ではあるものの、ダウンロードにしてもThread処理するよりも逐次実行したほうが速そうな感じであるのと、shellのcurlコマンドで並列でダウンロードしたほうが安全で速そうとか、かなり「不可能にチャレンジした以外にあまりほめるべき点がない」という雰囲気になっています。

ダウンロード先のURLが数個程度だと何も問題はないものの、数十個指定すると帰ってこなくなるなど、何か問題が起きているようなので、あくまで「実験」レベルの実装です。

AppleScript名:並列ダウンロードのじっけん v2
– Created 2015-08-20 by Takaaki Naganoya
– Created 2017-10-16 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4898

property aProp : {}
property aMax : {}

set aList to {“http://piyocast.com/as/wp-content/uploads/2016/08/xbook1_ver2.png.pagespeed.ic.1UE9W7-aVC.png”, “http://piyocast.com/as/wp-content/uploads/2016/08/xbook2_v2.png.pagespeed.ic.uWjZsXaLOP.png”, “http://piyocast.com/as/wp-content/uploads/2016/09/xscript_assistant.jpg.pagespeed.ic.fk8YHumFYV.jpg”}

set aProp to {}
set thList to current application’s NSMutableArray’s new()
set aMax to length of aList
set aCount to 1

repeat with i in aList
  set j to contents of i
  
set aURL to (current application’s |NSURL|’s URLWithString:j)
  
set aThread to (current application’s NSThread’s alloc()’s initWithTarget:me selector:“_threadLoop:” object:aURL)
  (
aThread’s setName:(“thread “ & (aCount as string)))
  (
thList’s addObject:aThread)
  
  
set noter1 to current application’s NSNotificationCenter’s defaultCenter()
  (
noter1’s addObserver:me selector:“_threadWillExit:” |name|:(current application’s NSThreadWillExitNotification) object:(thList’s lastObject()))
  
  
set aThread to “” –purge object from memory
  
set aCount to aCount + 1
end repeat

thList’s makeObjectsPerformSelector:“start” withObject:0

repeat 100000 times
  if length of aProp aMax then exit repeat
  
delay “0.0001″ as real
end repeat

–各Threadが実行するハンドラ
on _threadLoop:aInfo
  checkURLResourceExistence(aInfo, 10) of me
end _threadLoop:

–Threadが終了する際に呼ばれるハンドラ
on _threadWillExit:aNotification
  set tmpRes to aNotification’s object’s |name|()
  
log tmpRes as string
end _threadWillExit:

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
set the end of aProp to {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

2017/09/06 ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3

Safariで表示中のWebマンガサイト「ツイ4」(更新情報をTwitterに投稿)のマンガを全エピソードダウンロードしてPDFにまとめるAppleScriptです。

実行にあたってはShane StanleyのAppleScript Libraries「BridgePlus」のインストールを必要とします(~/ibrary/Script Librariesフォルダに入れるだけ)。

実行開始時にはSafariでツイ4の特定のマンガのページをオープンしている必要があります。

tui4.png

Safariの最前面のウィンドウからURLやTitle、リンクされている画像の詳細情報を取得し、条件チェックなどを行なったのちに詳細なデータの抽出を行います。

次に、PDFの保存先を選択するダイアログを表示。このさい、デフォルトの保存先を「ピクチャ」フォルダ、ファイル名をマンガのタイトルに指定。

ページにリンクされていた画像(ツイではファイル名はシーケンシャル番号)から番号の情報だけを抽出して最大値、最小値を計算。この範囲で画像のダウンロード、PDFへの追記を行います。ただし、実運用してみたところ、Safariからすべての画像を取得できないようで(非同期表示しているようなので)、とりあえず1〜9999までの番号の画像を順次ダウンロードし、画像が存在しなければ処理を終了しています。

画像をダウンロードするたびにPDFに追記していますが、このあたりは途中でエラーが出て停止してもそれまでの処理内容が保存されることを意図してのことです。SSD搭載機では問題のない処理ですが、HDD搭載機では若干遅く感じるかもしれません(もはやHDD搭載機が身の回りにないので不明)。

これまでは、マンガの新規連載がはじまるとcurlコマンドで画像をダウンロードしてPDFに連結する作業を手で行なっていたのですが(誰も頼んでねえよ)、新規連載が増えたので自動化してみました。それでもありあわせの部品を組み合わせただけなので、それほど手間はかかっていません。

本Scriptとは別に更新された差分をPDFに連結するAppleScriptを作って日々実行し、大きな画面でブラウズするのに役立てています。割とこういう、ごくごく私的なScriptで野心的な処理を先行してテストしているものです。

AppleScript名:ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3
– Created 2016-09-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “QuartzCore”
use BridgePlus : script “BridgePlus”
–http://piyocast.com/as/archives/4808

property SMSForder : a reference to current application’s SMSForder
property |NSURL| : a reference to current application’s |NSURL|
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection
property NSArray : a reference to current application’s NSArray
property NSFileManager : a reference to current application’s NSFileManager
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSPredicate : a reference to current application’s NSPredicate
property PDFPage : a reference to current application’s PDFPage
property PDFDocument : a reference to current application’s PDFDocument
property NSURLRequestUseProtocolCachePolicy : a reference to current application’s NSURLRequestUseProtocolCachePolicy
property NSNumberFormatterPadBeforePrefix : a reference to current application’s NSNumberFormatterPadBeforePrefix
property NSImage : a reference to current application’s NSImage
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSNumber : a reference to current application’s NSNumber
property NSRegularExpressionDotMatchesLineSeparators : a reference to current application’s NSRegularExpressionDotMatchesLineSeparators
property NSRegularExpressionAnchorsMatchLines : a reference to current application’s NSRegularExpressionAnchorsMatchLines
property NSRegularExpression : a reference to current application’s NSRegularExpression
property NSString : a reference to current application’s NSString

property theTargetSite : “http://sai-zen-sen.jp/”

tell application “Safari”
  if (count every document) = 0 then
    display notification “Safari does not open web page”
    
return
  end if
  
  
set docTitle to (do JavaScript “document.title” in front document) –Title
  
  
tell front document –URL
    set aURL to URL
  end tell
end tell

if aURL does not start with theTargetSite then
  display notification “This site is not the target”
  
return
end if

–Safariの最前面のウィンドウから画像リンクをすべて取得(Height, Width, URL)
set aList to getImageSizeAndURLOfFrontSafariDocument() of me

–取得した画像情報の2D Listをサイズで降順ソート
load framework –Force loading BridgePlus framework
set sortIndexes to {0, 1} –Key Item id: begin from 0
set sortOrders to {false, false}
set sortTypes to {“compare:”, “compare:”}
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value))

–画像が取得できなかったら処理終了
if (resList as list) = {} then
  display notification “There is no images on this page”
  
return –No Result
end if

–最大サイズの画像情報を取得する(おそらくマンガ)
set {maxHeight, maxWidth, maxURL} to contents of first item of (resList as list)

set aNSURL to |NSURL|’s URLWithString:maxURL
set aNSURLfilename to (aNSURL’s lastPathComponent())
set aNSURLpure to aNSURL’s URLByDeletingLastPathComponent()
set aNSURLextension to aNSURLfilename’s pathExtension() as string
set aNSURLfilenameLen to (aNSURLfilename’s stringByDeletingPathExtension())’s |length|() as integer –画像ファイル名から拡張子を除去した部分の文字列長

–画像情報リストを画像サイズで抽出
set maxHeightStr to (maxHeight as integer) as string
set maxWidthStr to (maxWidth as integer) as string
set thePred to NSPredicate’s predicateWithFormat:(“(self[0] == “ & maxHeightStr & “) AND (self[1] == “ & maxWidthStr & “)”)
set bArray to (resList’s filteredArrayUsingPredicate:thePred) as list

–URLからファイル名の数値部分のみ抽出
set imageArray to current application’s NSMutableArray’s new()
repeat with i in bArray
  set j to contents of last item of i –(Image URL)
  
set aTmpURL to (|NSURL|’s URLWithString:j)
  
set aTmpfilename to (aTmpURL’s lastPathComponent()) as string
  
set numStr to first item of (my findPattern:(“^\\d{1,” & (aNSURLfilenameLen as string) & “}”) inString:aTmpfilename)
  
set jj2 to (SMSForder’s transformedFrom:numStr ICUTransform:“Fullwidth-Halfwidth” inverse:false) as integer
  (
imageArray’s addObject:jj2)
end repeat

–ファイル名から抽出した数値の最小値と最大値を求める。ただ、実運用したらWeb側から画像をすべて取得されない(非同期読み込みを行なっているらしい)ケースがあったため、ここの値は参考値程度にしか使えなかった
set maxRes to (imageArray’s valueForKeyPath:“@max.self”)’s intValue() –最大値
set minRes to (imageArray’s valueForKeyPath:“@min.self”)’s intValue() –最小値
log {minRes, maxRes}

–PDFのファイル名と場所をユーザーに確認
set pdfFile to (choose file name with prompt “Select PDF Name & Location” default location (path to pictures folder) default name (docTitle & “.pdf”))
set pdfFilePOSIX to POSIX path of pdfFile
set newFilePath to current application’s NSString’s stringWithString:pdfFilePOSIX

–Make Blank PDF
set aPDFdoc to PDFDocument’s alloc()’s init()

–Download each image and append to blank PDF
set insCount to 1 –画像ダウンロード用のページ数(Loop Counter)とPDF連結用のページ番号(insCount)を分離

–repeat with i from minRes as integer to maxRes as integer
repeat with i from 1 to 9999
  –URL部品の連結
  
set aFILENAME to numToZeroPaddingStr(i, aNSURLfilenameLen, “0″) of me
  
set aFULLURL to (aNSURLpure’s absoluteString() as string) & (aFILENAME as string) & “.” & (aNSURLextension as string)
  
set aURL to (|NSURL|’s URLWithString:aFULLURL)
  
  
–URL(画像)をダウンロード
  
set {uRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
  
  
if uRes = true then
    display notification “Episode “ & (i as string) & ” exists…”
    
set bImage to (NSImage’s alloc()’s initWithData:aData)
    (
aPDFdoc’s insertPage:(PDFPage’s alloc()’s initWithImage:bImage) atIndex:(insCount - 1))
    (
aPDFdoc’s writeToFile:newFilePath) –1Page更新するたびにファイル保存
    
set changedF to true –PDFにページが追記されたことを検出
  else
    display notification “No more new episode….”
    
exit repeat
  end if
  
  
set insCount to insCount + 1
end repeat

–FinderコメントにURLを記入
tell application “Finder”
  set comment of (pdfFile as alias) to (aNSURLpure’s absoluteString() as string)
end tell

–生成したPDFをオープン。ビューワー経由ではなくFinder経由でopen命令を送って表示
tell application “Finder”
  open (pdfFile as alias)
end tell
–ここで処理終了

—————

on getImageSizeAndURLOfFrontSafariDocument()
  set aList to {}
  
  
tell application “Safari”
    if its running then
      if (count every document) = 0 then return {}
      
set aRes to (do JavaScript “document.images.length” in front document)
      
      
repeat with i from 0 to (aRes - 1)
        set aHeight to do JavaScript ((“document.images[” & i as string) & “].height”) in front document
        
set aWidth to do JavaScript ((“document.images[” & i as string) & “].width”) in front document
        
set aSRC to do JavaScript ((“document.images[” & i as string) & “].src”) in front document
        
set the end of aList to {aHeight, aWidth, aSRC}
      end repeat
    end if
  end tell
  
  
return aList
end getImageSizeAndURLOfFrontSafariDocument

on findPattern:thePattern inString:theString
  set theOptions to ((NSRegularExpressionDotMatchesLineSeparators) as integer) + ((NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list
  
set theResult to {}
  
set theNSString to NSString’s stringWithString:theString
  
  
repeat with i in theFinds
    set theRange to (contents of i)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as string
  end repeat
  
return theResult
end findPattern:inString:

–1D List(文字)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DList:theList ascOrder:aBool
  set aDdesc to NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

–整数の値に指定桁数ゼロパディングして文字列で返す
on numToZeroPaddingStr(aNum as integer, aDigit as integer, paddingChar as text)
  set aNumForm to NSNumberFormatter’s alloc()’s init()
  
aNumForm’s setPaddingPosition:(NSNumberFormatterPadBeforePrefix)
  
aNumForm’s setPaddingCharacter:paddingChar
  
aNumForm’s setMinimumIntegerDigits:aDigit
  
  
set bNum to NSNumber’s numberWithInt:aNum
  
set aStr to aNumForm’s stringFromNumber:bNum
  
  
return aStr as text
end numToZeroPaddingStr

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (NSURLRequest’s requestWithURL:aURL cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to 404
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

–指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
–返り値:PDFファイルのページ数(整数値)
on pdfPageCount(aFile)
  set aFile to POSIX path of aFile
  
set theURL to |NSURL|’s fileURLWithPath:aFile
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
  
set aRes to aPDFdoc’s pageCount()
  
return aRes as integer
end pdfPageCount

★Click Here to Open This Script 

2017/07/09 指定URLにリンクされているPDFをすべて指定のフォルダにダウンロードする

指定URLのHTMLにリンクされているPDFをすべて指定のフォルダにダウンロードするAppleScriptです。

従来、この手の処理はSafariに対してdo javascript命令を実行していましたが、呼び出しにそこそこ時間がかかります。

そこで、SafariまかせにせずにAppleScript側でオープンソースのフレームワーク「HTMLReader」を呼び出してHTMLを解析したところ、圧倒的に高速になりました。

同じページ内のリンク箇所の抽出処理だと、

  Safari+do javascript:89 seconds
  HTMLReader.framework:0.064 seconds (First Run Time:0.831 seconds)

と、Safariに対してdo javascriptコマンドを実行しないAppleScriptのほうが100〜1,400倍高速に処理できています。本Script全体の処理時間については、PDFのダウンロード処理をともなうためネットワークの速さに依存しますが、1分かからない程度で終わることでしょう。Safari+do javascriptだとリンク先の抽出がまだ終わっていないぐらいの時間です。

実行にあたっては、HTMLReaderのプロジェクトをダウンロードしてXcode上でビルドし、出来上がったフレームワークのバイナリを~/Library/Frameworksにインストールしておく必要があります。

ただ、PDFのURLが厳密にわかっている連番のファイルならshellのcurlコマンドを呼び出してダウンロードさせれば1行で終わってしまう内容ではあります。

AppleScript名:指定URLにリンクされているPDFをすべて指定のフォルダにダウンロードする
– Created 2017-07-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “HTMLReader” –https://github.com/nolanw/HTMLReader
–http://piyocast.com/as/archives/4720

set aTargFol to POSIX path of (choose folder with prompt “PDFダウンロード先のフォルダを選択”)
set aTargPath to current application’s NSString’s stringWithString:aTargFol

set aStr to “http://yakumo-tajimi.com/dl.html” –Safariの最前面のウィンドウからとってきてもよい
set aList to getWebLinkURLs(aStr, “pdf”) of me

repeat with i in aList
  set j to contents of i
  
set jURL to (current application’s |NSURL|’s URLWithString:j)
  
set {exRes, headerRes, aData} to checkURLResourceExistence(jURL, 10) of me
  
  
if exRes = true then
    set cURL to (current application’s |NSURL|’s URLWithString:j)
    
set cFileName to (cURL’s |lastPathComponent|()) as string
    
set savePath to (aTargPath’s stringByAppendingPathComponent:cFileName)
    
set wRes to (aData’s writeToFile:savePath atomically:true)
  end if
end repeat

–指定のURLのページのHTMLソースからリンクを抽出して、指定拡張子に合うものだけをフルパスのURL化して返す
on getWebLinkURLs(anURLstr, linkFileExt)
  –URLの妥当性チェック(存在チェック)
  
set aURL to (current application’s |NSURL|’s URLWithString:anURLstr)
  
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
  
if exRes = false then error “Illegal URL Error” –エラー発生時に処理打ち切り
  
  
–HTMLのソースを取得する
  
set conType to headerRes’s valueForKeyPath:“Content-Type”
  
set aHTML to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType
  
  
–リンク箇所を抽出
  
set aTextArray to ((aHTML’s nodesMatchingSelector:“a”)’s textContent) as list –リンク文字
  
set aLinkArray to ((aHTML’s nodesMatchingSelector:“a”)’s attributes’s valueForKeyPath:“href”) as list –URL
  
  
  
–取得したリンクを拡張子で絞り込みつつ、それぞれフルパスのURLを組み立てる
  
set urlList to {}
  
set aaURL to aURL’s URLByDeletingLastPathComponent()
  
  
repeat with i in aLinkArray
    set bURL to (current application’s |NSURL|’s URLWithString:i)
    
set aRes to (bURL’s |scheme|()) as string
    
set aExt to (bURL’s |pathExtension|()) as string
    
    
if aRes = “missing value” and aExt = linkFileExt then
      –想定URL(指定サイト内)のファイルへのリンクの処理
      
set aaaURL to (aaURL’s URLByAppendingPathComponent:i)
      
set aaaURLstr to (aaaURL’s absoluteString()) as string
      
set the end of urlList to aaaURLstr
    else if aRes is not “missing value” and aExt = linkFileExt then
      –指定外のURL(想定サイト外のファイルへのリンクなど)の処理
      
set the end of urlList to (aaURL’s absoluteString()) as string
    end if
  end repeat
  
  
–重複部分を除去してユニークなリストにして返す
  
return uniquify1DList(urlList, true) of me
end getWebLinkURLs

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

–1D/2D Listをユニーク化
on uniquify1DList(theList as list, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”
  
return bArray as list
end uniquify1DList

★Click Here to Open This Script 

2016/11/21 HTMLReaderでWeb上のHTMLからリンクを取得する

オープンソースのフレームワーク「HTMLReader」を用いて、指定のURLのHTMLをダウンロードして指定要素を取り出すAppleScriptです。

実行にあたっては、HTMLReaderをダウンロードしてビルドし、~/Library/Frameworksにインストールしておく必要があります。

AppleScript名:HTMLReaderでWeb上のHTMLからリンクを取得する
– Created 2016-11-21 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “HTMLReader” –https://github.com/nolanw/HTMLReader
–http://piyocast.com/as/archives/4325

set aStr to “https://github.com/nolanw/HTMLReader”
set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
if exRes = false then return –エラー発生時に処理打ち切り

set conType to headerRes’s valueForKeyPath:“Content-Type”
set aHTML to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType

set aTextArray to ((aHTML’s nodesMatchingSelector:“a”)’s textContent) as list –リンク文字
set aLinkArray to ((aHTML’s nodesMatchingSelector:“a”)’s attributes’s valueForKeyPath:“href”) as list –URL
–> {”#start-of-content”, “https://github.com/”, “/personal”, “/open-source”, “/business”, “/explore”, “/join?source=header-repo”, “/login?return_to=%2Fnolanw%2FHTMLReader”, “/pricing”, “/blog”, …….}

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

AppleScript名:HTMLReaderでWeb上のHTMLから画像リンクを取得する
– Created 2016-11-21 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “HTMLReader” –https://github.com/nolanw/HTMLReader
–http://piyocast.com/as/archives/4325

set aStr to “https://github.com/nolanw/HTMLReader”
set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
if exRes = false then return –エラー発生時に処理打ち切り

set conType to headerRes’s valueForKeyPath:“Content-Type”
set aHTML to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType

set aLinkArray to ((aHTML’s nodesMatchingSelector:“img”)’s attributes’s valueForKeyPath:“src”) as list –画像リンクURLを取得
–> {”https://avatars2.githubusercontent.com/u/177228?v=3&s=40″, “https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif”, “https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif”, ….

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★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/18 URLにリソースが存在するかチェック v3

指定したURLにリソース(ファイル)が存在するかを確認するAppleScriptの改良版です。

Webサーバーなどのリモート環境を指しているURLをファイル名までフルに記述して、画像ファイルなどの存在確認を行います。「存在確認だけ」を行うことができないので、確認すると実際にデータも取得します。

  結果:{存在確認(true/false), レスポンスヘッダー(NSDictionary), データ本体(NSData)}

v3では、Webサーバーに問い合わせを行ってエラーになったときの対応を追加しています。

AppleScript名:URLにリソースが存在するかチェック v3
– Created 2016-10-18 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4279

set aStr to “http://piyocast.com/as/wp-content/uploads/2016/10/xfinder2.jpg.pagespeed.ic.jFDNAr4CuI.jpg”

set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me

exRes
–> true / false

headerRes
–> (NSDictionary) {Connection:”Keep-Alive”, Content-Type:”image/jpeg”, Server:”Apache”, Last-Modified:”Mon, 10 Oct 2016 03:43:53 GMT”, Expires:”Tue, 10 Oct 2017 03:43:53 GMT”, Cache-Control:”max-age=31536000″, Accept-Ranges:”bytes”, Date:”Mon, 10 Oct 2016 05:24:38 GMT”, Keep-Alive:”timeout=1, max=100″, Content-Length:”4383″, Etag:”W/”0″”}

aData
–> (NSData)

set conType to (headerRes’s valueForKey:“Content-Type”) as string
–>  ”image/jpeg”

set modDate to (headerRes’s valueForKey:“Last-Modified”) as string
–>  ”Mon, 10 Oct 2016 03:43:53 GMT”

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

2016/10/10 URLにリソースが存在するかチェック v2

指定したURLにリソース(ファイル)が存在するかを確認するAppleScriptです。

Webサーバーなどのリモート環境を指しているURLをファイル名までフルに記述して、画像ファイルなどの存在確認を行います。

ただし、「存在確認だけ」を行うことができないようで、確認すると実際にデータも取得できてしまいます。

本来なら、このような処理は並列で同時に行いたいところ。強制的に並列化するツールも作って実験していますが、同時に大量のURLの存在確認を行うような処理はとてもありえそうです。

ただ、shell commandで行なっても割と手軽にできそうで、Cocoaのサービスを呼び出すのか、実際に処理速度を計測して選択したいところです。

AppleScript名:URLにリソースが存在するかチェック v2
– Created 2016-10-10 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4254

set aStr to “http://piyocast.com/as/wp-content/uploads/2016/10/xfinder2.jpg.pagespeed.ic.jFDNAr4CuI.jpg”

set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me

exRes
–> true / false

headerRes
–> (NSDictionary) {Connection:”Keep-Alive”, Content-Type:”image/jpeg”, Server:”Apache”, Last-Modified:”Mon, 10 Oct 2016 03:43:53 GMT”, Expires:”Tue, 10 Oct 2017 03:43:53 GMT”, Cache-Control:”max-age=31536000″, Accept-Ranges:”bytes”, Date:”Mon, 10 Oct 2016 05:24:38 GMT”, Keep-Alive:”timeout=1, max=100″, Content-Length:”4383″, Etag:”W/”0″”}

aData
–> (NSData)

set conType to (headerRes’s valueForKey:“Content-Type”) as string
–>  ”image/jpeg”

set modDate to (headerRes’s valueForKey:“Last-Modified”) as string
–>  ”Mon, 10 Oct 2016 03:43:53 GMT”

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
set hRes to (bRes’s allHeaderFields())
  
set aResCode to (bRes’s statusCode()) as integer
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★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 

2016/03/03 REST APIを呼ぶじっけん

Web上のREST APIのサービスを呼び出すAppleScriptです。

なかなか呼び出すのに苦労させられていたWeb上のREST APIを呼び出すための実験的なAppleScriptのコードです。

いろいろなAPIを見て回っていると、音声認識APIなどは音声ファイルをアップロードしてやる必要があるケースもあるため、こんな簡単な呼び出し方だけでは済まないようですが、、、

rest1.png

とりあえず、REST APIのテスト用アプリケーション「Cocoa Rest Client」で呼べることを確認したAPIについて、AppleScriptの実行結果と付け合わせて納得できる内容が得られたので、満足しています。

rest2.png

ほかにも、githubのREST APIを呼んでみたところ、きちんと結果が取得できました。

AppleScript名:REST APIを呼ぶじっけん
– Created 2016-03-03 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set reqURLStr to "http://demos.xojo.com/EEWS/index.cgi/GetAllCustomers"
–set reqURLStr to "https://api.github.com/repos/mmattozzi/cocoa-rest-client/releases"

set aRequest to current application’s NSURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:reqURLStr)
set respF to false
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
set resList to aRes as list
log {length of resList}
–> {2}

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)
–>  (NSString) "{"GetAllCustomers":{"10174":{"FirstName":"Abdul","LastName":"Mcconnell","City":"Colorado Springs","State":"CO","Zip":"80935"},….

–Get Response Code
set cRes to contents of second item of resList
set resCode to cRes’s statusCode()
–>  404

–Get Response Header
set resHeaders to cRes’s allHeaderFields()
–>  (NSDictionary) {Content-Encoding:"gzip", Content-Type:"text/html; charset=UTF-8", Content-Length:"5376", Connection:"close", Server:"Apache/2.2.15 (CentOS)", Date:"Thu, 03 Mar 2016 13:44:22 GMT"}

★Click Here to Open This Script 

2016/02/09 指定URLのJSONをダウンロードしてRecordに変換 v2.1

指定URLのJSONデータを取得して、結果をrecordに変換するAppleScriptです。AppleScript Libraries「BridgePlus」を利用するように変更してみました。

AppleScript名:指定URLのJSONをダウンロードしてRecordに変換 v2.1
– Created 2016-02-06 by Takaaki Naganoya
– Modified 2016-02-08 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

–東京電力電力供給状況API JSON URL(指定された日時の電力使用状況を返す)
set a to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/2016/2/6/19.json”) of me
–>  {forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3720, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 11:05:05″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:19, entryfor:”2016-02-06 10:00:00″}

–東京電力電力供給状況API JSON URL(指定された日の毎時の電力使用状況を、配列として返す)
set b to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/2016/2/6.json”) of me
–>  {{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3081, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-05 16:05:06″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:”2016-02-05 15:00:00″}…….{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3645, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 12:05:07″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:”2016-02-06 11:00:00″}}

–東京電力電力供給状況API JSON URL(指定された月の毎日毎時の電力使用状況を、配列として返す)
set c to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/2016/2.json”) of me
–>  {{forecast_peak_period:18, forecast_peak_usage:4260, capacity_updated:”2012-01-31 23:30:00″, usage:2901, forecast_peak_updated:”2012-01-31 23:30:00″, day:1, usage_updated:”2016-01-31 16:05:04″, capacity:4641, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:”2016-01-31 15:00:00″}……{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3645, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 12:05:07″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:”2016-02-06 11:00:00″}}

on downloadAndParseJSON(aURL)
  set aRes to downloadDataFromWeb(aURL, 30) of me
  
if aRes = false then return false –download error
  
  
set jsonString to current application’s NSString’s stringWithString:aRes
  
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)
  
  
set bRes to ASify from aJsonDict
  
return bRes
end downloadAndParseJSON

on downloadDataFromWeb(aURL, timeOutSec)
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeOutSec
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
  
if urlRes = missing value then
    return false –Download Error
  else
    set aVal to (current application’s NSString’s alloc()’s initWithData:urlRes encoding:(current application’s NSUTF8StringEncoding))
    
return aVal
  end if
end downloadDataFromWeb

★Click Here to Open This Script 

2016/02/06 指定URLのJSONをダウンロードしてRecordに変換 v2

指定URLのJSONデータを取得して、結果をrecordに変換するAppleScriptです。結果をrecordとして返すAPIのほかrecordのlistで返すものもあるようなので、対応させてみました。

AppleScript名:指定URLのJSONをダウンロードしてRecordに変換 v2
– Created 2016-02-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

on run
  –東京電力電力供給状況API JSON URL(指定された日時の電力使用状況を返す)
  
set a to downloadAndParseJSON("http://tepco-usage-api.appspot.com/2016/2/6/19.json") of me
  
–>  {forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3720, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-06 11:05:05", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:19, entryfor:"2016-02-06 10:00:00"}
  
  
–東京電力電力供給状況API JSON URL(指定された日の毎時の電力使用状況を、配列として返す)
  
set b to downloadAndParseJSON("http://tepco-usage-api.appspot.com/2016/2/6.json") of me
  
–>  {{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3081, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-05 16:05:06", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:"2016-02-05 15:00:00"}…….{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3645, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-06 12:05:07", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:"2016-02-06 11:00:00"}}
  
  
  
–東京電力電力供給状況API JSON URL(指定された月の毎日毎時の電力使用状況を、配列として返す)
  
set c to downloadAndParseJSON("http://tepco-usage-api.appspot.com/2016/2.json") of me
  
–>  {{forecast_peak_period:18, forecast_peak_usage:4260, capacity_updated:"2012-01-31 23:30:00", usage:2901, forecast_peak_updated:"2012-01-31 23:30:00", day:1, usage_updated:"2016-01-31 16:05:04", capacity:4641, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:"2016-01-31 15:00:00"}……{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3645, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-06 12:05:07", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:"2016-02-06 11:00:00"}}
  
end run

on downloadAndParseJSON(aURL)
  set aRes to downloadDataFromWeb(aURL, 30) of me
  
if aRes = false then return false –download error
  
  
set jsonString to current application’s NSString’s stringWithString:aRes
  
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)
  
  
—-recordとして評価して返す
  
try
    set aRec to aJsonDict as record
  end try
  
—-recordのlistとして評価して返す
  
try
    set aRec to aJsonDict as list
  on error
    return false
  end try
  
—–
  
return aRec
  
end downloadAndParseJSON

on downloadDataFromWeb(aURL, timeOutSec)
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeOutSec
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
  
if urlRes = missing value then
    return false –Download Error
  else
    set aVal to (current application’s NSString’s alloc()’s initWithData:urlRes encoding:(current application’s NSUTF8StringEncoding))
    
return aVal
  end if
end downloadDataFromWeb

★Click Here to Open This Script 

2016/02/06 指定URLのJSONをダウンロードしてRecordに変換

指定URLのJSONデータを取得して、結果をrecordに変換するAppleScriptです。

Web上でいろいろサンプルを見繕っていたら、シンプルな例がなかなか存在しないため(わざと複雑に書いてあるのはなぜなんだろう?)、自分で簡単な例を書いてみました。

呼び出しているJSONのサービスは、@ssciさんが提供されている東京電力の最新の電力使用状況を返すものです。返ってくるデータの詳細については、「APIの使い方」をご参照ください

AppleScript名:指定URLのJSONをダウンロードしてRecordに変換
– Created 2015-12-16 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

on run
  –東京電力電力供給状況API JSON URL(最新の電力使用状況を返す)
  
set a to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/latest.json”) of me
  
return a
  
–>  {forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3720, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 11:05:05″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:19, entryfor:”2016-02-06 10:00:00″}
end run

on downloadAndParseJSON(aURL)
  set aRes to downloadDataFromWeb(aURL, 30) of me
  
if aRes = false then return false –download error
  
  
set jsonString to current application’s NSString’s stringWithString:aRes
  
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)
  
  
try
    set aRec to aJsonDict as record
  on error
    set aRec to false
  end try
  
  
return aRec
end downloadAndParseJSON

on downloadDataFromWeb(aURL, timeOutSec)
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeOutSec
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
  
if urlRes = missing value then
    return false –Download Error
  else
    set aVal to (current application’s NSString’s alloc()’s initWithData:urlRes encoding:(current application’s NSUTF8StringEncoding))
    
return aVal
  end if
end downloadDataFromWeb

★Click Here to Open This Script 

2015/12/16 ASOCでインターネット接続確認

Cocoaの機能を用いたインターネット接続確認を行うAppleScriptです。

やり方はAppleScriptでもObjective-Cでも変わらないというか、AppleScriptでもはるかかなた昔から行われているやり方で使う道具が違うだけとか、そういう感じです。

AppleScript名:ASOCでインターネット接続確認
– Created 2015-12-16 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aRes to hasInternetConnection() of me
–>  true

on hasInternetConnection()
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:“http://www.google.com”
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:5.0
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
if urlRes = missing value then
    return false
  else
    return true
  end if
end hasInternetConnection

★Click Here to Open This Script 

2015/09/09 指定URLのファイルをダウンロード

Cocoaの機能を用いて、指定URLのファイルをダウンロードするAppleScriptです。

書いている途中でどうしてもNSURLErrorDomain Error 3001が出てダウンロードできなかったのですが、それはダウンロード先をファイル名まで指定していなかったからでした(Appleのサンプルどおりに書いたのに!)。

最初の掲載時にはcachePolicyにNSURLRequestUseProtocolCachePolicyを指定していたのですが、ネット非接続時も正常終了したり、キャッシュが効いて最新版が取得できないなどの問題を見かけたため、NSURLRequestReloadIgnoringLocalCacheDataに変更しました。

AppleScript名:ASOCで指定URLのファイルをダウンロード
– Created 2015-09-09 Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–https://developer.apple.com/library/mac/documentation/Cocoa/
– Conceptual/URLLoadingSystem/Tasks/UsingNSURLDownload.html

property dlF : false
property dlTimeOutSec : 60.0

set my dlF to false

–DL先はファイル名まで指定しないとエラー(Error 3001)になる
set theDLdir to (current application’s NSHomeDirectory())’s stringByAppendingPathComponent:“Desktop/index.html”
–>  (NSString) “/Users/me/Desktop”

downloadFrom(“http://www.apple.com/jp/index.html”, theDLdir) of me

set waitLoop to 1000 * dlTimeOutSec –60 seconds
set hitF to false
repeat waitLoop times
  if my dlF is not equal to false then
    set hitF to true
    
exit repeat
  end if
  
current application’s NSThread’s sleepForTimeInterval:(“0.001″ as real) –delay 0.001
end repeat
if hitF = false then return
return dlF
–>  true

on downloadFrom(aURLstr, dlDir)
  
  
set aURL to current application’s |NSURL|’s URLWithString:aURLstr
  
–>  (NSURL) http://www.apple.com
  
  
set theReq to current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:dlTimeOutSec
  
–>  (NSURLRequest) { URL: http://www.apple.com }
  
  
set theDownload to current application’s NSURLDownload’s alloc()’s initWithRequest:theReq delegate:me
  
–>  (NSURLDownload) { request: { URL: http://www.apple.com } }
  
  
theDownload’s setDestination:dlDir allowOverwrite:true
  
end downloadFrom

–Download Error Event Handler
on download:aDownload didFailWithError:anError
  set anErrorStr to anError’s localizedDescription()
  
set errorReason to (anError’s userInfo())’s objectForKey:(current application’s NSURLErrorFailingURLStringErrorKey)
  
set my dlF to {anErrorStr, errorReason}
end download:didFailWithError:

–Download Finished Event Handler
on downloadDidFinish:aDownload
  set my dlF to true
end downloadDidFinish:

★Click Here to Open This Script