之前倒騰豆瓣 API 的時候就想看看自己從標記上「想讀」到「讀過」要花多長時間。但我每次買書都會把看過的書的標記刪掉,其實就是把豆瓣讀書當作購書單。這樣的壞處就是沒法拿到「想讀」的時間了。不過好在標記「想讀」的同時,豆瓣會自動幫我發一條廣播。可以從廣播裏找回來。
那麼問題來了,豆瓣廣播的所有 API 操作必須登錄,而要登錄必須豆瓣授權,可是豆瓣已經關閉授權申請了。這不「第二十二條軍規」嘛😒
然後想到,瀏覽器不有 從 cookie 嘛,讓瀏覽器去抓廣播的頁面。這不就繞開了!好了:
- 找個能操縱 GUI 的膠水把廣播頁面 down 下來;
- 找個 HTML 解析庫揀出數據;
- 導到 Excel/Numbers 之類的小型數據庫裏畫圖。
結果……每一步都是坑啊😭 從晚上一直幹到第二天凌晨五點才有些眉目。接着九點半又爬起來弄了會才搞定。
就像好的程序會提供「圖形界面」和「命令行」兩套接口一樣,好的網站也會提供「服務於人的頁面」和「服務於程序」的 API 。
呃~豆瓣是個好網站!
先說第一步吧。想用 Python 的 pyautogui 來着,沒裝上。然後想找找有沒有 Ruby 版的 AutoIt 。突然想到,那還不如用 Automator 或者 AppleScript 呢。又試了下 Automator ,功能太簡單,轉向 AppleScript 。
AppleScript 坑
沒曾想這才是個大坑呢!連 Apple 官方的文檔都打不開。各種查資料才湊出段勉強能用的腳本。其實 AppleScript 設計得挺好的,就是不知道爲啥網上的資料大多沒講到點子上。
大家說「Mac 接口統一」,其實意思是「在圖形界面之外,還有一套不可見、卻能爲程序訪問的第二界面。那是機器之間的悄悄話」。是的,好程序都有兩套接口。所以,好程序更複雜,而不是更簡單。
在 Mac 上,這套「程序之間的黑話」叫「Apple events」。其實任何一個 Mac 程序都是一個服務器,只不過它們之間是經由 Apple Event Manager 用 Apple events 來傳遞信息。而 AppleScript 就是把 Apple events 包裝了下。而能聽懂這套黑話的程序叫做「AppleScriptable applications」。AppleScript 的能力邊界取決於它黏合的那些程序能幹什麼。
接下來,請記住:這套黑話是爲了方便其他程序能夠理解。
就像一篇文章由段落構成,段落由句子構成,句子由成分構成,成分由單詞構成,單詞由字母構成,AppleScript 是以 object 爲單位來組織架構的。object 是包含一定信息的某種抽象。之所以抽取出這些信息片段,是爲了方便其他程序理解。AppleScript 內置了一些基本的 object ,比如:numbers, strings, dates ...
42
3.14
"Hello, World!"
date "Friday, Sep 16, 2016"
{2, 3, 17, 18, 43, 45}
理解 AppleScript 的關鍵之一,就是弄清楚程序是怎麼來組織信息的,這些信息單元又對應於哪些 objects,可以通過哪些 commands 來操作這些 objects 。
之前接觸 AppleScript 的時候,之所以覺得一地雞毛、零碎得很的原因就在於沒有弄清楚操作對象的 objects 組織架構(也就是 objets model)。
有三種方法可以操控 object ,分別是:command, operactor, variable.
而把這些黏合起來的,就是「控制語句」:
- 我該不該做這個? Should I do this?
- 我該做多少次? How often should I do this?
- 要是出錯了怎麼辦? What should I do if things go wrong?
以及某種抽象機制——handlers[1] & script objects.
神奇的是,AppleScript 的 handlers 允許先調用,後定義[2]😱 但不允許嵌套定義。
但,最最神奇的是,AppleScript 允許一套通過標籤(而非位置)來傳遞參數的方式定義 handler 。既可以是預定義的標籤[^predefined label],也可以是自定義標籤[^user label]。這才是 AppleScript 敢把自己叫做「English-like」語言的原因。
[^predefined label]: predefined labels 有23個:about
, above
, against
, apart from
, around
, aside from
, at
, below
, beneath
, beside
, between
, by
, for
, from
, instead of
, into
, on
, onto
, out of
, over
, since
, thru
(or through
), and under
. 另外,第一個參數可以用in
或of
來標識,但僅限於第一個參數。
[^user label]: user labels 用given
來標識。如果自定義標籤所指示的參數是 boolean 變量,在調用時可以用with
來設置爲true
,或者用without
來設置爲false
。
用腳本去操控程序,根本就不是去模擬人的點擊、鍵入……,而是腳本直接與程序對話。AppleScript 中類似「點擊」「鍵入」……等動作的操作,就是 commands 。
所有的程序會響應 run, open, quit 這些指令。有的程序還會提供自己的特有指令。人,是通過點擊 menus, buttons 這些圖形元素來操縱程序。而程序通過 commands 來操控其他程序。既然是指令,就需要有作用對象。這樣,commands 就和 objects 綁定起來了。
nokogiri 坑
……