blog/content/post/2009/11/29/2009-11-29-00001279.md

167 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Emacs から HTTP リクエストを送信する
author: kazu634
date: 2009-11-29
wordtwit_post_info:
- 'O:8:"stdClass":13:{s:6:"manual";b:0;s:11:"tweet_times";i:1;s:5:"delay";i:0;s:7:"enabled";i:1;s:10:"separation";s:2:"60";s:7:"version";s:3:"3.7";s:14:"tweet_template";b:0;s:6:"status";i:2;s:6:"result";a:0:{}s:13:"tweet_counter";i:2;s:13:"tweet_log_ids";a:1:{i:0;i:4957;}s:9:"hash_tags";a:0:{}s:8:"accounts";a:1:{i:0;s:7:"kazu634";}}'
categories:
- Emacs
---
<div class="section">
<p>
<a href="http://d.hatena.ne.jp/hayamiz/" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://d.hatena.ne.jp/hayamiz/', 'id:hayamiz');">id:hayamiz</a> さんの twittering-mode のソースをのぞいていると、 Emacs だけで HTTP リクエストを送信していることを発見した。 Web 経由の API って、基本的には  HTTP の get か post リクエストなんだから、 Emacs から Web API を利用することが出来るのではないかと考えてみた。
</p>
<p>
というわけで、 Google Mapジオコーディング API を使用してみようと考えてみました…でも、まだ途中です。とりあえず xml でレスポンスを入手するところまで出来ました。基本的には <a href="http://d.hatena.ne.jp/hayamiz/" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://d.hatena.ne.jp/hayamiz/', 'id:hayamiz');">id:hayamiz</a> さんのソースを<strike>ぱくり</strike>参考にさせていただいております。
</p>
<h4>
ソース
</h4>
<p>
「*test-buffer*」というバッファーに HTTP レスポンスを表示させ、そこからごちゃごちゃと処理する流れになっています。
</p>
<pre class="syntax-highlight">
<span class="synSpecial">(</span><span class="synStatement">require</span> <span class="synSpecial">'</span><span class="synIdentifier">xml</span><span class="synSpecial">)</span>
<span class="synComment">;; バッファーが存在しなければ、バッファーを作成する</span>
<span class="synSpecial">(</span><span class="synStatement">defun</span> GMap-get-or-generate-buffer <span class="synSpecial">(</span>buffer<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">if</span> <span class="synSpecial">(</span>bufferp buffer<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">if</span> <span class="synSpecial">(</span>buffer-live-p buffer<span class="synSpecial">)</span>
buffer
<span class="synSpecial">(</span>generate-new-buffer <span class="synSpecial">(</span>buffer-name buffer<span class="synSpecial">)))</span>
<span class="synSpecial">(</span><span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">stringp</span> buffer<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">or</span> <span class="synSpecial">(</span>get-buffer buffer<span class="synSpecial">)</span>
<span class="synSpecial">(</span>generate-new-buffer buffer<span class="synSpecial">)))))</span>
<span class="synComment">;; HTTP GETリクエストを送信する</span>
<span class="synSpecial">(</span><span class="synStatement">defun</span> GMap-http-get <span class="synSpecial">(</span>address<span class="synSpecial">)</span>
<span class="synConstant">&#34;A method for sending http GET request to maps.google.com&#34;</span>
<span class="synSpecial">(</span>GMap-get-or-generate-buffer <span class="synConstant">&#34;*test-buffer*&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>save-excursion
<span class="synSpecial">(</span>set-buffer <span class="synConstant">&#34;*test-buffer*&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>erase-buffer<span class="synSpecial">))</span>
<span class="synSpecial">(</span><span class="synStatement">let</span>
<span class="synSpecial">((</span>proc <span class="synStatement">nil</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>query <span class="synSpecial">(</span>url-hexify-string address<span class="synSpecial">)))</span>
<span class="synSpecial">(</span>condition-case <span class="synStatement">nil</span>
<span class="synSpecial">(</span><span class="synStatement">progn</span>
<span class="synSpecial">(</span><span class="synStatement">setq</span> proc
<span class="synSpecial">(</span>open-network-stream
<span class="synConstant">&#34;GMap-connection-process&#34;</span> <span class="synConstant">&#34;*test-buffer*&#34;</span>
<span class="synConstant">&#34;maps.google.com&#34;</span> <span class="synConstant">80</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>set-process-sentinel proc <span class="synSpecial">'</span><span class="synIdentifier">test-sentinel</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>process-send-string
proc
<span class="synSpecial">(</span><span class="synStatement">let</span> <span class="synSpecial">((</span>nl <span class="synConstant">&#34;\r\n&#34;</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>concat <span class="synConstant">&#34;GET /maps/geo?output=xml&#38;hl=ja&#38;q=&#34;</span>
query
<span class="synConstant">&#34;&#38;ie=UTF8&#38;oe=UTF8 HTTP/1.1&#34;</span> nl
<span class="synConstant">&#34;Host: maps.google.com&#34;</span> nl
<span class="synConstant">&#34;Keep-Alive: 10&#34;</span> nl
<span class="synConstant">&#34;Accept: text/xml&#34;</span>
<span class="synConstant">&#34;,application/xhtml+xml&#34;</span>
<span class="synConstant">&#34;,application/html;q=0.9&#34;</span>
<span class="synConstant">&#34;,text/plain;q=0.8&#34;</span> nl
<span class="synConstant">&#34;Accept-Charset: utf-8;q=0.7,*;q=0.7&#34;</span> nl
<span class="synConstant">&#34;Connection: close&#34;</span>
nl nl<span class="synSpecial">))))</span>
<span class="synSpecial">(</span><span class="synStatement">error</span>
<span class="synSpecial">(</span>message <span class="synConstant">&#34;Failure: HTTP GET&#34;</span><span class="synSpecial">)</span> <span class="synStatement">nil</span><span class="synSpecial">))))</span>
<span class="synComment">;; HTTP レスポンスからヘッダーの部分を抽出する</span>
<span class="synSpecial">(</span><span class="synStatement">defun</span> GMap-extract-http-response-header <span class="synSpecial">(</span>&#38;optional buffer<span class="synSpecial">)</span>
<span class="synConstant">&#34;A method for extracting http response. You need to give the buffer name as the argument.&#34;</span>
<span class="synSpecial">(</span>save-excursion
<span class="synSpecial">(</span>set-buffer <span class="synConstant">&#34;*test-buffer*&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">let</span> <span class="synSpecial">((</span>content <span class="synSpecial">(</span>buffer-string<span class="synSpecial">)))</span>
<span class="synSpecial">(</span>substring content <span class="synConstant"></span> <span class="synSpecial">(</span>string-match <span class="synConstant">&#34;\r?\n\r?\n&#34;</span> content<span class="synSpecial">)))))</span>
<span class="synComment">;; HTTP レスポンスからボディーの部分(XML)を抽出する</span>
<span class="synSpecial">(</span><span class="synStatement">defun</span> GMap-extract-http-response-body <span class="synSpecial">(</span>&#38;optional buffer<span class="synSpecial">)</span>
<span class="synConstant">&#34;A method for extracting http response body from HTTP response.&#34;</span>
<span class="synSpecial">(</span><span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">stringp</span> buffer<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synStatement">setq</span> buffer <span class="synSpecial">(</span>get-buffer buffer<span class="synSpecial">)))</span>
<span class="synSpecial">(</span><span class="synStatement">if</span> <span class="synSpecial">(</span><span class="synStatement">null</span> buffer<span class="synSpecial">)</span> <span class="synSpecial">(</span><span class="synStatement">setq</span> buffer <span class="synConstant">&#34;*test-buffer*&#34;</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>save-excursion
<span class="synSpecial">(</span>set-buffer buffer<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">let</span> <span class="synSpecial">((</span>content <span class="synSpecial">(</span>buffer-string<span class="synSpecial">)))</span>
<span class="synSpecial">(</span>xml-parse-region <span class="synSpecial">(</span><span class="synStatement">+</span> <span class="synSpecial">(</span>string-match <span class="synConstant">&#34;\r?\n\r?\n&#34;</span> content<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">length</span> <span class="synSpecial">(</span>match-string <span class="synConstant"></span> content<span class="synSpecial">)))</span>
<span class="synSpecial">(</span>point-max<span class="synSpecial">)))))</span>
<span class="synComment">;; GET リクエストを送信して、レスポンスが返ってきたら実行される関数</span>
<span class="synSpecial">(</span><span class="synStatement">defun</span> test-sentinel <span class="synSpecial">(</span>proc state<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">let</span> <span class="synSpecial">((</span>header <span class="synSpecial">(</span>GMap-extract-http-response-header<span class="synSpecial">))</span>
<span class="synSpecial">(</span>status <span class="synStatement">nil</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span><span class="synStatement">if</span> <span class="synSpecial">(</span>string-match <span class="synConstant">&#34;HTTP/1\.[01] \\([A-Z0-9 ]+\\)\r?\n&#34;</span> header<span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">progn</span>
<span class="synSpecial">(</span><span class="synStatement">setq</span> status <span class="synSpecial">(</span>match-string-no-properties <span class="synConstant">1</span> header<span class="synSpecial">))</span>
<span class="synSpecial">(</span>case-string
status
<span class="synSpecial">((</span><span class="synConstant">&#34;200 OK&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>message <span class="synConstant">&#34;Success: Get.&#34;</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span><span class="synStatement">t</span> <span class="synSpecial">(</span>message status<span class="synSpecial">))))</span>
<span class="synSpecial">(</span>message <span class="synConstant">&#34;Failure: Bad HTTP response.&#34;</span><span class="synSpecial">))))</span>
</pre>
<p>
</p>
<h4>
実行例
</h4>
<p>
下記のコマンドを実行してみてください。とりあえずレスポンスは取得できています。後はこれをどうつかうかだな:
</p>
<pre class="syntax-highlight">
<span class="synSpecial">(</span>GMap-http-get <span class="synConstant">&#34;横浜&#34;</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span>GMap-extract-http-response-header<span class="synSpecial">)</span>
<span class="synSpecial">(</span>GMap-extract-http-response-body<span class="synSpecial">)</span>
</pre>
<h4>
参考
</h4>
<ul>
<li>
<a href="http://www.asahi-net.or.jp/~pw9s-szk/emacs/elisp_net.html" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://www.asahi-net.or.jp/~pw9s-szk/emacs/elisp_net.html', 'elisp でのネットワークプログラム');" target="_blank">elisp でのネットワークプログラム</a>
</li>
</ul>
<div class="hatena-asin-detail">
<a href="http://www.amazon.co.jp/dp/4906391702/?tag=hatena_st1-22&ascsubtag=d-7ibv" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://www.amazon.co.jp/dp/4906391702/?tag=hatena_st1-22&ascsubtag=d-7ibv', '');"><img src="https://images-na.ssl-images-amazon.com/images/I/51C4N4SHT7L._SL160_.jpg" class="hatena-asin-detail-image" alt="やさしいEmacsLisp講座" title="やさしいEmacsLisp講座" /></a></p>
<div class="hatena-asin-detail-info">
<p class="hatena-asin-detail-title">
<a href="http://www.amazon.co.jp/dp/4906391702/?tag=hatena_st1-22&ascsubtag=d-7ibv" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://www.amazon.co.jp/dp/4906391702/?tag=hatena_st1-22&ascsubtag=d-7ibv', 'やさしいEmacsLisp講座');">やさしいEmacsLisp講座</a>
</p>
<ul>
<li>
<span class="hatena-asin-detail-label">作者:</span> <a href="http://d.hatena.ne.jp/keyword/%B9%AD%C0%A5%CD%BA%C6%F3" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://d.hatena.ne.jp/keyword/%B9%AD%C0%A5%CD%BA%C6%F3', '広瀬雄二');" class="keyword">広瀬雄二</a>
</li>
<li>
<span class="hatena-asin-detail-label">出版社/メーカー:</span> <a href="http://d.hatena.ne.jp/keyword/%A5%AB%A5%C3%A5%C8%A5%B7%A5%B9%A5%C6%A5%E0" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://d.hatena.ne.jp/keyword/%A5%AB%A5%C3%A5%C8%A5%B7%A5%B9%A5%C6%A5%E0', 'カットシステム');" class="keyword">カットシステム</a>
</li>
<li>
<span class="hatena-asin-detail-label">発売日:</span> 1999/01
</li>
<li>
<span class="hatena-asin-detail-label">メディア:</span> 単行本
</li>
<li>
<span class="hatena-asin-detail-label">購入</span>: 4人 <span class="hatena-asin-detail-label">クリック</span>: 145回
</li>
<li>
<a href="http://d.hatena.ne.jp/asin/4906391702" onclick="__gaTracker('send', 'event', 'outbound-article', 'http://d.hatena.ne.jp/asin/4906391702', 'この商品を含むブログ (30件) を見る');" target="_blank">この商品を含むブログ (30件) を見る</a>
</li>
</ul>
</div>
<div class="hatena-asin-detail-foot">
</div>
</div>
</div>