零基礎爬蟲學習全記錄2:今日頭條指定搜索內容下的所有圖集圖片保存——圖片採集小程序

零基礎爬蟲學習全記錄

無論僅僅有多少基礎,都不該在徘徊和猶豫中浪費!

只有放棄幻想,用行動促進思考,才能最快找到想要的路。

背景:

  1. 沒有任何編程基礎的金融學專業學生,C語言都沒接觸過
  2. 對於語法掌握,來自於編程小白的第一本 Python 入門書(極其簡單,內容有趣)
  3. 前一篇爬蟲學習利用Requests+正則表達式爬取貓眼電影,學習全過程記錄與體會。
  4. 曾經在零基礎時受到 @路人甲 大神有關爬虫部分回答和文章的指點!得到了非常多有用的學習資料!明確了整個學習的方向!非常感謝!
  5. 學習耐心很差,大塊頭書籍無法堅持啃下,遂在簡單語法掌握後,立即動手學習爬蟲

目的:

  1. 短期目的在於完成崔大的Python3爬蟲視頻學習教程 | 靜覓
  2. 中期目的,基本掌握爬蟲技能,有能力爬取互聯網上大部分網站信息。
  3. 將爬取的信息用於數據分析,創造價值。

聲 明

  1. 本爬蟲學習的實戰項目——爬取今日頭條圖片
  2. 在學習過程中,通過思考,理解後,打出自己理解的代碼。
  3. 學習資料,來自於Python3爬蟲三大案例實戰分享 - 網易雲課堂
  4. 學習資料視頻作者——崔慶才,崔大神。 @靜覓
  5. 作者博客地址:靜覓丨崔慶才的個人博客

參考學習資料:

  1. 如何學習Python爬蟲[入門篇]?(強烈推薦!十分有用!裡面有關python學習線路很適合大眾,爬蟲的相關學習難度也很適中)
  2. Python3爬蟲三大案例實戰分享 - 網易雲課堂
  3. Python正則表達式 | 菜鳥教程
  4. Python3 教程 | 菜鳥教程
  5. 快速上手 - Requests 2.18.1 文檔
  6. python中os模塊 - 消失的混蛋 - 博客園
  7. 正則表達式30分鐘入門教程 - deerchao - 博客園

環境配置:

  1. 系統環境:WIN8
  2. 編譯環境:Python3.5
  3. 所需庫:requests、re、json、multiprocessing、os、pymongo、hashlib
  4. IDE:Pycharm

學前疑惑:

  1. 如何分析AJAX請求?
  2. 圖片的爬取如何做到?
  3. 如何將爬取的信息存儲進資料庫?

程序實現的功能:

  • 抓取,今日頭條中,自己設定的搜索內容下,指定數量的圖集圖片。
  • 並且分類保存至指定文件夾中,和保存至MONGODB資料庫

具體代碼:

