SHELL網路爬蟲執行個體剖析

來源:互聯網
上載者:User

標籤:sed   awk   shell   網路爬蟲   

       前天簡單分享了用 shell 寫網路爬蟲的一些見解,今天特地把代碼發出來與51博友分享,還是那句話,愛技術、愛開源、愛linux。

       針對指令碼的註解和整體構思,我會放到指令碼之後為大家詳解。

#!/bin/bash## This script is used to grab the data on the specified industry websites# Written by sunsky# Mail : [email protected]# Date : 2014-09-14 3:06:00#if [ `echo $UID` != 0 ];then  echo ‘Please use the root to execute the script!‘fiif [ ! -f /dataimg/years ];then  echo ‘Please give date file, the file path for/dataimg/years .‘fiif [ ! -d $TMP_DIR ];then  mkdir -p $TMP_DIRfiif [ ! -d $URL_MD5_DIR ];then  mkdir -p $URL_MD5_DIRfiif [ ! -d $HTML_DIR ];then  mkdir -p $HTML_DIRfiROOT_DIR="/dataimg"                  # 指定指令碼運行根目錄TMP_DIR="$ROOT_DIR/tmp"              # 產生商品詳細頁url之前的臨時資料存放目錄URL_MD5_DIR="$ROOT_DIR/url_md5"      # 記錄商品詳細頁url的MD5值的目錄HTML_DIR="$ROOT_DIR/html"            # 存放下載下來的商品詳細頁目錄URL_MD5="$URL_MD5_DIR/md5.$year"     # 負責記錄商品詳細頁url的md5值WEB_URL="https://www.redhat.sx/"     # 所耙梳站的首頁urlREPORT="$ROOT_DIR/report"            # 負責記錄採集的url綜合資訊CURL="curl -A ‘Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.102 Safari/537.36‘ --referer http://www.redhat.sx"OPT0="/dataimg/years"                                                   # 年份資訊 OPT1="$TMP_DIR/${X1_MD5}"                                               # 品牌資訊     OPT2="$TMP_DIR/${X1_MD5}_${X2_MD5}"                                     # 車型資訊OPT3="$TMP_DIR/${X1_MD5}_${X2_MD5}_${X3_MD5}"                           # 裝飾資訊OPT4="$TMP_DIR/${X1_MD5}_${X2_MD5}_${X3_MD5}_${X4_MD5}"                 # 部位分類資訊OPT5="$TMP_DIR/${X1_MD5}_${X2_MD5}_${X3_MD5}_${X4_MD5}_${URL_LIST_MD5}" # 商品詳情頁url資訊FIFO_FILE="/tmp/$$.fifo"mkfifo $FIFO_FILEexec 9<>$FIFO_FILErm -f $FIFO_FILEnum=10for ((i=0;i<$num;i++));doechodone >&9while read X1;do{  URL1="${WEB_URL}/model/YMMTSelects.cfc?method=getMakes&PassYear=$X1"  X1_MD5=`echo $URL1|cksum|cut -d‘ ‘ -f1`  if ! ls $OPT1 >&/dev/null;then    $CURL -s $URL1|awk ‘BEGIN{RS="<"}{print $0}‘|awk -F‘>‘ ‘{print $2}‘|sed ‘1,9d‘|sed ‘$d‘|grep -v ‘^$‘ > $OPT1  fi  while read X2;do    X2=`echo $X2|sed ‘s# #%20#g‘`    URL2="${URL1}&PassMakeName=$X2"    #X2_MD5=`echo $URL|cksum|cut -d‘ ‘ -f1`    if ! ls $OPT2 >&/dev/null;then      $CURL -s $URL2|awk ‘BEGIN{RS="<"}{print $0}‘|awk -F‘>‘ ‘{print $2}‘|sed ‘1,6d‘|sed ‘$d‘|grep -v ‘^$‘ > $OPT2    fi    while read X3;do      X3=`echo $X3|sed ‘s#[[:space:]]#%20#g‘`      URL3="${URL2}&PassModel=$X3"      X3_MD5=`echo $URL3|cksum|cut -d‘ ‘ -f1`      if ! ls $OPT3 >&/dev/null;then        $CURL -s $URL3|sed ‘s#[[:space:]]##g‘|awk ‘BEGIN{RS="<|=|>"}{print $0}‘|egrep ‘^[0-9]+$‘ > $OPT3      fi      while read X4;do        X4=`echo $X4|sed ‘s# #%20#g‘`        URL4="${URL3}&PassVehicleID=$X4"        X4_MD5=`echo $URL4|cksum|cut -d‘ ‘ -f1`        if ! ls "${OPT4}" >&/dev/null;then          $CURL -s $URL4|awk ‘BEGIN{RS="<"}{print $0}‘|awk -F‘[>;]‘ ‘{print $2}‘|sed -e ‘1,3d‘ -e ‘$d‘ -e ‘/^$/d‘ > $OPT4        fi        while read X5;do          X5=`echo $X5|sed ‘s# #%20#g‘`          URL_LIST="${WEB_URL}index.cfm?fuseaction=store.sectionSearch&YMMTyears=$X1&YMMTmakenames=$X2&YMMTmodelnames=$X3&YMMTtrimnames=$X4&YMMTsectionnames=$X5"          URL_LIST_MD5=`echo "$URL_LIST"|md5sum|awk ‘{print $1}‘`          if ! grep -q $URL_LIST_MD5 "$URL_MD5" ;then            $CURL -s "$URL_LIST" > "$URL_MD5_DIR/$URL_LIST_MD5"            NUM=`grep ‘View page‘ "$URL_MD5_DIR/$URL_LIST_MD5"|wc -l`            NUM2=$(($NUM/2))            echo > $OPT5            grep ‘a href="index.cfm?fuseaction=store.PartInfo&PartNumbe‘ "$URL_MD5_DIR/$URL_LIST_MD5"|cut -d‘"‘ -f2 > $OPT5            while [ $NUM2 -ge 2 ];do              URL_LIST=`grep "View page $NUM2" "$URL_MD5_DIR/$URL_LIST_MD5"|awk -F‘[" ]‘  ‘{a[$9]=$9}END{for(i in a)print a[i]}‘`              $CURL -s "$URL_LIST"|grep ‘a href="index.cfm?fuseaction=store.PartInfo&PartNumbe‘|cut -d‘"‘ -f2 >> $OPT5              NUM2=$(($NUM2-1))            done            echo $URL_LIST_MD5 >> "$URL_MD5"          fi          while read X6;do            URL_DETAIL="${WEB_URL}${X6}"            URL_DETAIL_MD=`echo $URL_DETAIL|md5sum|awk ‘{print $1}‘`            if ! grep -q $URL_DETAIL_MD "$URL_MD5" >&/dev/null;then # 該判斷以商品列表詳細頁URL的md5值為基準,負責URL的重複項判定              $CURL -s "$URL_DETAIL" > "$HTML_DIR/$URL_DETAIL_MD"              LABEL=`grep ‘diagram-label‘ "$HTML_DIR/$URL_DETAIL_MD"|awk -F‘[<>]‘ ‘{print $5}‘`  # 商品標籤              GIF_URL=`grep -B 10 partInfo "$HTML_DIR/$URL_DETAIL_MD"|grep -o "https.*gif"|awk ‘{a=$0}END{print a}‘` # 產品對應的圖片URL              PRODUCT_ID=`grep ‘productID‘ "$HTML_DIR/$URL_DETAIL_MD"|awk -F‘[<>]‘ ‘{print $3}‘` # 產品零件號碼              GIFILE=${GIF_URL#*/}   # 去除了https:/後的圖片URL資訊,as:/a/b.gif              GIF_IMG="${ROOT_DIR}${GIFILE}" # 圖片存到本地後的絕對路徑,as:/dataimg/a/b.gif              U4=`grep -B 10 ‘<!-- start opentop -->‘ "$HTML_DIR/$URL_DETAIL_MD"|grep javascript|awk -F‘[<>]‘ ‘{print $3}‘`              ! ls $GIF_IMG >& /dev/null && wget -q -m -k -P "$ROOT_DIR" "$GIF_URL"              echo $URL_DETAIL_MD >> "$URL_MD5"              echo "$(date +%m%d%T)+++$X1+++$X2+++$X3+++$U4+++$X5+++$URL_DETAIL+++$URL_DETAIL_MD+++$LABEL+++$PRODUCT_ID+++$GIF_IMG+++$URL_LIST" >> "$REPORT"            fi          done < $OPT5  # 傳入商品詳細列表url資訊,進行迴圈        done < $OPT4    # 傳入產品部位分類資訊,進行迴圈      done < $OPT3      # 傳入裝飾資訊,進行迴圈    done < $OPT2        # 傳入車型資訊,進行迴圈  done < $OPT1          # 傳入品牌資訊,進行迴圈  echo >&9}&done < $OPT0            # 傳入年份資訊,進行迴圈if [ $? -eq 0 ];then  echo "--------完成了--------" >> $REPORTelse  echo "--------未完成--------" >> $REPORTfiwaitexec 9<&-

       OK!

       以上就是指令碼的全部內容,整體指令碼主要包含了組合目標URL和抓取目標URL兩個大方向,圍繞這兩個大方向,主要是使用 curl 來做資料抓取,是用sed、awk、grep、cut來做興趣資料的抽取。

       由於所要抓取的目標URL必須經過幾個選項匹配,最終才能得到想要結果,因此我們在抓取目標URL之前添加了組合目標URL這一操作。整體這2個方向,我通過多層的while迴圈嵌套,來實現對參數的複用和一層一層的輸入挖掘。

       為了最佳化速度以及控制速度,採用了 shell 的多進程和資料智能判重的方式。

       採用 shell 的多進程目的是為了增大運算元來縮短整體完成時間,提高抓取效率。

       shell 多進程主要依託 迴圈 + { } + & 來實現。如果多進程的進程數量有指定數值,那麼我們可以使用for和while都而已,如果多進程的進程數量沒有指定數值,那麼我們最好使用while迴圈語句。通過將 { }& 嵌套在迴圈中實現將 {}內的命令群組放到後台去自動執行,然後完成本次 { }& 操作,使得迴圈可以進入下一次。

       以上並未實現該shell 在後台開啟進程數的控制,假設你的需要執行一萬次,如果你未控制速度,就可能會導致直接觸發著一萬次操作,同時放到後台執行,這樣對系統是致命的傷害。另一方面,作為爬蟲,你對目標網站的並發量也不能太大。出於這兩方面的考慮,我們需要控制 shell 多進程每次放入後台執行的數量。針對這一行為,我們主要通過檔案描述符來實現。通過建立一臨時管道檔案,然後為該檔案開啟一個檔案描述符,並為其傳遞指定數量的空行(本文傳遞了10個空行),這樣做的目的是為了實現對進程並發量的控制。接著,在下面迴圈中, { }&操作的前面使用read -u9(這裡9為本文使用的檔案描述符)來從9這個檔案描述符中擷取一行,如果擷取到就能繼續往下執行,如果擷取不到就在這裡等待。

       通過以上的2者結合,就能實現對 shell 多進程的智能管控。

       採用資料智能判重的目的在於,在指令碼調試中發現速度的執行瓶頸在於curl的速度,即網路速度,因此一旦指令碼異常中斷後,恢複之後,又要重複進行curl操作,這樣就極大增加了指令碼執行時間。因此通過智能判重,完美實現了curl時間消耗過久的以及資料重複採集的問題。以下是資料只能判重的邏輯圖:

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/49/91/wKioL1QUnWzyFIJZAAMW8rN7OK8488.jpg" title="QQ20140914033817.png" alt="wKioL1QUnWzyFIJZAAMW8rN7OK8488.jpg" />

      針對指令碼中變數的取值意義,我已經在上面的指令碼中進行了詳細的注釋,這裡不在複述。

      其它細枝末節的一些使用方法和技巧,這裡不再一一解釋。對 shell 感興趣的朋友可以和我一起交流,一起進步。

本文出自 “Not Only Linux” 部落格,請務必保留此出處http://nolinux.blog.51cto.com/4824967/1552472

SHELL網路爬蟲執行個體剖析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.