爬取妹子圖(requests + BeautifulSoup)


  剛剛入門爬蟲,今天先對於單個圖集進行爬取,過幾天再進行翻頁爬取。

  使用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("爬取完成")
View Code

 

這個程序能夠爬取圖片,但是效率太低,正在學習多進程,希望之后可以提高該程序的爬取效率。

我爬了3個多G的圖片花了我接近4個小時,足以證明效率是真的低。

並且在爬取過程中出現一個問題,提示 你的主機中的軟件中止了一個已建立的連接 ,這個問題還未找到解決方法,也未找明產生的具體原因。

這是我寫的第一篇較長的博客,還有很多未完善的地方,希望大家見諒。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM