Clojure 爬虫:抓取花瓣网图片
最近刚看完《Clojure程序设计》,书上的例子都能看懂,但要开始用Clojure还是有点不知道怎么下手,想写个小程序练练手。之前用Python写过一个抓取花瓣网美女画板下图片的小爬虫,爬虫过程很简单,也没有涉及登录验证或是反爬虫之类的,用来熟悉新语言非常合适,就有了这个Clojure版的爬虫。
我用Python的实现可以看我之前的博客。
1. 分析网站
花瓣网美女画板的地址是:http://huaban.com/favorite/beauty/ ,访问该地址会展示20张美女图片,当浏览到页面底端,浏览器再通过Ajax加载20幅图片。爬虫也分两部分,抓取美女面板首页图片和抓取Ajax加载的图片。
1.1 抓取首页图片
访问 http://huaban.com/favorite/beauty/ 得到的响应如下:
可以看到,花瓣网的页面是js动态生成的,我们可以不用渲染页面,直接分析js数据,找到图片地址信息。分析对比发现,图片的信息在app.page[“pins”]变量中,是一个json字符串。在json字符串中,对应20个字典,每个字典对应一张图片信息,字典结构类似这种
图片地址与”file”下面的”key”中的内容有关。
1.2 抓取下拉刷新图片
对网站分析发现,访问 http://huaban.com/favorite/beauty/ 只会展示20张图片,之后每次浏览到页面底端,都会通过Ajax请求得到20张新的图片。Ajax请求url为”http://huaban.com/favorite/beauty/?ise2bat0&max=832135275&limit=20&wfl=1",其中832135275是页面最后一张图片的`pin_id`值。
在请求头添加:
1 | "Accept" "application/json" |
模拟Ajax请求,得到图片的json数据,直接解析json数据得到图片地址信息。
2. 编写爬虫
2.1 初始化项目
使用Leiningen构建项目
1 | lein new app clojure-crawle |
项目中用到了两个库,data.json
是处理json数据的,http-kit
是处理http请求的,在project.clj
中添加这两个依赖:
1 | :dependencies [[org.clojure/clojure "1.7.0"] |
2.2 爬取首页图片
获取花瓣网美女标签下的html页面
1
2
3
4
5
6
7
8(defn get-home-page
"请求首页内容"
[]
(let [options {:timeout 1000
:as :text}
url "http://huaban.com/favorite/beauty/"
{:keys [body]} @(http/get url options)]
body))从html页面中获取图片信息json
1
2
3
4(defn get-image-info
"从首页内容得到图片信息"
[page]
(subs (re-find (re-matcher #"page\[\"pins\"\].*;" page)) 15))解析json数据位列表
1
2
3
4(defn str2json
"将json字符串转换为字典"
[body]
(json/read-str body :key-fn keyword))下载一张图片
1
2
3
4
5
6
7(defn download-image
"将图片保存在本地"
[url file-name]
(println (str "download " url))
(with-open [in (io/input-stream url)
out (io/output-stream file-name)]
(io/copy in out)))下载一页20张图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17(defn make-image-url
"根据key值得到图片真实地址"
[k]
(str "http://hbimg.b0.upaiyun.com/" k "_fw658"))
(defn make-file-name
[file-name]
(str image-save-path file-name ".jpg"))
(defn download-images
"根据json字符串下载图片"
[jsons]
(dorun (map (fn [a]
(let [k (:key (:file a)) file-name (:pin_id a)]
(download-image (make-image-url k) (make-file-name file-name))))
jsons))
(:pin_id (last jsons)))美女标签页首页图片的完整下载过程
1
2
3
4
5
6
7(defn download-home-page
"下载首页图片"
[]
(-> (get-home-page)
get-image-info
str2json
download-images))
2.3 爬取Ajax加载的图片
1 | (defn make-json-request-url |
3. 项目地址
完整的项目我放在了Github上了。大家可以下载下来运行玩一玩。