shell爬蟲批量下載豆瓣相冊(cè)圖片

不久前家里裝修,想搞個(gè)書架,看到豆瓣上有這么一個(gè)相冊(cè)收集了一些書房書架的圖片,簡(jiǎn)單寫了個(gè)shell全部抓回來參考。

shell爬取豆瓣相冊(cè)中的圖片

分析該相冊(cè)首頁(yè)的源碼,可以看到相冊(cè)總頁(yè)數(shù)含有關(guān)鍵字data-total-page,每一頁(yè)有18張圖片,次頁(yè)到最后一頁(yè)的url,只要在首頁(yè)url后加?start=PAGENUMBER,其中PAGENUMBER18*頁(yè)碼,通過字符串拼接即得到相冊(cè)每一頁(yè)完整的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è)每一頁(yè)的url,并將該url傳遞給另一個(gè)函數(shù)get_img_no,這是一種shell中常用的參數(shù)傳遞方法。

需要注意,在(())中引用的變量不需要加前綴$

函數(shù)get_img_no用于獲取相冊(cè)每一頁(yè)中目標(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è)每一頁(yè)中的圖片編號(hào)全部提取出來了。

圖片的url可以通過簡(jiǎn)單的字符串拼接得到,但是該頁(yè)面所展示的圖片只是一個(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)頁(yè)的鏈接img_s_url,該網(wǎng)頁(yè)中的“查看大圖”含有關(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è)簡(jiǎn)單的例子,抓取豆瓣上其它類似內(nèi)容都易如反掌了。

這個(gè)腳本充分體現(xiàn)了shell“糙、猛、快”的特點(diǎn),對(duì)于一次性的自用需求,簡(jiǎn)直不能再合適了。

豆瓣上有個(gè)“害羞組”,是很多python爬蟲初學(xué)者的試驗(yàn)?zāi)繕?biāo),何不試試shell呢?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容