不久前家里裝修,想搞個(gè)書架贴唇,看到豆瓣上有這么一個(gè)相冊(cè)收集了一些書房書架的圖片遂鹊,簡單寫了個(gè)shell全部抓回來參考涩嚣。
分析該相冊(cè)首頁的源碼崇众,可以看到相冊(cè)總頁數(shù)含有關(guān)鍵字data-total-page
掂僵,每一頁有18張圖片航厚,次頁到最后一頁的url顷歌,只要在首頁url后加?start=PAGENUMBER
,其中PAGENUMBER
為18*頁碼
幔睬,通過字符串拼接即得到相冊(cè)每一頁完整的url眯漩。
get_page_url(){
num_pages=$(curl -A "${user_agent}" "${base_url}" | grep 'data-total-page' | head -n 1 | awk -F\" '{print $4}')
for ((i=0; i<=num_pages; i++))
do
page_no=$(( 18 * i))
page_url="${base_url}"?start=${page_no}
get_img_no ${page_url}
done
}
這里定義了一個(gè)函數(shù)get_page_url
用于獲取相冊(cè)每一頁的url,并將該url傳遞給另一個(gè)函數(shù)get_img_no
麻顶,這是一種shell中常用的參數(shù)傳遞方法赦抖。
需要注意,在(())
中引用的變量不需要加前綴$
辅肾。
函數(shù)get_img_no
用于獲取相冊(cè)每一頁中目標(biāo)圖片的編號(hào)队萤,只要搜索關(guān)鍵詞photolst_photo
即可。
get_img_no() {
curl -A "${user_agent}" "$1" | grep "photolst_photo" | awk -F\/ '{print $6}' >> /tmp/img_no.txt
}
$1
就是從get_page_url
傳遞過來的網(wǎng)址矫钓,從該網(wǎng)址中提取圖片的編號(hào)要尔,存儲(chǔ)到文件/tmp/img_no.txt
中。
通過函數(shù)get_page_url
中的for
循環(huán)新娜,反復(fù)調(diào)用get_img_no
赵辕,就把相冊(cè)每一頁中的圖片編號(hào)全部提取出來了。
圖片的url可以通過簡單的字符串拼接得到概龄,但是該頁面所展示的圖片只是一個(gè)縮略圖还惠,為了得到原圖,需要解析“查看大圖”的鏈接私杜。
get_img() {
while read line
do
if !(grep $line img_done.txt)
then
img_s_url="https://www.douban.com/photos/photo/""$line""/large"
img_url=$(curl -A "${user_agent}" "$img_s_url" | grep '/large/' | awk -F\" '{print $6}')
curl -A "${user_agent}" -O "$img_url"
echo $line >> img_done.txt
sleep 20
fi
done < /tmp/img_no.txt
rm /tmp/img_no.txt
}
函數(shù)get_img
用于解析大圖鏈接并下載圖片蚕键。while
循環(huán)按行提取圖片編號(hào),拼接為圖片所在網(wǎng)頁的鏈接img_s_url
衰粹,該網(wǎng)頁中的“查看大圖”含有關(guān)鍵詞/large/
锣光,很容易解析出大圖鏈接img_url
,下載完大圖后寄猩,將該圖編號(hào)追加到文件img_done.txt
中嫉晶,也就是說img_done.txt
中存儲(chǔ)了所有已下載圖片的編號(hào)。
這里的if
用于確認(rèn)某一張圖片是否已經(jīng)下載過田篇,如果下載過則直接跳過替废,不再重復(fù)下載。如果每隔一段時(shí)間運(yùn)行一次該腳本泊柬,就可以保證只下載最新圖片椎镣。
豆瓣的反爬措施相對(duì)而言是比較完善的,不過只要稍微控制一下訪問頻率兽赁,爬取少量圖片還不足以觸發(fā)反爬程序状答,因此加入了一個(gè)延時(shí)sleep 20
冷守。
完整的代碼如下。
#!/usr/bin/env bash
base_url='https://www.douban.com/photos/album/84338335/'
user_agent='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36'
touch img_done.txt
get_img() {
while read line
do
if !(grep $line img_done.txt)
then
img_s_url="https://www.douban.com/photos/photo/""$line""/large"
img_url=$(curl -A "${user_agent}" "$img_s_url" | grep '/large/' | awk -F\" '{print $6}')
curl -A "${user_agent}" -O "$img_url"
echo $line >> img_done.txt
sleep 20
fi
done < /tmp/img_no.txt
rm /tmp/img_no.txt
}
get_img_no() {
curl -A "${user_agent}" "$1" | grep "photolst_photo" | awk -F\/ '{print $6}' >> /tmp/img_no.txt
}
get_page_url(){
num_pages=$(curl -A "${user_agent}" "${base_url}" | grep 'data-total-page' | head -n 1 | awk -F\" '{print $4}')
for ((i=0; i<=num_pages; i++))
do
page_no=$(( 18 * i))
page_url="${base_url}"?start=${page_no}
get_img_no ${page_url}
done
}
get_page_url
get_img
exit 0
由于首次運(yùn)行時(shí)還沒有img_done.txt
文件惊科,因此使用touch
新建一個(gè)文件拍摇,如果該文件已經(jīng)存在,touch
只更新文件的屬性信息馆截。
將該文件存儲(chǔ)為get_img.sh
充活,通過bash -x
可在終端中實(shí)時(shí)看到腳本運(yùn)行的情況:
$ bash -x get_img.sh
如果把腳本扔到crontab
中定時(shí)運(yùn)行,就可以追蹤該相冊(cè)的更新情況蜡娶,并自動(dòng)下載最新圖片了混卵。(不過這個(gè)相冊(cè)貌似很久都不更新了。)
搞明白這個(gè)簡單的例子窖张,抓取豆瓣上其它類似內(nèi)容都易如反掌了幕随。
這個(gè)腳本充分體現(xiàn)了shell“糙、猛宿接、快”的特點(diǎn)赘淮,對(duì)于一次性的自用需求,簡直不能再合適了澄阳。
豆瓣上有個(gè)“害羞組”拥知,是很多python爬蟲初學(xué)者的試驗(yàn)?zāi)繕?biāo),何不試試shell呢碎赢?