自學python網路爬蟲,從小白快速成長,分別實現靜態網頁爬取,下載meiztu中圖片;動態網頁爬取,下載burberry官網所有當季新品圖片。

叫我PT發表於2020-02-06

文章目錄

1.前言

2.知識儲備

3.爬取靜態網站

4.爬取動態網站

5.原始碼

1.前言

近日疫情嚴重,手機已經玩吐了,閒著無聊逛衣服品牌官網發現,結果一時興起,想學一學python,寫一個爬蟲下載官網所有最新上架的衣服圖片和價格;說幹就幹,但身為一個只學過一些c和c++的python 零基礎大二小白,csdn上的各種教程裡涉及的各種發法、工具和庫讓我眼花繚亂;因此走了很多彎路,終於花三天時間完成了爬蟲的設計實現。自己總結下來發現學習+上手其實 真的一點都不難
今天我把自己的從零開始的所有經驗記錄下來,讓所有想學爬蟲但是面對各類教程不知所措的童鞋們能從中收穫一二。

2.知識儲備

  • python基本語法

    • 尤其是列表、字典的操作

  • 庫(安裝方式自行百度)

    • request庫

      主要用庫中的get方法和post方法用來向指定的url(網址)請求資料,

      	import requests
      	url = 'https://cn.burberry.com/service/shelf/mens-new-arrivals-new-in/'
      	response = requests.get(url)
      

      值得注意的是,對於一些網頁必須加入指定的headers,用來將你的爬蟲偽裝成閱覽器,並新增一些重要的標誌,否則網站不會讓你訪問它的資料,

      	User_Agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0'
      	
      	header = {
      	    'User-agent':User_Agent,
      	}
       	response = requests.get(url,headers = header)
      

      另外,請求到的資料是requests型別,我們要對其進行分析,必須把它轉化成bytes型別或者str型別,即

      	content = response.content
      	#或者使用text屬性得到相應字串
      	#content = response.text
      

      這樣就成功得到bytes型別的網站原始碼啦!
      接下來對該文字進行分析,怎麼進行呢?有兩個選擇,一是正規表示式(比較難),二就是方便我們初學者使用的BeautifulSoup庫啦!
      但首先,我們需要安裝使BeautifulSoup的使用更為方便快速的解碼庫lxml庫

    • lxml庫

      用來為BeautifulSoup的初始化構造提供解碼器。

    • BeautifulSoup庫

      主要使用庫中的“建構函式”完成對bytes型別資料的格式化,即將其轉化為可以利用庫中方法進行檢索的物件

      	import lxml
      	from bs4 import BeautifulSoup
      	soup = BeautifulSoup(content,'lxml')
      

      之後便可以利用庫中的findfind_all方法,用來找原始碼中相應的標籤! 舉個栗子,下面是burberry官網的原始碼截圖,在這裡插入圖片描述
      假設我們已經構造好了其BeautifulSoup型別的物件soup
      現在我們想從中找到加亮的那一行程式碼,首先明確其 標籤div, 其中class = xxx* 為該標籤下的 屬性,那麼我們就用find函式來找:

      target = soup.find(name = 'div',attrs = {'class':'productts_container'})
      
      #name代表著標籤的名稱
      #attrs是屬性的字典,class是屬性名,product_container是該屬性的值
      #如果只匹配name,不匹配屬性,會找錯,因為find預設返回第一個
      #找到匹配的值,而加亮程式碼行上面也有名為div的標籤,因此必須匹配獨一無二的屬性
      

      值得注意的是,find函式返回的是BeautifulSoup型別的物件,如果想要訪問其中的某項屬性,需要使用attrs[]方法,例如現在我們要訪問上述的class屬性值

      class_result = target.attrs['class']
      #attrs可以省略
      #class_result = target['class']
      print(class_result)
      #products_container
      

      find_all函式的呼叫方法和find函式相同,傳入引數也一樣,只不過find_all會找到所有匹配的項,並將其構建為一個列表

  • JSON檔案基礎

    • 在爬取動態網頁時會用到,我理解其為字典的列表,其中字典有巢狀的結構

    • 具體可參考

