日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網營銷解決方案
使用Shell構建多進程的CommandlineFu爬蟲

 CommandlineFu 是一個記錄腳本片段的網站,每個片段都有對應的功能說明和對應的標簽。我想要做的就是嘗試用 shell 寫一個多進程的爬蟲把這些代碼片段記錄在一個 org 文件中。

創(chuàng)新互聯(lián)公司總部坐落于成都市區(qū),致力網站建設服務有成都網站建設、網站制作、網絡營銷策劃、網頁設計、網站維護、公眾號搭建、小程序設計、軟件開發(fā)等為企業(yè)提供一整套的信息化建設解決方案。創(chuàng)造真正意義上的網站建設,為互聯(lián)網品牌在互動行銷領域創(chuàng)造價值而不懈努力!

參數定義

這個腳本需要能夠通過 -n 參數指定并發(fā)的爬蟲數(默認為 CPU 核的數量),還要能通過 -f 指定保存的 org 文件路徑(默認輸出到 stdout)。

 
 
 
  1. #!/usr/bin/env bash
  2.  
  3. proc_num=$(nproc)
  4. store_file=/dev/stdout
  5. while getopts :n:f: OPT; do
  6. case $OPT in
  7. n|+n)
  8. proc_num="$OPTARG"
  9. ;;
  10. f|+f)
  11. store_file="$OPTARG"
  12. ;;
  13. *)
  14. echo "usage: ${0##*/} [+-n proc_num] [+-f org_file} [--]"
  15. exit 2
  16. esac
  17. done
  18. shift $(( OPTIND - 1 ))
  19. OPTIND=1

解析命令瀏覽頁面

我們需要一個進程從 CommandlineFu 的瀏覽列表中抽取各個腳本片段的 URL,這個進程將抽取出來的 URL 存放到一個隊列中,再由各個爬蟲進程從進程中讀取 URL 并從中抽取出對應的代碼片段、描述說明和標簽信息寫入 org 文件中。

這里就會遇到三個問題:

  1. 進程之間通訊的隊列如何實現(xiàn)
  2. 如何從頁面中抽取出 URL、代碼片段、描述說明、標簽等信息
  3. 多進程對同一文件進行讀寫時的亂序問題

實現(xiàn)進程之間的通訊隊列

這個問題比較好解決,我們可以通過一個命名管道來實現(xiàn):

 
 
 
  1. queue=$(mktemp --dry-run)
  2. mkfifo ${queue}
  3. exec 99<>${queue}
  4. trap "rm ${queue} 2>/dev/null" EXIT

從頁面中抽取想要的信息

從頁面中提取元素內容主要有兩種方法:

  1. 對于簡單的 HTML 頁面,我們可以通過 sed、grepawk 等工具通過正則表達式匹配的方式來從 HTML 中抽取信息。
  2. 通過 html-xml-utils 工具集中的 hxselect 來根據 CSS 選擇器提取相關元素。

