爬蟲豆瓣美女

我是冰霜發表於2018-11-28

這次爬取一點有意思的東西,爬豆瓣美女網站

1.爬取目標

本次爬蟲比較簡單,先只爬取豆瓣美女網站中的“大胸妹”tab,而且只爬取最外層的圖片,不點開圖集,如下

2.分析網頁元素

網頁原始碼如下

可以看到很明顯的規律,每個圖片都包裹在<img>標籤中,而且title屬性代表名稱,src屬性代表圖片url

所以本次爬蟲就提取上述2個元素:alt和src

可以用BeautifulSoup或者正規表示式進行提取

3.爬取過程

先貼出完整程式碼,再進行分析

# -*- coding:utf-8 -*-
import requests
from requests.exceptions import RequestException
from bs4 import BeautifulSoup
import bs4
import os


def get_html(url, header=None):
    """請求初始url"""
    response = requests.get(url, headers=header)
    try:
        if response.status_code == 200:
            # print(response.status_code)
            # print(response.text)
            return response.text
        return None
    except RequestException:
        print("請求失敗")
        return None


def parse_html(html, list_data):
    """提取img的名稱和圖片url,並將名稱和圖片地址以字典形式返回"""
    soup = BeautifulSoup(html, 'html.parser')
    img = soup.find_all('img')
    for t in img:
        if isinstance(t, bs4.element.Tag):
            # print(t)
            name = t.get('alt')
            img_src = t.get('src')
            list_data.append([name, img_src])
    dict_data = dict(list_data)
    return dict_data

def get_image_content(url):
    """請求圖片url,返回二進位制內容"""
    print("正在下載", url)
    try:
        r = requests.get(url)
        if r.status_code == 200:
            return r.content
        return None
    except RequestException:
        return None


def main(num=None, depth=None):
    base_url = 'https://www.dbmeinv.com/index.htm?'
    for i in range(1, depth):
        url = base_url + 'cid=' + str(num) + '&' + 'pager_offset=' + str(i)
        # print(url)
        header = {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q = 0.9, image/webp,image/apng,*/*;q='
                      '0.8',
            'Accept-Encoding': 'gzip,deflate,br',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Cache-Control': 'max-age=0',
            'Connection': 'keep-alive',
            'Host': 'www.dbmeinv.com',
            'Upgrade-Insecure-Requests': '1',
            'User-Agent': 'Mozilla/5.0(WindowsNT6.1;Win64;x64) AppleWebKit/537.36(KHTML, likeGecko) Chrome/'
                          '70.0.3538.102Safari/537.36 '
        }
        list_data = []
        html = get_html(url)
        # print(html)
        dictdata = parse_html(html, list_data)
        # print(list_data)
        # print(dict(list_data))
        # print(data)
        # for url in data.values():
        #     download_image(url)
        root_dir = os.path.dirname(os.path.abspath('.'))
        save_path = root_dir + '/pics/'
        for t in dictdata.items():
            file_path = '{0}/{1}.{2}'.format(save_path, t[0], 'jpg')
            if not os.path.exists(file_path):  # 判斷是否存在檔案,不存在則爬取
                with open(file_path, 'wb') as f:
                    f.write(get_image_content(t[1]))
                    f.close()
                    print('檔案儲存成功')


if __name__ == '__main__':
    # t = main(2)
    # print(t)  # 這樣列印之所以為None,是因為main函式中沒有任何內容返回出來,尷尬了。。。
    main(2, 10)

(1)構造url

“大胸妹”首頁url為:https://www.dbmeinv.com/index.htm?cid=2

翻到下一頁後,變為:https://www.dbmeinv.com/index.htm?cid=2&pager_offset=2

可以看到有2個引數cid和pager_offset

所在在主函式中,定義了2個引數,一個表示“大胸妹”對應的cid值,一個表示翻頁

def main(num=None, depth=None):
    base_url = 'https://www.dbmeinv.com/index.htm?'
    for i in range(1, depth):
        url = base_url + 'cid=' + str(num) + '&' + 'pager_offset=' + str(i)

 

(2)分析parse_html()方法

這個方法用來提取圖片的title和src,使用的是BeautifulSoup;

傳入2個引數,一個是初始url的返回內容,另外定義了一個list_data這裡表示一個列表,會把提取到的title和src,以[title:src]的形式追加到list_data中;

然後再把list_data轉換為字典返回出去,這樣就得到了一個以title為鍵,以src為值的字典。

後面可以通過迭代這個字典,在儲存圖片時,使用圖片的title作為圖片名稱

列印list_data和dict_data分別如下

 

 (3)根據parse_html()方法得到圖片url後,還需要進一步請求圖片url,並將返回的二進位制內容以jpg的格式進行儲存

首先定義了一個get_image_content()方法,它與get_html()方法一樣,不過是返回的二進位制內容

然後就是主函式中構造圖片儲存的形式了:

因為parse_html()方法返回了dict_data,它是以title為鍵,以src為值的字典,

我們知道迭代字典,可以得到一個鍵值對組成的元組,如下:

所以可以通過迭代這個字典,分別提取字典的鍵作為圖片名稱,提取字典值作為圖片url進行請求,如下:

root_dir = os.path.dirname(os.path.abspath('.'))
save_path = root_dir + '/pics/'
for t in dictdata.items():
    file_path = '{0}/{1}.{2}'.format(save_path, t[0], 'jpg')
    if not os.path.exists(file_path):  # 判斷是否存在檔案,不存在則爬取
        with open(file_path, 'wb') as f:
            f.write(get_image_content(t[1]))
            f.close()
            print('檔案儲存成功')

t[0]表示每個鍵值對的鍵,即圖片的title;t[1]表示每個鍵值對的值,即圖片的url

 

 最終儲存的圖片如下

 


 

補充:用正則提取

import re
import requests
import os
from requests.exceptions import RequestException

r = requests.get('https://www.dbmeinv.com/index.htm?cid=2')
# print(r.status_code)
html = r.text
# print(r.text)
# print(html)

name_pattern = re.compile(r'<img class="height_min".*?title="(.*?)"', re.S)
src_pattern = re.compile(r'<img class="height_min".*?src="(.*?.jpg)"', re.S)

name = name_pattern.findall(html)  # 提取title
src = src_pattern.findall(html)  # 提取src
data = [name,src]
# print(name)
# print(src)
d=[]
for i in range(len(name)):
    # print(name[i])
    # print(src[i])
    d.append([name[i], src[i]])

dictdata = dict(d)
for i in dictdata.items():
    print(i)

def get_content(url):
    try:
        r = requests.get(url)
        if r.status_code == 200:
            return r.content
        return None
    except RequestException:
        return None


root_dir = os.path.dirname(os.path.abspath('.'))
save_path = root_dir + '/pics/'
for t in dictdata.items():
    file_path = '{0}/{1}.{2}'.format(save_path, t[0], 'jpg')
    if not os.path.exists(file_path):  # 判斷是否存在檔案,不存在則爬取
        with open(file_path, 'wb') as f:
            f.write(get_content(t[1]))
            f.close()
            print('檔案儲存成功')

 

相關文章