3.爬取靜態網站

  • 流程(我們遵循csdn傳統~以下載https://www.mzitu.com/221136每一頁圖片為例,內容不重要!學習才是根本目的

    1.我們看到網站的每一頁圖片都是載入好的,即沒有***檢視更多***等按鈕,也不會隨著滑鼠 滾輪拖動而載入新的內容,所以是靜態網頁。

    2.用開發人員工具f12分析原網頁,一步步找到要爬的圖片所在的位置,如圖,一個紅圈是標題,一個紅圈是圖片所在的url,一個是當前頁數,一個是總頁數

    在這裡插入圖片描述

    • 發現標題是在名為h2的標籤的字串,並且該標籤有class屬性,其值為main-title
    • 同時圖片的url存在名為img的標籤src屬性裡,並且該img標籤還有屬性alt,其值和標題相同
    • 我們不關心當前是第幾頁,只需要獲取頁數上界,而頁數儲存在名為div,有屬性class = pagenavi的標籤的名為a的子標籤的名為span的子標籤的字串裡,而上界存在倒數第二個上述標籤中(自己觀察網頁,發現最後一個存的是下一頁

    3.分析網址的變化:

    • 我們點進第二頁圖片,發現網站url在初始頁的基礎上新增了’/2’,如圖:
      在這裡插入圖片描述
    • 同時第二頁的標題、圖片url所在位置都沒有發生變化,如圖:
      在這裡插入圖片描述
    • 再試一試能否通過在原url上新增’/1’能否訪問到第一頁,發現可以;至此,全部分析結束,開始寫程式碼。

    4.用requests庫的get方法獲得資料

    	import requests
    	import lxml
    	from bs4 import BeautifulSoup	#引入庫
    	
    	url = 'https://www.mzitu.com/221136'
    	header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) 			Gecko/20100101 Firefox/66.0",
    	"Referer":"https://www.mzitu.com/jiepai/comment-page-1/"}
    	#header裡必須設定Referer屬性,否則無法下載圖片
    	response = requests.get(url,headers = header)	#請求網頁
    

    4.將其構造為BeautifulSoup物件

    	bsobj = BeautifulSoup(content,'lxml')	#解析html
    

    5.用find、find_all方法找到相應的資料

    	#get_text()方法獲取中文字樣,用string屬性也可以
    	title = bsobj.find('h2',class_ = 'main-title').get_text()
    	#按照分析出儲存頁數上界的位置尋找,儲存其string屬性即得最大頁數
    	picture_max = bsobj.find('div',class_ = 'pagenavi').find_all('a')[-2].string
    	
    	#按照分析出的網址變化形式逐頁訪問
    	for i in range(1,int(picture_max)):
    		href = url + '/' + str(i)	#訪問每一頁
    		response = requests.get(href,headers = header)	#請求資料
    		content = response.content	#得到二進位制物件
    		soup = BeautifulSoup(content,'lxml')	#初始化
    		
    		#找img標籤,訪問src屬性,找圖片url
    		picture_url = soup.find('img',alt = title).attrs['src']
    		#訪問圖片url
    		response_img = requests.get(picture_url['src'],headers = header)
    		#獲取二進位制圖片檔案
    		content_img = response_img.content
    		#命名檔案,注意加.jpg
    		file_name = title + '-' + str(i) + '.jpg'
    		#寫入,注意以二進位制寫入方式開啟
    		with open(file_name,'wb') as f:
       	 		f.write(content_img)
    

    不出意外,會在程式碼所在目錄下得到44張圖片yeah!
    現在我們已經完成了對靜態網站的爬取,是不是很簡單啊!那麼好學的我們肯定不滿足於此啦,現在的大部分網站都有動態載入的功能,具體實現機制可以自行學習,有了上述的知識儲備和簡單實踐,動態網頁的爬取任務對我們也不過是piece of cake,那麼就來試試吧!

