Enliveをさわってみたのでメモ

Enliveをさわってみたのでメモ。

導入

  • project.clj の :dependencies に下記を追加
[enlive "1.1.5"]

REPLから試用

user=> (use 'net.cgrand.enlive-html)
nil

user=> (dir net.cgrand.enlive-html)
(中略)
html
html-content
html-resource
html-snippet
(中略)
select
(以下略)
html関数
user=> (doc html)
-------------------------
net.cgrand.enlive-html/html
([& nodes-specs])
  Allows to define inline fragments with a hiccup-like syntax.
nil

user=> (html [:div {:id "divHoge"} [:input {:id "textHoge" :type "text"}]])
({:tag :div, :attrs {:id "divHoge"}, :content ({:tag :input, :attrs {:type "text", :id "textHoge"}, :content ()})})
html-resource関数
user=> (doc html-resource)
-------------------------
net.cgrand.enlive-html/html-resource
([resource] [resource options])
  Loads an HTML resource, returns a seq of nodes.
nil

user=> ; clojure.java.io の reader 関数を用いて HTML resource を取得して渡してみる
user=> (use 'clojure.java.io)
nil

user=> (doc reader)
-------------------------
clojure.java.io/reader
([x & opts])
  Attempts to coerce its argument into an open java.io.Read
   Default implementations always return a java.io.Buffered

   Default implementations are provided for Reader, Buffere
   InputStream, File, URI, URL, Socket, byte arrays, charac
   and String.

   If argument is a String, it tries to resolve it first as
   as a local file name.  URIs with a 'file' protocol are c
   local file names.

   Should be used inside with-open to ensure the Reader is
   closed.
nil

user=> (reader "http://google.com")
#<BufferedReader java.io.BufferedReader@1969526c>

user=> (html-resource (reader "http://google.com"))
({:type :dtd, :data ["html" nil nil]} {:tag :html, :attrs {
(以下略)
select関数
user=> (doc select)
-------------------------
net.cgrand.enlive-html/select
([node-or-nodes selector])
  Returns the seq of nodes or fragments matched by the specified selector.
nil

user=> (select
  #_=>   (html [:div {:id "divHoge"} [:input {:id "textHoge" :type "text"}]])
  #_=>   [:input])
({:tag :input, :attrs {:type "text", :id "textHoge"}, :content ()})

user=> (select
  #_=>   (html [:div {:id "divHoge"} [:input {:id "textHoge" :type "text"}] [:input {:id "textToge" :type "check"}]])
  #_=>   [:input#textToge])
({:tag :input, :attrs {:type "check", :id "textToge"}, :content ()})

user=> (select
  #_=>   (html [:html [:div {:id "divHoge"} [:input {:id "textHoge" :type "text"}]] [:input {:id "textToge" :type "check"}]])
  #_=>   [:div :input])
({:tag :input, :attrs {:type "text", :id "textHoge"}, :content ()})

user=> (select
  #_=>   (html [:html [:div {:id "divHoge"} [:input {:id "textHoge" :type "text"}]] [:input {:id "textToge" :type "check"}]])
  #_=>   #{[:div :input] [:#textToge]})
({:tag :input, :attrs {:type "text", :id "textHoge"}, :content ()} {:tag :input, :attrs {:type "check", :id "textToge"}, :content ()})

実用

強引感が半端ないが、Yahoo!ファイナンスから板気配を取得するコードを書いてみた。

(use 'net.cgrand.enlive-html)
(use 'clojure.java.io)

(defn kehai-url
  [meigara-code]
  (str "http://stocks.finance.yahoo.co.jp/stocks/detail/?code="
       meigara-code
       "."
       "T"))

(defn kehai
  [meigara-code]
  (let [[title-row row1 row2]
        (select
          (html-resource (reader (kehai-url meigara-code)))
          [:.main2colL :table :tr])]
    {:meigara-code meigara-code
     :uri-kehai
      (first
        (:content
          (first
            (select row1 [[:td (nth-of-type 1)]]))))
     :uri-kehai-kabuka
      (first
        (:content
          (first
            (select row1 [[:td (nth-of-type 3)] :strong]))))
     :kai-kehai
      (first
        (:content
          (first
            (select row2 [[:td (nth-of-type 5)]]))))
     :kai-kehai-kabuka
      (first
        (:content
          (first
            (select row2 [[:td (nth-of-type 3)] :strong]))))}))
user=> (map kehai [4689 4755])
({:meigara-code 4689, :uri-kehai "---", :uri-kehai-kabuka "---", :kai-kehai "---", :kai-kehai-kabuka "---"} 
{:meigara-code 4755, :uri-kehai "---", :uri-kehai-kabuka "---", :kai-kehai "---", :kai-kehai-kabuka "---"})