Emacs から HTTP リクエストを送信する

Nov 29, 2009   #Emacs  :

id:hayamiz さんの twittering-mode のソースをのぞいていると、 Emacs だけで HTTP リクエストを送信していることを発見した。 Web 経由の API って、基本的には  HTTP の get か post リクエストなんだから、 Emacs から Web API を利用することが出来るのではないかと考えてみた。

というわけで、 Google Mapジオコーディング API を使用してみようと考えてみました…でも、まだ途中です。とりあえず xml でレスポンスを入手するところまで出来ました。基本的には id:hayamiz さんのソースをぱくり参考にさせていただいております。

ソース

「*test-buffer*」というバッファーに HTTP レスポンスを表示させ、そこからごちゃごちゃと処理する流れになっています。

(require 'xml)
;; バッファーが存在しなければ、バッファーを作成する
(defun GMap-get-or-generate-buffer (buffer)
(if (bufferp buffer)
(if (buffer-live-p buffer)
buffer
(generate-new-buffer (buffer-name buffer)))
(if (stringp buffer)
(or (get-buffer buffer)
(generate-new-buffer buffer)))))
;; HTTP GETリクエストを送信する
(defun GMap-http-get (address)
"A method for sending http GET request to maps.google.com"
(GMap-get-or-generate-buffer "*test-buffer*")
(save-excursion
(set-buffer "*test-buffer*")
(erase-buffer))
(let
((proc nil)
(query (url-hexify-string address)))
(condition-case nil
(progn
(setq proc
(open-network-stream
"GMap-connection-process" "*test-buffer*"
"maps.google.com" 80))
(set-process-sentinel proc 'test-sentinel)
(process-send-string
proc
(let ((nl "\r\n"))
(concat "GET /maps/geo?output=xml&hl=ja&q="
query
"&ie=UTF8&oe=UTF8 HTTP/1.1" nl
"Host: maps.google.com" nl
"Keep-Alive: 10" nl
"Accept: text/xml"
",application/xhtml+xml"
",application/html;q=0.9"
",text/plain;q=0.8" nl
"Accept-Charset: utf-8;q=0.7,*;q=0.7" nl
"Connection: close"
nl nl))))
(error
(message "Failure: HTTP GET") nil))))
;; HTTP レスポンスからヘッダーの部分を抽出する
(defun GMap-extract-http-response-header (&optional buffer)
"A method for extracting http response. You need to give the buffer name as the argument."
(save-excursion
(set-buffer "*test-buffer*")
(let ((content (buffer-string)))
(substring content  (string-match "\r?\n\r?\n" content)))))
;; HTTP レスポンスからボディーの部分(XML)を抽出する
(defun GMap-extract-http-response-body (&optional buffer)
"A method for extracting http response body from HTTP response."
(if (stringp buffer) (setq buffer (get-buffer buffer)))
(if (null buffer) (setq buffer "*test-buffer*"))
(save-excursion
(set-buffer buffer)
(let ((content (buffer-string)))
(xml-parse-region (+ (string-match "\r?\n\r?\n" content)
(length (match-string  content)))
(point-max)))))
;; GET リクエストを送信して、レスポンスが返ってきたら実行される関数
(defun test-sentinel (proc state)
(let ((header (GMap-extract-http-response-header))
(status nil))
(if (string-match "HTTP/1\.[01] \\([A-Z0-9 ]+\\)\r?\n" header)
(progn
(setq status (match-string-no-properties 1 header))
(case-string
status
(("200 OK")
(message "Success: Get."))
(t (message status))))
(message "Failure: Bad HTTP response."))))

実行例

下記のコマンドを実行してみてください。とりあえずレスポンスは取得できています。後はこれをどうつかうかだな:

(GMap-http-get "横浜")
(GMap-extract-http-response-header)
(GMap-extract-http-response-body)

参考

やさしいEmacs‐Lisp講座

やさしいEmacs‐Lisp講座