4.爬取動態網站

  • 流程(以下載burberry男士最新上架的圖片為例)

    1.點開網站發現有一個瀏覽全部按鈕!怎麼回事,開啟f12康一康:在這裡插入圖片描述

    • 咦,為什麼右邊多了一堆沒顯示的東西,格式也和上面的不一樣?而且為什麼只有四張圖片是和右邊原始碼相匹配的,剩下的圖片呢?
    • 於是我們嘗試點開瀏覽全部
      在這裡插入圖片描述
    • 哇塞,又多出來好多內容啊。。。這可怎麼辦?如果直接訪問這個url,沒有辦法點開瀏覽全部的話,那撐死只能下載到原始碼中最開始展示的寥寥幾張圖片,達不到我們想要下載全部最新上架圖片的目的啊!
    • 因此,我們也有了針對這一類動態載入時間的新的處理辦法!

    2.分析由點選瀏覽全部而觸發的事件:

    • 一般的,這一類動態載入都會由一個javascriptxhr觸發,通過ajax將其內容(一般是json)非同步載入到網頁上來這裡說的都是我根據各教程學習後自己的理解,可能有不正確的地方,建議感興趣的夥伴自行搜尋,或者大神在評論區指點),我們的首要任務就是找到這個指令碼:

      1. 重新整理網頁後,f12,切換到network欄,選中JS
      在這裡插入圖片描述
      2.點選瀏覽全部,發現JS中沒有新載入的項
      3.再重新整理介面,選中XHR
      在這裡插入圖片描述
      4.點選瀏覽全部按鈕
      在這裡插入圖片描述
      咦,怎麼瞬間多出來一項?之後又多出來好多項?!
      原來這就是我們要找的指令碼——也就是關鍵所在啦~

    • 這個指令碼的作用就是連結到一個新的url,該url指向一個json檔案,然後把檔案裡的內容載入到了網頁裡!現在需要找出這個url,並且分析訪問它的條件

      1.點選該指令碼
      在這裡插入圖片描述
      發現其訪問的url在General欄中已經給出,為https://cn.burberry.com/service/shelf/mens-new-arrivals-new-in/?_=1580538937924
      但直接訪問這個連結,發現不成功?!原來是網站自動過濾了我們的訪問請求,因為我們給出的資訊不足,人家不讓看!那麼怎麼辦呢?
      簡單!完善資訊就行了!

      2.我們發現General裡給出的Request MethodGet,那麼我們就點開Request Headers進行分(fu)析(zhi)
      在Request Headers欄中給出了一系列鍵值,我們把其中所有內容複製在我們爬蟲的header裡

      	url = 'https://cn.burberry.com/service/shelf/mens-new-arrivals-new-in/?_=1580313287552'
      	#User-Agent可以自定
      	USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0"
      
      	Cookie = '_ga=GA1.3.396709042.1580187372; Hm_lvt_0a183129752754c550277ef8f347c9a3=1580187372; mm-if-site-persist-ua-44=%5B%22Fredhopper%20Search%20vs%20ATG%20Search%3Dsearch%3Avariant%22%2C%22T103%20-%20For%20U%20Entrance_CN%3Dnavbarlink%3Avariant%22%5D; storeId=store_cn; language=zh_CN; burberryId=7bb25b00-418a-11ea-b799-55681cc34864_NULL_NULL; _cs_c=1; LPVID=Y5OTExZWZkN2E2ODU3MjJm; recentViewed=80255061; fita.sid.burberry_cn=_m_DQ-7-69P0cFThc2tobfutAzbPHGD4; sessionId=s%3AReNqxNlCK1NzYQoeLWwIj_coMlvnjpWk.0%2Bg%2FXkrRjQkaRGXI7EDgnCh%2BZFsWsJfMDSqfUwNsPI0; useFredhopperSearchApi=true; _gid=GA1.3.742106807.1580274394; favouritesUuid=1f8625c0-4255-11ea-a013-5bf3d8c0acce; mmapi.p.bid=%22lvsvwcgeu01%22; mmapi.p.srv=%22lvsvwcgeu01%22; mediamathReferralUrl=http%3A%2F%2Fcn.burberry.com%2Fmens-new-arrivals-new-in%2F; LPSID-6899673=mMKP-pQCSxW3XarPamAv-A; _gat=1; Hm_lpvt_0a183129752754c550277ef8f347c9a3=1580313289; mmapi.p.pd=%22-681797386%7CXAAAAApVAwBTKATmpxIU4AABEgABQgAP7o0iBQBakVOV06TXSIkNP2Wuo9dIAAAAAP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAA9jbi5idXJiZXJyeS5jb20CpxIFAAAAAAAAAAAA5bYCAOW2AgDltgIAAwA4JAEAuJua%2FVenEgD%2F%2F%2F%2F%2FAacSqBL%2F%2FxcAAAEAAAAAAeDhAgDcqwMAAeW2AgAXAAAAAg4BAJjThIWOpxIA%2F%2F%2F%2F%2FwGnEqgS%2F%2F8XAAABAAAAAAGMpgIAkFsDAAHltgIAFwAAAPkeAQAuhS3GMKcSAP%2F%2F%2F%2F8BpxKoEv%2F%2FFwAAAQAAAAABnNMCAIOZAwAB5bYCABcAAAAAAAAAAAFF%22; _cs_id=2468e318-c811-a969-be08-20c949f87206.1580187380.7.1580313293.1580312933.1.1614351380113; _cs_s=5.1'
      	Refer = 'https://cn.burberry.com/mens-new-arrivals-new-in/'
      
      	header = {
          'Authority':'cn.burberry.com',
          'User-agent':USER_AGENT,
          'Cookie':Cookie,
          'Referer':Refer,
          'Accept':'application/json, text/javascript, */*; q=0.01',
          'Accept-encoding':'gzip, deflate, br',
          'Accept-language':'zh-CN,zh;q=0.9',
          'Sec-fetch-mode':'cors',
          'Sec-fetch-site':'same-origin',
          'X-csrf-token':'p6nTTTy3-IcLowOIEB_u1lbpowcTgZ3wVPkA',
          'X-newrelic-id':'VwIOVFFUGwIJVldQBAQA',
          'X-requested-with':'XMLHttpRequest'
      	}
      

      這樣我們就完善了資訊!接下來進行訪問!

    • 訪問指令碼檔案,將其下載到本地,並進行分析:

      1.訪問並下載

      	import requests
      	from bs4 import BeautifulSoup
      	#訪問
      	web_response = requests.get(url,headers=header)
      	
      	#用text屬性取得字串,方便寫入檔案
      	web_text = web_response.text
      	#web_content = web_response.content
      	
      	with open('html.json','w',encoding='utf-8') as f:
      		f.write(web_text)
      

      2.利用線上json分析器對下載下來的一堆字元進行分析~即將html.json中的所有字元複製到網站中
      在這裡插入圖片描述
      人家把縮排啥的都給我們加好啦!我們要做的就是找資料!名稱、價格和圖片源~

      • 發現名稱都存在label屬性中
      • 圖片源url存在imagesimg屬性中
      • 價格存在price屬性中
      • 這樣我們就找全啦,開始程式碼??
    • 等等!我們想要完成的是任何時候執行程式碼就能得到所有最新上架,但是現在這個網頁是固定死的呀!沒辦法讓它保持更新,怎麼辦呢?

      1.分析url,看到結尾的一長串數字,我們聯想到時間,一查,果然,這是從1970-1-1一直到訪問網頁的時刻的總毫秒數,於是我們利用time庫確定當前時間~並把url稍作修改:

      	import time
      	#修正url,保留時間戳前的部分
      	url = 'https://cn.burberry.com/service/shelf/mens-new-arrivals-new-in/?_='
      	#獲取當前時間
      	_time = int(time.time()*1000)
      	#修改url
      	url += str(_time)
      

      2.接下來就可以放心寫程式碼啦

  • 寫程式碼

    	import json
    	#定義儲存路徑,需要提前建立資料夾
    	savePath = 'C:/Users/Administrator/Pictures/Burberry_New_Arrivals/'
    	def download(imgSrc,title):
    		#定義檔名
    		fileName = savePath + title + '.jpg'
    		#圖片url
    		img_url = 'http:' + imgSrc
    		#訪問
    		img_response = requests.get(img_url,headers = header)
    		img_content = img_response.content
    		#下載寫入
    		with open(fileName,'wb') as file:
        		file.write(img_content)
        		
    	#建立列表,儲存資訊
    	name_list = list()
    	price_list = list()
    	img_list = list()
    	#將bytes型別讀取為json型別
    	json_content = json.loads(web_content)
    	#根據分析結果,找名稱、價格、圖片源
    	for item in json_content:
    		#利用json的get方法找屬性
     		name_list.append(item.get('label'))
    		price_list.append(item.get('price'))
    		img_list.append(item.get('images').get('img').get('src'))
    		
    	#利用zip打包三個列表	
    	img_zip = zip(name_list,price_list,img_list)
    
    	for each in img_zip:
    		#用名稱+價格作為標題
    		title = each[0] + str(each[1])
    		#下載
    		download(each[2],title)
    		
    

    完成!

    5.原始碼

    • 爬取靜態網頁spider.py

    import requests
    import lxml
    import re
    from bs4 import BeautifulSoup
    
    url = 'https://www.mzitu.com/221136'
    header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0",
              "Referer": "https://www.mzitu.com/jiepai/comment-page-1/"
              }
    
    response = requests.get(url, headers=header)  # 請求網頁
    content = response.content  # 獲取html
    
    
    bsobj = BeautifulSoup(content, 'lxml')  # 解析html
    title = bsobj.find('h2', class_='main-title').string  # 需要用class_
    picture_max = bsobj.find('div', class_='pagenavi').find_all('a')[-2].string  # 一共多少張圖
    
    
    for i in range(1, int(picture_max)):
    
        href = url + '/' + str(i)  # 訪問每一頁
        response = requests.get(href, headers=header)  # 請求資料
        content = response.content  # 得到二進位制物件
        soup = BeautifulSoup(content, 'lxml')  # 初始化
    
        # 找img標籤,訪問src屬性,找圖片url
        picture_url = soup.find('img', alt=title).attrs['src']
        # 訪問圖片url
        response_img = requests.get(picture_url, headers=header)
        # 獲取二進位制圖片檔案
        content_img = response_img.content
        # 命名檔案,注意加.jpg
        file_name = title + '-' + str(i) + '.jpg'
        # 寫入,注意以二進位制寫入方式開啟
        with open(file_name, 'wb') as f:
            f.write(content_img)
    
    • 爬取動態網頁burberryInfo.py

    import re
    import requests
    import lxml
    import random
    import json
    import time
    from bs4 import BeautifulSoup
    	
    def download(imgSrc, title):
        fileName = savePath + title + '.jpg'
    
        img_url = 'http:' + imgSrc
        # print(img_url)
        img_response = requests.get(img_url, headers=header)
        img_content = img_response.content
        with open(fileName, 'wb') as file:
            file.write(img_content)
    
    url = 'https://cn.burberry.com/service/shelf/mens-new-arrivals-new-in/?_='
    USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:66.0) Gecko/20100101 Firefox/66.0"
    	
    Cookie = '_ga=GA1.3.396709042.1580187372; Hm_lvt_0a183129752754c550277ef8f347c9a3=1580187372; mm-if-site-persist-ua-44=%5B%22Fredhopper%20Search%20vs%20ATG%20Search%3Dsearch%3Avariant%22%2C%22T103%20-%20For%20U%20Entrance_CN%3Dnavbarlink%3Avariant%22%5D; storeId=store_cn; language=zh_CN; burberryId=7bb25b00-418a-11ea-b799-55681cc34864_NULL_NULL; _cs_c=1; LPVID=Y5OTExZWZkN2E2ODU3MjJm; recentViewed=80255061; fita.sid.burberry_cn=_m_DQ-7-69P0cFThc2tobfutAzbPHGD4; sessionId=s%3AReNqxNlCK1NzYQoeLWwIj_coMlvnjpWk.0%2Bg%2FXkrRjQkaRGXI7EDgnCh%2BZFsWsJfMDSqfUwNsPI0; useFredhopperSearchApi=true; _gid=GA1.3.742106807.1580274394; favouritesUuid=1f8625c0-4255-11ea-a013-5bf3d8c0acce; mmapi.p.bid=%22lvsvwcgeu01%22; mmapi.p.srv=%22lvsvwcgeu01%22; mediamathReferralUrl=http%3A%2F%2Fcn.burberry.com%2Fmens-new-arrivals-new-in%2F; LPSID-6899673=mMKP-pQCSxW3XarPamAv-A; _gat=1; Hm_lpvt_0a183129752754c550277ef8f347c9a3=1580313289; mmapi.p.pd=%22-681797386%7CXAAAAApVAwBTKATmpxIU4AABEgABQgAP7o0iBQBakVOV06TXSIkNP2Wuo9dIAAAAAP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAA9jbi5idXJiZXJyeS5jb20CpxIFAAAAAAAAAAAA5bYCAOW2AgDltgIAAwA4JAEAuJua%2FVenEgD%2F%2F%2F%2F%2FAacSqBL%2F%2FxcAAAEAAAAAAeDhAgDcqwMAAeW2AgAXAAAAAg4BAJjThIWOpxIA%2F%2F%2F%2F%2FwGnEqgS%2F%2F8XAAABAAAAAAGMpgIAkFsDAAHltgIAFwAAAPkeAQAuhS3GMKcSAP%2F%2F%2F%2F8BpxKoEv%2F%2FFwAAAQAAAAABnNMCAIOZAwAB5bYCABcAAAAAAAAAAAFF%22; _cs_id=2468e318-c811-a969-be08-20c949f87206.1580187380.7.1580313293.1580312933.1.1614351380113; _cs_s=5.1'
    Refer = 'https://cn.burberry.com/mens-new-arrivals-new-in/'
    	
    header = {
        'Authority': 'cn.burberry.com',
        'User-agent': USER_AGENT,
        'Cookie': Cookie,
        'Referer': Refer,
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-encoding': 'gzip, deflate, br',
        'Accept-language': 'zh-CN,zh;q=0.9',
        'Sec-fetch-mode': 'cors',
        'Sec-fetch-site': 'same-origin',
        'X-csrf-token': 'p6nTTTy3-IcLowOIEB_u1lbpowcTgZ3wVPkA',
        'X-newrelic-id': 'VwIOVFFUGwIJVldQBAQA',
        'X-requested-with': 'XMLHttpRequest'
    }
    	
    _time = int(time.time()*1000)
    url += str(_time)
    	
    # 定義儲存路徑,根據自己需要修改,需要提前建立資料夾
    savePath = 'C:/Users/Pt/Pictures/Burberry_New_Arrivals/'
    
    # 訪問
    web_response = requests.get(url, headers=header)
    
    web_content = web_response.content
    	
    # 用text屬性取得字串,方便寫入檔案
    # web_text = web_response.text
    # with open('html3.json','w',encoding='utf-8') as f:
    #    f.write(web_content)
    
    # 建立列表,儲存資訊
    name_list = list()
    price_list = list()
    img_list = list()
    # 將bytes型別讀取為json型別
    json_content = json.loads(web_content)
    # 根據分析結果,找名稱、價格、圖片源
    	
    for item in json_content:
        #利用json的get方法找屬性
        name_list.append(item.get('label'))
        price_list.append(item.get('price'))
        img_list.append(item.get('images').get('img').get('src'))
    
    # 利用zip打包三個列表
    img_zip = zip(name_list,price_list,img_list)
    	
    for each in img_zip:
    	# 用名稱+價格作為標題
        title = each[0] + str(each[1])
        # 下載
        download(each[2],title)
    

相關文章