還沒有看飽網絡美女,輕鬆教你使用python爬蟲爬取網絡美女圖片,讓你一次看過癮

前言

還在去網站上找網絡美女看嘛,卻發現網站上找到的並不是特別好看,而且比較模糊,下面教你們如何用爬蟲去爬取網絡美女圖片。

一、準備工作
安裝requests庫(用於請求靜態頁面)

pip install requests -i https://mirrors.ustc.edu.cn/pypi/web/simple

安裝lxml庫(用於解析html文件)

pip install lxml -i https://mirrors.ustc.edu.cn/pypi/web/simple

安裝與配置selenium(用於請求動態頁面)

pip install selenium -i https://mirrors.ustc.edu.cn/pypi/web/simple

selenium 需要與瀏覽器配合使用,在以前的爬蟲教程中,往往把 selenium 和 PhantomJS 配合使用,PhantomJS 是一款無界面的瀏覽器,能否執行js腳本,從而可以實現加載和渲染動態頁面。但是由於最新版 selenium 已經不再支持 PhantomJS,所以必須使用其他瀏覽器代替,本教程使用的是Firefox瀏覽器,Firefox瀏覽器也支持無界面模式( headless模式 ),用於爬蟲非常方便。另外Chrome也是支持的。詳細的安裝與配置教程請參考:

Python爬蟲利器五之Selenium的用法

二、頁面分析
打開妹子圖頁面,如下圖。頁面的正文部分列出了33個美女圖集。每個頁面共有33個圖集,總共有33個頁面,所以總共有1089個圖集。圖片的鏈接就包含在每個圖集中。
妹子圖

在頁面上單擊右鍵,選擇 審查元素按鍵,或直接按 F12進入調試模式。頁面結構如下:
在這裏插入圖片描述
妹子圖
妹子圖

點進任意一個圖集中,進入調試模式,可以看出頁面結構如下
妹子圖

源碼詳解
從前面的頁面分析中可以看出,這個網站的頁面結構其實很簡單,我們只需要依次打開第1到第33個頁面,得到每個頁面的html源碼,然後從html源碼中提取出每個頁面上包含的圖集的鏈接列表(共33個),然後再依次打開第1到第33個圖集詳情頁面,但是圖集詳情頁面中的圖片列表是用js動態加載的,我們需要使用selenium加載這個動態頁面,等該頁面加載完畢之後再得到該頁面的html源碼,然後從圖集詳情頁面中提取出每張圖片的鏈接,最後再依次下載每張圖片保存即可。
整個流程其實並不複雜。

使用requests下載靜態html頁面
該函數用於下載圖集列表頁面,這個頁面是靜態的,可以直接通過 requests.get(url) 函數抓取。但是有一點需要注意,爲了把我們的爬蟲僞裝成正常的瀏覽器請求,避免我們的爬蟲被服務器禁止,我們需要給 requests 添加http請求頭,其中包含僞造的 User-Agent 瀏覽器標識

如果你對python感興趣,我這有個學習Python基地,裏面有很多學習資料,感興趣的+Q羣:688244617

def download_page_html(url):
    phtml = None

    try:
        requests_header["User-Agent"] = random.choice(user_agent_list) # 選擇一個隨機的User-Agent
        # print(requests_header)
        page = requests.get(url=url, headers=requests_header) # 請求指定的頁面
        # print(page.encoding)
        page.encoding = "gb2312" # 轉換頁面的編碼爲gb2312(避免中文亂碼)
        phtml = page.text # 提取請求結果中包含的html文本
        # print("requests success") 
        page.close() # 關閉requests請求
    except requests.exceptions.RequestException as e:
        print("requests error:", e)
        phtml = None
    finally:
        return phtml

下載指定鏈接的圖片文件
該函數用於提取出圖片鏈接之後下載圖片,圖片保存在以圖集標題命名的文件夾中

def download_picture(url, dir):
    try:
        picdir = "{0}/{1}".format(PICTURE_PATH, dir) # 構造圖片保存路徑
        # print(picdir)
        if os.path.exists(picdir) != True:
            os.makedirs(picdir) # 如果指定的文件夾不存在就遞歸創建

        pic_name = url.split("/")[-1] # 用圖片鏈接中最後一個/後面的部分作爲保存的圖片名
        pic_full_name = "{0}/{1}".format(picdir, pic_name)

        # print("save picture to :", pic_full_name)

        requests_header["User-Agent"] = random.choice(user_agent_list) # 選擇一個隨機的User-Agent

        response = requests.get(url, headers=requests_header)  # 獲取的文本實際上是圖片的二進制文本
        imgdata = response.content  # 將他拷貝到本地文件 w 寫  b 二進制  wb代表寫入二進制文本
        if len(imgdata) > (5*1024):  # 只保存大於5k的圖片
            with open(pic_full_name, 'wb') as f:
                f.write(imgdata) # 把圖片數據寫入文件。with語句會自動關閉f
            print("save picture to :", pic_full_name)
        else:
            print("picture size too small")
        response.close()
    except:
        print("download piccture {0} error".format(url))

獲取所有需要爬取的頁面數
我們剛纔已經分析過了,實際上只有33個需要處理的頁面,但是以後網站肯定會更新,爲了兼容性,我們並不準備寫死,而是從html頁面中提並分析出待處理的頁面數。在選擇頁面底部的導航欄中有一個 末頁 按鈕,其href屬性中包含了一個數字,這個數字就是頁面的數目(也是頁面的序號)。

