爬虫爬取图片练习

开始:

最近在自学爬虫,自己也做了一些实例,(自认为)写的比较好的就是对整个网站的爬取了。接下来我将会说一说我使用的工具及方法。

注意:为了尊重网站维护人员,我只爬取了网站首页的24个套图,其余的,需要的小伙伴可以自行添加翻页操作!!!

编译环境和所需库

IDE: PyCharm Community Edition 2020.1 x64
python版本: 3.8.2
所需库: requests , BeautifulSoup4,os,time,random


分析与步骤:

第一步

废话不多说,我们直接开始:
第一件事就是导库了,这个简单,就不用我多说了吧。直接上代码:

import os
import time
from random import random
import requests
from bs4 import BeautifulSoup
第二步

这第二件事当然是要去请求网站了,但是我们了解到该网站有反爬机制,所以我们必须先包装一下自己。

ref_url='https://www.mzitu.com'
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36 Edg/81.0.416.53',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'cache-control': 'max-age=0',
    'Referer': ref_url
    }

:为什么 headers 字段中 Referer 的值要设为全局变量
:因为我在测试代码可行性的时候发现,当 Referer 的值为一个定值时,请求大量数据,就会触发反爬机制,导致出现下标越界(或者是找不到某个标签)的异常。从而导致爬取中断。另外根据网站的反爬机制,Referer 字段是必须要有的。

第三步

当我们打开主页就会发现,主页上有24个套图链接,每个套图链接就是一套写真。所以,我们首先爬取的应该是主页上这24个套图链接:
打开浏览器进入主页后查看源码,我们可以看到,首页中24个套图链接都在 ‘ li ’ 标签里面。
所以在代码中 ,我先用 BeautifulSoup 解析源码,将每套图的 ‘ li ’ 标签保存到 Temp_list 中。
再利用 for 提取出每个套图链接,再次进行解析。取出每个 ’ a ’ 标签属性中的 ’ href ’ 字段的值。
又将 ’ href ’ 字段的值作为关键字,保存每套图的名字(每个 ’ img ’ 标签属性中的 ’ alt ’ 字段的值),生成一个字典。
最后,提示当前页面的所有链接都保存成功。
代码如下:

def get_main_url(url):  # 获取每个主页的24个图片链接
    res = requests.get(url,headers=header)
    soup = BeautifulSoup(res.text, 'html.parser')
    Temp_list = soup.find_all('li')[8:]
    # [8:] 的目的是过滤掉多余的 li 标签
    for lab_list in Temp_list:
        div = BeautifulSoup(str(lab_list), 'html.parser')
        main_url.append(div.a.attrs['href'])  
        # 每个主页中套图详情列表链接
        name_dict[div.a.attrs['href']] = div.img.attrs['alt']
        # 每个主页中套图名字列表
    print("获取当前页面所有链接成功!")
第四步

来到这里,我首先用 for 挨个取出这24个套图链接。
然后取出每一个套图链接的名字,判断是否有同名文件夹,如果有,则跳过,如果没有,则创建。
接着对每个链接进行解析,找出该套图链接中的图片页数。
紧接着,利用 for 进行翻页操作。
for 每翻一页,就对当前页面进行解析。
通过 BeautifulSoup 解析后,取出 ’ div ’ 标签下, ’ img ’ 属性中的 ‘ arc ’ 字段的值,即为高清图片的地址。
通过 requests 库请求该图片链接(同样要带上 header ,不然仍然会触发反爬,导致图片出错)。
接下来利用 ‘ split ’ 对图片链接进行处理,取出当前图片名字作为图片名。
’ split ‘ 不会用?点击查看使用方法
最后,将转换为二进制的图片保存下来。
注意:当我们以一定频率或者速度(requests请求速度几乎是一定的)去大量的连续请求时,还是会触发反爬,所以在每爬完一张照片后开始随机休眠。(如果还是不够的话,可以写成 ’ time.sleep(random() * 5) ’ ,数字随便定,不过要注意:数字太大下载会很慢,太小会触发反爬,根据情况可以自行设置)
代码如下:

def get_image():
    global main_num,ref_url
    for now_url in main_url:
        main_num+=1   #第 main_num 套图
        ref_url=now_url  #修改当前的 Referer 
        
        if os.path.exists(path + '/' + name_dict[now_url]):
            pass
        else:
            os.mkdir(path + '/' + name_dict[now_url])
            
        response = requests.get(now_url, headers=header)
        soup = BeautifulSoup(response.text, 'html.parser')
        page_nums = soup.find('div', attrs={'class': "pagenavi"})
        page_num = BeautifulSoup(str(page_nums), 'html.parser').find_all('span')[-2].string
        
        for i in range(1, int(page_num) + 1):
            now_new_url = now_url + '/' + '{}'.format(i)
            new_response = requests.get(now_new_url, headers=header)
            Temp = BeautifulSoup(new_response.text, 'html.parser')
            image_url = Temp.find('div', attrs={'class': "main-image"}).img.attrs['src']
            image = requests.get(image_url,headers=header)
            name = str(image_url).split('/', 5)[-1]
            
            with open(path + '/' + name_dict[now_url] + '/' + name, 'wb') as f:
                f.write(image.content)
                print('正在爬取第'+str(main_num)+'个图库的第'+str(i)+'张图片,本页共'+page_num+'张照片。')
                time.sleep(random())

最后:

主要功能写完后,就可以开始用主函数调用了:

if __name__ == '__main__':
    start_time = time.time()
    get_main_url(url)
    get_image()
    end_time = time.time()
    print('耗时:' + str(end_time - start_time))

运行时展示:
在这里插入图片描述
最最最最最后:
附上我总结了三天经验后写出的源码:

import os
import time
from random import random
import requests
from bs4 import BeautifulSoup

path = './spider'
if os.path.exists(path):
    pass
else:
    os.mkdir(path)
url = 'https://www.mzitu.com'
main_url = []
name_dict = {}
main_num = 0

ref_url='https://www.mzitu.com'
header = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36 Edg/81.0.416.53',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
    'cache-control': 'max-age=0',
    'Referer': ref_url
    }


def get_main_url(url):  # 获取每个主页的24个图片链接
    res = requests.get(url,headers=header)
    soup = BeautifulSoup(res.text, 'html.parser')
    Temp_list = soup.find_all('li')[8:]
    for lab_list in Temp_list:
        div = BeautifulSoup(str(lab_list), 'html.parser')
        main_url.append(div.a.attrs['href'])  # 每个主页中图片详情列表链接
        name_dict[div.a.attrs['href']] = div.img.attrs['alt']
    print("获取当前页面所有链接成功!")


# <div class="main-image">  图片标签
# <div class="pagenavi">    页码标签
def get_image():
    global main_num,ref_url
    for now_url in main_url:
        main_num+=1
        ref_url=now_url
        if os.path.exists(path + '/' + name_dict[now_url]):
            pass
        else:
            os.mkdir(path + '/' + name_dict[now_url])
        response = requests.get(now_url, headers=header)
        soup = BeautifulSoup(response.text, 'html.parser')
        page_nums = soup.find('div', attrs={'class': "pagenavi"})
        page_num = BeautifulSoup(str(page_nums), 'html.parser').find_all('span')[-2].string
        for i in range(1, int(page_num) + 1):
            now_new_url = now_url + '/' + '{}'.format(i)
            new_response = requests.get(now_new_url, headers=header)
            Temp = BeautifulSoup(new_response.text, 'html.parser')
            image_url = Temp.find('div', attrs={'class': "main-image"}).img.attrs['src']
            image = requests.get(image_url,headers=header)
            name = str(image_url).split('/', 5)[-1]
            with open(path + '/' + name_dict[now_url] + '/' + name, 'wb') as f:
                f.write(image.content)
                print('正在爬取第'+str(main_num)+'个图库的第'+str(i)+'张图片,本页共'+page_num+'张照片。')
                time.sleep(random())

if __name__ == '__main__':
    start_time = time.time()
    get_main_url(url)
    get_image()
    end_time = time.time()
    print('耗时:' + str(end_time - start_time))

猜你喜欢

转载自blog.csdn.net/qq_44700693/article/details/105598212
今日推荐