# -*- coding: UTF-8 -*-import requestsfrom urllib.parse import urlencodefrom requests import RequestExceptionimport jsonfrom bs4 import BeautifulSoupimport reimport pymongo# from config import *from hashlib import md5import osfrom multiprocessing import Poolfrom json.decoder import JSONDecodeErrorMONGO_URL = localhost#建立資料庫基本參數,並且連接本地MONGODB資料庫。MONGO_DB = toutiaoMONGO_TABLE = toutiaoclient = pymongo.MongoClient(MONGO_URL,connect=False)#聲明MONGODB資料庫對象,connect=False是為了消除MONGODB有關多線程的提示db=client[MONGO_DB]#資料庫名稱#首先在今日頭條搜索街拍,然後點擊圖集,這個頁面先叫做索引頁。再然後,尋找,有關各個圖集的入口。#在檢查索引頁網頁元素中,network中找到XHR板塊,發現下拉網頁會得到新的XHR返回#再發現,原來是通過帶有data中有不同offset值的請求的方式,來使得載入更多鏈接。觀察,刷新出新的AJAX請求中Response值部分,發現是JSON格式,並且帶有各個詳情頁入口# 通過循環,拿到各個街拍組圖鏈接的數據,返回的結果是JSON數據,用JSON包解析數據成字典#再進入詳情頁,在網頁中尋找有關圖片及其圖集中其他圖片相關鏈接#先找XHR,尋找AJAX請求中是否有想要的數據,未發現有效連接#繼續尋找,在network的doc板塊中的網頁源代碼中,發現是通過變數gallery載入,後面帶有大量圖片鏈接,並且與圖集後續圖片鏈接一致。目的是解析gallerydef get_pade_index(offset,keyword):#獲取索引頁網站源代碼 data={ offset: offset, format: json, keyword: keyword, autoload: true, count: 20, cur_tab: 3#!!!這裡特別注意!!!視頻與實際網頁有改動,觀察點擊圖集前後對比,發現cur_tab變數不同。 #如果發現請求結果有大量非圖集,請修改這個參數 } url=http://www.toutiao.com/search_content/?+urlencode(data)#urlencode(data)將字典對象轉化為URL請求參數 #構建一個帶有data的請求,以取得返回的Response中的JSON try: headers = { User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3538.400 QQBrowser/9.6.12501.400 }#為了保證爬蟲正常運行,設置請求頭 response = requests.get(url, headers=headers) if response.status_code == 200: return response.text return None except RuntimeError: print(請求索引出錯) return Nonedef parse_page_index(html):#解析索引頁信息 try:#解析索引頁通過請求獲得的各個請求返回的JSON,最終獲得各個圖集入口 data=json.loads(html)#將JSON字元串,轉化為JSON變數對象 if data and data in data.keys():#data存在且有存在data值 for item in data.get(data): yield item.get(article_url) except: passdef get_page_detail(url): try: headers = { User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3538.400 QQBrowser/9.6.12501.400 } response = requests.get(url, headers=headers) if response.status_code == 200: return response.text return None except RuntimeError: print(請求詳情頁出錯,url) return Nonedef parse_page_detail(html,url):#該函數解析詳情頁數據,最後返回各個圖集的標題及其圖片鏈接 soup = BeautifulSoup(html,lxml) title=soup.select(title)[0].get_text()#利用BS解析出title print(title) images_pattern=re.compile(gallery: (.*?),
,re.S)#正則表達式,注意gallery與原網站不同,記得加入,
!!
result=re.search(images_pattern,html) if result:#如果存在result則運行 data = json.loads(result.group(1))#解析JSON集,順便提取result里的內容 if data and sub_images in data.keys():#data存在,且有sub_images這個變數。 sub_images=data.get(sub_images) images=[item.get(url) for item in sub_images]#構建一個列表,存放images地址。sub_images是一個JSON中的值,不能直接引用。 for image in images: download_image(image) return { title:title, url:url, images:images }def save_to_mongo(result): try: if db[MONGO_TABLE].insert(result): print(存儲到MONGODB成功,result) return True return False except: print(存儲錯誤)def download_image(url): print(正在下載,url)#!!很重要,獲得一個調製信息 try: headers = { User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3538.400 QQBrowser/9.6.12501.400 } response = requests.get(url, headers=headers) if response.status_code == 200: save_image(response.content)#返回二進位內容,如圖片。 return None except RequestException: print(請求圖片出錯,url) return Nonedef save_image(content):#創建對應分類的文件夾,並且保存圖片。個人 dir_name=str(KEYWORD)+_+str(GROUP_START)+-+str(GROUP_END)#個人補充功能! dir_path=F:spiderpicture{}.format(dir_name) try: os.mkdir(dir_path) except: pass file_path={0}/{1}.{2}.format(dir_path,md5(content).hexdigest(),jpg) if not os.path.exists(file_path): with open(file_path,wb) as f: f.write(content) f.close()def main(offset):#主程序流程 html = get_pade_index(offset,KEYWORD) #自己輸入搜索內容,還有搜索量,獲取索引頁源代碼 for url in parse_page_index(html):#解析索引頁代碼,並且用遍歷,提取出url(各個詳情頁鏈接入口) html=get_page_detail(url)#得到詳情頁網頁源代碼 if html:#如果得到正常得到詳情頁網站源代碼,繼續以下步驟 result=parse_page_detail(html,url)#解析詳情頁源代碼,得到result,包含各個圖片的鏈接,所在圖集標題,詳情頁地址。 if result :save_to_mongo(result)#如果result正常獲取,則保存下來。GROUP_START = 1#輸入起始頁數,可以隨意設置GROUP_END = 2#結束頁數,可以隨意設置KEYWORD = 台灣#搜索內容,可以隨意修改if __name__ == __main__: groups=[x*20 for x in range(GROUP_START,GROUP_END+1)] pool=Pool() pool.map(main,groups)