def get_page_list_num(tree):

    page_list_num = 0

    try:
        gotolast = tree.xpath("/html/body/div[1]/div[2]/div[2]/div[1]/div[2]/div/ul/li[18]/a/@href")[0]  # sexy_33.html
        # print(gotolast)
        gotolast = str(gotolast)
        # print(gotolast)
        gotolast = re.sub(r"\D", "", gotolast)  # 把非數字字符串替換爲空
        page_list_num = int(gotolast)  # 轉化爲整數
        print("max_page_number:", page_list_num)
    except:
        print("get page number error")
        page_list_num = 0
    finally:
        return page_list_num

xpath選擇器
其實要在複雜的html文件中定位出我們需要的元素並不容易,但是一般瀏覽器都爲我們提供了這一功能,比如我所使用的firefox瀏覽器就自帶了這一功能,選中所需要的元素,然後在右鍵複製菜單中可以看到 複製Xpath的選項,使用它可以幫助我們快速定位我們需要的元素。下文所有的xpath都是使用這種方式得到的。如下圖:
妹子圖

獲取頁面中的圖片集列表

def get_pagealbum_list(tree):  # 獲取頁面中的圖片集列表
    pagealbum_list = []
    pagealbum_list = tree.xpath(
        "/html/body/div[1]/div[2]/div[2]/div[1]/div[1]/ul/li/div/div/a/@href")
    return pagealbum_list

獲取圖集的標題和圖集中的圖片鏈接
這裏同樣使用的firefox的xpath工具定位到我們需要的元素的,然後通過lxml庫的xpath方法從html頁面中提取出我們想要的內容

def get_albumphoto_list(tree):  # 獲取圖集中的圖片列表
    albumphoto_list = []
    albumphoto_list = tree.xpath(
        "/html/body/div[2]/div[2]/div[2]/div[1]/div[2]/div[1]/p/img/@src")
    return albumphoto_list


def get_albumphoto_title(tree):  # 獲取圖集中的標題
    albumphoto_title = None
    albumphoto_title = tree.xpath(
        "/html/body/div[2]/div[2]/div[2]/div[1]/div[1]/div[1]/h2/a/text()")[0]
    # print(albumphoto_title)
    return albumphoto_title

加載和渲染動態網頁
由於圖集詳情頁中的圖片列表是通過js代碼動態渲染得到的,所以如果直接通過requests請求這個頁面會得到一個只包含js代碼的html,裏面並沒有我們需要的圖片鏈接,因爲requests請求不能執行js代碼,所以沒法加載出圖片。我們這裏需要使用selenium配合firefox瀏覽器來加載和渲染這個動態頁面,等待渲染完成後再獲取html源碼,這時html中包含了圖片鏈接

def web_driver_init():
    global web_driver
    if web_driver == None:
        options = Options()
        options.add_argument('-headless')  # 無頭參數
        # 配了環境變量第一個參數就可以省了,不然傳絕對路徑
        web_driver = Firefox(firefox_options=options)
        web_driver.implicitly_wait(20)


def web_driver_page(url):
    htmlpage = None
    try:
        web_driver.get(url)
        htmlpage = web_driver.page_source
    except:
        print("get webpage {0} error".format(url))
    finally:
        return htmlpage


def web_driver_exit():
    if web_driver != None:
        web_driver.close()

爬蟲處理邏輯meizitu_webspider

def meizitu_webspider():
    global page_list_num
    global page_list_idx
    global requests_url
    global webspider_sleep

    print("requests_url :", requests_url)
    page_html_list = download_page_html(requests_url)  # 下載當前頁面
    if(page_html_list != None):
        # print(page_html_list)
        tree = lxml.html.fromstring(page_html_list)
        if page_list_num == 0:  # 計算當前共有多少個頁面需要處理
            page_list_num = get_page_list_num(tree)

        pagealbum_list = get_pagealbum_list(tree)  # 獲取當前頁面中圖集列表
        # print(pagealbum_list)
        for lst in pagealbum_list:  # 以此遍歷當前頁面中的每個圖集
            print("album_list:", lst)
            # 圖集使用的js異步加載圖片,所以這裏要用selenium加載動態頁面
            albumphoto_page = web_driver_page(lst)
            # print(albumphoto_page)
            if albumphoto_page != None:
                tree0 = lxml.html.fromstring(albumphoto_page)

                albumphoto_title = get_albumphoto_title(tree0)  # 獲取圖集標題
                print("Title:", albumphoto_title)

                albumphoto_list = get_albumphoto_list(tree0)  # 獲取圖集中的圖片列表
                for plst in albumphoto_list:
                    print("imgsrc:", plst)

                    download_picture(plst, albumphoto_title)  # 下載圖片

                    webspider_sleep = random.randint(1, 5)  # 延時一個隨機值,避免被服務器反爬
                    print("waiting {0} seconds".format(webspider_sleep))
                    time.sleep(webspider_sleep)

        if page_list_idx < page_list_num:  # 遞歸處理下一個頁面
            page_list_idx = page_list_idx + 1
            requests_url = REQUEST_URL1.format(page_list_idx)
            meizitu_webspider()
        else:
            return 0

運行爬蟲

if __name__ == "__main__":
    web_driver_init()  # 初始化selenium
    meizitu_webspider()
    web_driver_exit()  # 退出selenium

程序運行截圖
在這裏插入圖片描述

項目文件截圖
妹子圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章