剛剛入門爬蟲,今天先對於單個圖集進行爬取,過幾天再進行翻頁爬取。
使用requests庫和BeautifulSoup庫
目標網站:妹子圖
今天是對於單個圖集的爬取,就選擇一個進行爬取,我選擇的鏈接為:http://www.mzitu.com/123114
首先網站的分析,該網站有一定的反爬蟲策略,所以應對就是加入headers(目前是小白,目前不知道具體為毛這樣做)
Hostreferer = { 'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 'Referer':'http://www.mzitu.com' } Picreferer = { 'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 'Referer':'http://i.meizitu.net' }
前一個頭作為請求網站,后一個頭作為破解盜鏈使用
獲得頁面HTML代碼
用requests庫的get方法,加上Hostreferer
def get_html(url):#獲得頁面html代碼 req = requests.get(url, headers=Hostreferer) html = req.text return html
獲得圖集名稱以及圖集最大頁數
分析網頁構成如圖所示,圖集名稱包含在h2標簽內,且該標簽在整個HTML代碼里有唯一的class="main-title",
而最大頁數只是被span標簽包含,無法通過屬性來提取。所以提取圖集名稱采取標簽名+屬性名一起提取,而最大頁數就采取將span標簽全部找出,最大頁數在span標簽中第11位,
def get_page_name(url):#獲得圖集最大頁數和名稱 html = get_html(url) soup = BeautifulSoup(html, 'lxml') span = soup.findAll('span') title = soup.find('h2', class_="main-title") return span[10].text, title.text
獲得圖片url鏈接
分析頁面內容,含有圖片鏈接的img標簽中有一個alt屬性的值是跟圖集名稱相同,可以用這個來直接找到這個標簽,當然也可以先找到div標簽中的class屬性是main-inage,再找到img的src屬性,這里我就采用第一種方法。
def get_img_url(url, name): html = get_html(url) soup = BeautifulSoup(html, 'lxml') img_url = soup.find('img', alt= name) return img_url['src']
將圖片存入本地
得到圖片url鏈接之后要講圖片存到本地,在請求圖片url的時候要加入Picreferer,否則網站會認為你是一個爬蟲,會返還給你一個盜鏈圖
該方法傳入的參數有3個,第一個是圖片url,第二個當前圖片的頁數,用作創建文件,第三個是圖集名稱,在存儲之前先創建了一個名稱是圖集名稱的文件夾,這樣就能將圖片存入指定文件夾
def save_img(img_url, count, name): req = requests.get(img_url, headers=Picreferer) with open(name+'/'+str(count)+'.jpg', 'wb') as f: f.write(req.content)
爬取一個圖集完整代碼
import requests from bs4 import BeautifulSoup import os Hostreferer = { 'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 'Referer':'http://www.mzitu.com' } Picreferer = { 'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 'Referer':'http://i.meizitu.net' } def get_page_name(url):#獲得圖集最大頁數和名稱 html = get_html(url) soup = BeautifulSoup(html, 'lxml') span = soup.findAll('span') title = soup.find('h2', class_="main-title") return span[10].text, title.text def get_html(url):#獲得頁面html代碼 req = requests.get(url, headers=Hostreferer) html = req.text return html def get_img_url(url, name): html = get_html(url) soup = BeautifulSoup(html, 'lxml') img_url = soup.find('img', alt= name) return img_url['src'] def save_img(img_url, count, name): req = requests.get(img_url, headers=Picreferer) with open(name+'/'+str(count)+'.jpg', 'wb') as f: f.write(req.content) def main(): old_url = "http://www.mzitu.com/123114" page, name = get_page_name(old_url) os.mkdir(name) for i in range(1, int(page)+1): url = old_url + "/" + str(i) img_url = get_img_url(url, name) #print(img_url) save_img(img_url, i, name) print('保存第' + str(i) + '張圖片成功') main()
在main方法中先請求到圖集的名稱和最大頁數,並且使用名稱創建一個文件夾來存儲圖片。再從1到最大頁數做一個for循環,
然后圖片的每一頁是 圖集首頁 + / + 當前頁數,得到含有圖片內容的url鏈接,后面就可以將得到圖片存入本地。
爬取結果
文件夾名稱即為圖集名稱,內部圖片以頁數作為文件名。
下面准備開始多個頁面的爬取,先將前面爬取一個圖集的方法進行封裝
爬取一個圖集
在進行爬取一個圖集前先加入一個方法,在爬取圖集名稱的時候,由於名稱的字符不限,所以可能出現含有文件夾中不能出現的一些字符,例如:/ \ : ? < > 等
所以需要將前面的代碼進行修改,加入一個rename方法,將這些字符換成可行的字符。(在這里我就直接將這些字符去掉)
這里采用re庫,將name中含有的非法字符換成空,可以看做直接去掉。
import re def rename(name): rstr = r'[\/\\\:\*\?\<\>\|]' new_name = re.sub(rstr, "", name) return new_name def save_one_atlas(old_url): page, name = get_page_name(old_url) new_name = rename(name) os.mkdir(new_name) print("圖集--" + name + "--開始保存") for i in range(1, int(page)+1): url = old_url + "/" + str(i) img_url = get_img_url(url, name) # print(img_url) save_img(img_url, i, name) print('正在保存第' + str(i) + '張圖片') print("圖集--" + name + "保存成功")
爬取一整頁圖集
def get_atlas_list(url): req = requests.get(url, headers=Hostreferer) soup = BeautifulSoup(req.text, 'lxml') atlas = soup.find_all(attrs={'class':'lazy'}) atlas_list = [] for atla in atlas: atlas_list.append(atla.parent['href']) return atlas_list
分析一個頁面中的url鏈接,發現如果找 target="_blank" 這一屬性,則會產生很多多余的鏈接,所以我直接從字標簽入手找到屬性 class="lazy"的img標簽,然后再在尋找到img標簽的父標簽中的href
def save_one_page(start_url): atlas_url = get_atlas_list(start_url) for url in atlas_url: save_one_atlas(url)
將爬取一整夜圖集進行封裝,方便后續的翻頁爬取
翻頁爬取
分析頁面url,發現每一頁均是初始網址+page/+頁數/
第一頁是初始網址,但是頁數為1的鏈接也是直接進入第一頁,所以所有頁的url就可以用以上通式改變頁數進行遍歷。
start_url = "http://www.mzitu.com/" for count in range(1, 3): url = start_url + "page/" + str(count) +"/" save_one_page(url)
這里作為測試,所以只爬取前兩頁圖集。改變range內的參數,即可改變爬取頁數。
完整代碼

1 import requests 2 from bs4 import BeautifulSoup 3 import os 4 import re 5 6 Hostreferer = { 7 'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 8 'Referer':'http://www.mzitu.com' 9 } 10 Picreferer = { 11 'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 12 'Referer':'http://i.meizitu.net' 13 } 14 15 def get_page_name(url):#獲得圖集最大頁數和名稱 16 html = get_html(url) 17 soup = BeautifulSoup(html, 'lxml') 18 span = soup.findAll('span') 19 title = soup.find('h2', class_="main-title") 20 return span[10].text, title.text 21 22 def get_html(url):#獲得頁面html代碼 23 req = requests.get(url, headers=Hostreferer) 24 html = req.text 25 return html 26 27 def get_img_url(url, name): 28 html = get_html(url) 29 soup = BeautifulSoup(html, 'lxml') 30 img_url = soup.find('img', alt= name) 31 return img_url['src'] 32 33 def save_img(img_url, count, name): 34 req = requests.get(img_url, headers=Picreferer) 35 new_name = rename(name) 36 with open(new_name+'/'+str(count)+'.jpg', 'wb') as f: 37 f.write(req.content) 38 39 def rename(name): 40 rstr = r'[\/\\\:\*\?\<\>\|]' 41 new_name = re.sub(rstr, "", name) 42 return new_name 43 44 def save_one_atlas(old_url): 45 page, name = get_page_name(old_url) 46 new_name = rename(name) 47 os.mkdir(new_name) 48 49 print("圖集--" + name + "--開始保存") 50 for i in range(1, int(page)+1): 51 url = old_url + "/" + str(i) 52 img_url = get_img_url(url, name) 53 # print(img_url) 54 save_img(img_url, i, name) 55 print('正在保存第' + str(i) + '張圖片') 56 print("圖集--" + name + "保存成功") 57 58 59 def get_atlas_list(url): 60 req = requests.get(url, headers=Hostreferer) 61 soup = BeautifulSoup(req.text, 'lxml') 62 atlas = soup.find_all(attrs={'class':'lazy'}) 63 atlas_list = [] 64 for atla in atlas: 65 atlas_list.append(atla.parent['href']) 66 return atlas_list 67 68 def save_one_page(start_url): 69 atlas_url = get_atlas_list(start_url) 70 for url in atlas_url: 71 save_one_atlas(url) 72 73 74 if __name__ == '__main__': 75 start_url = "http://www.mzitu.com/" 76 for count in range(1, 3): 77 url = start_url + "page/" + str(count) +"/" 78 save_one_page(url) 79 print("爬取完成")
這個程序能夠爬取圖片,但是效率太低,正在學習多進程,希望之后可以提高該程序的爬取效率。
我爬了3個多G的圖片花了我接近4個小時,足以證明效率是真的低。
並且在爬取過程中出現一個問題,提示 你的主機中的軟件中止了一個已建立的連接 ,這個問題還未找到解決方法,也未找明產生的具體原因。
這是我寫的第一篇較長的博客,還有很多未完善的地方,希望大家見諒。