雖然,通過視頻學習爬蟲,是由視頻作者帶著學習者爬蟲的思路走。

但是,換個角度來看,如果從頭開始獨立設計這個爬蟲,該怎麼整理邏輯呢?

今日頭條圖片爬蟲代碼中各個功能順序:

1.獲得搜索結果下的索引頁網站源代碼

2.通過分析索引頁源代碼,從network的XHR中發現,當帶著data去請求網站時會得到一個JSON集,其中就有各個詳情頁入口鏈接

3.獲得詳情頁的網站源代碼

4.分析詳情頁的源代碼,分析發現,在network的doc中,存在一個變數gallery中有該詳情頁所有圖片地址、標題。

5.獲取圖片地址標題,並保存到MONGODB資料庫

6.下載圖片——請求後,返回response.content即為圖片

7.創建對應分類圖片文件夾,並且將圖片保存進去(個人自己實現!第一次實現自己想要的小功能,很開心。)

8.主程序調用各個函數。

9.調用多線程

學習過程中出現的問題:

  1. 既然是爬蟲教程,就肯定會存在,網站代碼的變化情況。但是,想清楚每個步驟目的,就能正常獲得結果。
  2. 第一個遇到的問題,請求獲得各個詳情頁地址時,發現大部分結果不是圖集,無法正常獲得圖片地址。最後發現,帶著data的請求中,cur_tab: 3,後面的3是決定搜索結果的參數,這點與教程視頻裡面不同,需要留意。
  3. 視頻中的vr gallery變數,在實際網頁中變成了gallery。
  4. 實際運行中,多次遇到requests請求失敗,json解析失敗,MONGODB解析失敗等等錯誤情況,利用try: except,能順利解決,使得程序不會因為一點問題就卡殼。也總結了一個套路,遇到錯誤提示,找到XXXEROOR這部分,然後對他進行try,except處理。
  5. 視頻中建立了配置文件config,並且能調用裡面的變數,但是自身操作時卻不能正常調用,所以將變數一齊寫在代碼里。
  6. 視頻中圖片保存在代碼所在目錄下,非常雜亂。自己通過百度,查找有關os庫的創建文件夾用法,自己實現了爬取圖片分類保存,視頻以外自己實現的小功能,很開心!
  7. 學習中還出現了一些語法理解問題,但是都在短暫思考後解決。
  8. 上述代碼中的注釋,還有很多自身學習時遇到的問題,基本上都記錄下了。

爬取結果展示:

感謝 @路人甲 提供的學習爬蟲路線及其大量爬蟲學習資料!

感謝@靜覓的爬蟲教程,收穫了非常多知識。

我在上篇文章時寫下的,要求,這星期完成學習這篇爬蟲視頻學習,並且總結。

三天之後的今天,完成了。

你對你自己要求的的學習目標,完成了嗎?

如果還未完成,如果你心動的話。

關注我知乎~

不要吝嗇你的贊~

我會繼續學習和總結,希望能給你帶來一些幫助。

與大家共勉,繼續努力!

覺得這篇文章對你有幫助的話,幫忙點個贊~

這也是我動力的來源,謝謝各位。

這裡有個Q群541809771,由 @路人乙 創建,群里有許多人正在學習的路上,歡迎各位前來討論,互相監督,互相進步。

推薦閱讀:

國內有哪些 Django 牛人?
Python從零開始系列連載(12)——Python的基本運算和表達式(下)
為什麼感覺django裡面class based view很難呢?
關於python Django與Flask學習的一些疑惑?
用django建一個簡單的購物網站需要多久?

TAG:Python | 爬虫计算机网络 | Python入门 |