clojure.core/map-isn';行不通
我正在试图弄清楚为什么我的一个map调用不起作用。我正在构建一个爬虫,目的是学习Clojureclojure.core/map-isn';行不通,clojure,Clojure,我正在试图弄清楚为什么我的一个map调用不起作用。我正在构建一个爬虫,目的是学习Clojure (使用“[clojure.java.io]) 但是第二个调用(映射爬网URL)似乎被忽略了 crawl函数按预期工作,对url进行slurp,使用regex解析a标记获取href,并在循环中累积按预期工作,但是当我使用crawl调用map和页面上找到的url时,对map的调用被忽略 如果我尝试调用(映射爬网[“http://www.example.com“])此呼叫再次被忽略 几周前我开始了我的Cl
(使用“[clojure.java.io])
但是第二个调用(映射爬网URL)
似乎被忽略了
crawl
函数按预期工作,对url进行slurp,使用regex解析a
标记获取href,并在循环中累积按预期工作,但是当我使用crawl
调用map
和页面上找到的url
时,对map
的调用被忽略
如果我尝试调用(映射爬网[“http://www.example.com“])
此呼叫再次被忽略
几周前我开始了我的Clojure之旅,因此欢迎提出任何建议/批评
谢谢你在Clojure,map
是懒惰的。从文档中,映射:
返回一个惰性序列,该序列由将f应用于
每个coll的第一个项目集,然后将f应用于该集合
每个coll中的第二项,直到任何一个coll
筋疲力尽
您的爬网功能是一个具有副作用的功能-您正在向文件中吐出一些结果,并打印ln
-ing报告进度。但是,由于map
返回一个惰性序列,这些事情都不会发生——结果序列永远不会显式实现,因此它可以保持惰性
实现惰性序列的方法有很多种(例如使用map
创建的),但在这种情况下,当您想使用具有副作用的函数迭代序列时,最好使用doseq
:
重复执行身体(可能是因为副作用)和
“for”提供的绑定和筛选。不保留
序列的首部。返回零
如果将对(映射爬网URL)
的调用替换为(doseq[u url](爬网u))
,则应该会得到所需的结果
注意:您对map的第一次调用按预期工作,因为您正在使用(apply str)
实现结果。如果不计算顺序,就无法(应用str)
。检查访问过哪些页面的方式有一个小错误:检查(str“theinternet/page”(md5 url))
是否存在,但将文件写入(str“theinternet/(md5 url))
,因此,您将陷入循环中,因为即使在您抓取页面时,它看起来也没有抓取页面。另外:有用的提示:让和defn
包含一个隐式do
,这样就可以包含多个表达式-您不需要在do
中显式地将它们分组在一起。感谢Daniel提供的提示。我已经编辑了文件名,我在其中编写了slurp的结果,我关注的是map
为什么不起作用。如前所述,我已经用doseq
更改了map
,现在一切正常。太好了!我希望你喜欢你的Clojure冒险:)
(defn md5
"Generate a md5 checksum for the given string"
[token]
(let [hash-bytes
(doto (java.security.MessageDigest/getInstance "MD5")
(.reset)
(.update (.getBytes token)))]
(.toString
(new java.math.BigInteger 1 (.digest hash-bytes)) ; Positive and the size of the number
16)))
(defn full-url [url base]
(if (re-find #"^http[s]{0,1}://" url)
url
(apply str "http://" base (if (= \/ (first url))
url
(apply str "/" url)))))
(defn get-domain-from-url [url]
(let [matcher (re-matcher #"http[s]{0,1}://([^/]*)/{0,1}" url)
domain-match (re-find matcher)]
(nth domain-match 1)))
(defn crawl [url]
(do
(println "-----------------------------------\n")
(if (.exists (clojure.java.io/as-file (apply str "theinternet/page" (md5 url))))
(println (apply str url " already crawled ... skiping \n"))
(let [domain (get-domain-from-url url)
text (slurp url)
matcher (re-matcher #"<a[^>]*href\s*=\s*[\"\']([^\"\']*)[\"\'][^>]*>(.*)</a\s*>" text)]
(do
(spit (apply str "theinternet/page" (md5 url)) text)
(loop [urls []
a-tag (re-find matcher)]
(if a-tag
(let [u (nth a-tag 1)]
(recur (conj urls (full-url u domain)) (re-find matcher)))
(do
(println (apply str "parsed: " url))
(println (apply str (map (fn [u]
(apply str "-----> " u "\n")) urls)))
(map crawl urls)))))))))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(crawl "http://www.example.com/"))
(println (apply str (map (fn [u]
(apply str "-----> " u "\n")) urls)))