這里我們使用 html-xml-utils 工具來提?。?/p>

 
 
 
  1. function extract_views_from_browse_page()
  2. {
  3. if [[ $# -eq 0 ]];then
  4. local html=$(cat -)
  5. else
  6. local html="$*"
  7. fi
  8. echo ${html} |hxclean |hxselect -c -s "\n" "li.list-group-item > div:nth-child(1) > div:nth-child(1) > a:nth-child(1)::attr(href)"|sed 's@^@https://www.commandlinefu.com/@'
  9. }
  10.  
  11. function extract_nextpage_from_browse_page()
  12. {
  13. if [[ $# -eq 0 ]];then
  14. local html=$(cat -)
  15. else
  16. local html="$*"
  17. fi
  18. echo ${html} |hxclean |hxselect -s "\n" "li.list-group-item:nth-child(26) > a"|grep '>'|hxselect -c "::attr(href)"|sed 's@^@https://www.commandlinefu.com/@'
  19. }

這里需要注意的是:hxselect 對 HTML 解析時要求遵循嚴格的 XML 規(guī)范,因此在用 hxselect 解析之前需要先經過 hxclean 矯正。另外,為了防止 HTML 過大,超過參數列表長度,這里允許通過管道的形式將  HTML 內容傳入。

循環(huán)讀取下一頁的瀏覽頁面,不斷抽取代碼片段 URL 寫入隊列

這里要解決的是上面提到的第三個問題: 多進程對管道進行讀寫時如何保障不出現(xiàn)亂序? 為此,我們需要在寫入文件時對文件加鎖,然后在寫完文件后對文件解鎖,在 shell 中我們可以使用 flock 來對文件進行枷鎖。 關于 flock 的使用方法和注意事項,請參見另一篇博文 Linux shell flock 文件鎖的用法及注意事項。

由于需要在 flock 子進程中使用函數 extract_views_from_browse_page,因此需要先導出該函數:

 
 
 
  1. export -f extract_views_from_browse_page

由于網絡問題,使用 curl 獲取內容可能失敗,需要重復獲?。?/p>

 
 
 
  1. function fetch()
  2. {
  3. local url="$1"
  4. while ! curl -L ${url} 2>/dev/null;do
  5. :
  6. done
  7. }

collector 用來從種子 URL 中抓取待爬的 URL,寫入管道文件中,寫操作期間管道文件同時作為鎖文件:

 
 
 
  1. function collector()
  2. {
  3. url="$*"
  4. while [[ -n ${url} ]];do
  5. echo "從$url中抽取"
  6. html=$(fetch "${url}")
  7. echo "${html}"|flock ${queue} -c "extract_views_from_browse_page >${queue}"
  8. url=$(echo "${html}"|extract_nextpage_from_browse_page)
  9. done
  10. # 讓后面解析代碼片段的爬蟲進程能夠正常退出,而不至于被阻塞.
  11. for ((i=0;i<${proc_num};i++))
  12. do
  13. echo >${queue}
  14. done
  15. }

這里要注意的是, 在找不到下一頁 URL 后,我們用一個 for 循環(huán)往隊列里寫入了 =proc_num= 個空行,這一步的目的是讓后面解析代碼片段的爬蟲進程能夠正常退出,而不至于被阻塞。

解析腳本片段頁面

我們需要從腳本片段的頁面中抽取標題、代碼片段、描述說明以及標簽信息,同時將這些內容按 org 模式的格式寫入存儲文件中。

 
 
 
  1. function view_page_handler()
  2. {
  3. local url="$1"
  4. local html="$(fetch "${url}")"
  5. # headline
  6. local headline="$(echo ${html} |hxclean |hxselect -c -s "\n" ".col-md-8 > h1:nth-child(1)")"
  7. # command
  8. local command="$(echo ${html} |hxclean |hxselect -c -s "\n" ".col-md-8 > div:nth-child(2) > span:nth-child(2)"|pandoc -f html -t org)"
  9. # description
  10. local description="$(echo ${html} |hxclean |hxselect -c -s "\n" ".col-md-8 > div.description"|pandoc -f html -t org)"
  11. # tags
  12. local tags="$(echo ${html} |hxclean |hxselect -c -s ":" ".functions > a")"
  13. if [[ -n "${tags}" ]];then
  14. tags=":${tags}"
  15. fi
  16. # build org content
  17. cat <
  18. * ${headline} ${tags}
  19.  
  20. :PROPERTIES:
  21. :URL: ${url}
  22. :END:
  23.  
  24. ${description}
  25. #+begin_src shell
  26. ${command}
  27. #+end_src
  28.  
  29. EOF
  30. }

這里抽取信息的方法跟上面的類似,不過代碼片段和描述說明中可能有一些 HTML 代碼,因此通過 pandoc 將之轉換為 org 格式的內容。

注意***輸出 org 模式的格式并寫入存儲文件中的代碼不要寫成下面這樣:

 
 
 
  1. flock -x ${store_file} cat <${store_file}
  2. * ${headline}\t\t ${tags}
  3. ${description}
  4. #+begin_src shell
  5. ${command}
  6. #+end_src
  7. EOF

它的意思是使用 flock 對 cat 命令進行加鎖,再把 flock 整個命令的結果通過重定向輸出到存儲文件中,而重定向輸出的這個過程是沒有加鎖的。

spider 從管道文件中讀取待抓取的 URL,然后實施真正的抓取動作。

 
 
 
  1. function spider()
  2. {
  3. while :
  4. do
  5. if ! url=$(flock ${queue} -c 'read -t 1 -u 99 url && echo $url')
  6. then
  7. sleep 1
  8. continue
  9. fi
  10.  
  11. if [[ -z "$url" ]];then
  12. break
  13. fi
  14. view_page_handler ${url}
  15. done
  16. }

這里要注意的是,為了防止發(fā)生死鎖,從管道中讀取 URL 時設置了超時,當出現(xiàn)超時就意味著生產進程趕不上消費進程的消費速度,因此消費進程休眠一秒后再次檢查隊列中的 URL。

組合起來

 
 
 
  1. collector "https://www.commandlinefu.com/commands/browse" &
  2.  
  3. for ((i=0;i<${proc_num};i++))
  4. do
  5. spider &
  6. done
  7. wait

抓取其他網站

通過重新定義 extract_views_from_browse_pageextract_nextpage_from-browse_page、 view_page_handler 這幾個函數, 以及提供一個新的種子 URL,我們可以很容易將其改造成抓取其他網站的多進程爬蟲。

例如通過下面這段代碼,就可以用來爬取 xkcd 上的漫畫:

 
 
 
  1. function extract_views_from_browse_page()
  2. {
  3. if [[ $# -eq 0 ]];then
  4. local html=$(cat -)
  5. else
  6. local html="$*"
  7. fi
  8. max=$(echo "${html}"|hxclean |hxselect -c -s "\n" "#middleContainer"|grep "Permanent link to this comic" |awk -F "/" '{print $4}')
  9. seq 1 ${max}|sed 's@^@https://xkcd.com/@'
  10. }
  11.  
  12. function extract_nextpage_from_browse_page()
  13. {
  14. echo ""
  15. }
  16.  
  17. function view_page_handler()
  18. {
  19. local url="$1"
  20. local html="$(fetch "${url}/")"
  21. local image="https:$(echo ${html} |hxclean |hxselect -c -s "\n" "#comic > img:nth-child(1)::attr(src)")"
  22. echo ${image}
  23. wget ${image}
  24. }
  25.  
  26. collector "https://xkcd.com/" &

網站名稱:使用Shell構建多進程的CommandlineFu爬蟲
網站地址:http://www.5511xx.com/article/ccdpsoi.html