分享

Python爬虫:做一个界面爬虫小软件爬取图片

 东西二王 2020-07-23

任务目标:

1. 抓取不同类型的图片

2. 编写一个GUI界面爬虫程序,打包成exe可执行文件

3. 遇到的难点

1. 分析如何抓取不同类型的图片

首先打开网站,可以看到有如下6个类型的菜单

Python爬虫:做一个界面爬虫小软件爬取图片

点击不同菜单,发现url显示如下

大胸妹:https://www./?cid=2

小翘臀:https://www./?cid=6

可以看到每个类型图片对应不同的cid值

所以要想抓取不同类型的图片,只需要构造下url

将cid进行参数化,然后传给url即可

具体代码在下面给出

2. 利用tkinter进行GUI编程

之前有写过一些tkinter编程的随笔

例如 利用python制作一个翻译工具

先来看一下这次设计的程序最终页面布局,

然后再具体讲下如何实现的,页面布局如下:

Python爬虫:做一个界面爬虫小软件爬取图片

1. 选择图片存储路径

抓取到的图片要保存到电脑本地,所以就想着最好能够自己选取本地任意一个文件夹作为存储路径

后来网上冲浪一番发现tkinter是可以实现这个功能的

可以通过tkinter.filedialog模块中的askdirectory()方法实现

下面是在网上找到的一段示例代码

#coding:UTF-8 from tkinter import * from tkinter.filedialog import askdirectory def select_path(): path_ = askdirectory() path.set(path_) root = Tk() path = StringVar() Label(root,text = '目标路径:').grid(row = 0, column = 0) Entry(root, textvariable = path).grid(row = 0, column = 1) Button(root, text = '路径选择', command = select_path).grid(row = 0, column = 2) root.mainloop()

效果如下

Python爬虫:做一个界面爬虫小软件爬取图片

具体到这个例子,

(1)定义一个文本框,用来存放(显示)选择的存储路径

self.input = tk.Entry(self.window, textvariable = self.path, widt

(2)定一个按钮,来触发选择本地路径功能

self.t_button = tk.Button(self.window, text='选择路径', relief=tk.RAISED, width=8, height=1, command=self.select_Path)


(3)定义一个函数,来实现选取路径功能

def select_Path(self):
    '''选取本地路径'''
    path_ = askdirectory()
    self.path.set(path_)

后续保存图片时,路径可以直接使用前面定义好的的self.input中的值

2. 选择分类


因为图片分为了6个类别,每个类别对应一个cid值,所以可以事先把cid抽象出来,当作参数传递

(1)定义一个下拉框,存储图片类型

self.menu['value'] = ('大胸妹','小翘臀', '黑丝袜', '美腿控', '有颜值','大杂烩')

(2)根据所选类型不同,返回不同的cid值

def get_cid(self):
    category = {
        'DX':  2,
        'XQT': 6,
        'HSW': 7,
        'MTK': 3,
        'YYZ': 4,
        'DZH': 5
    }
    cid = None
    if self.menu.get() == '大胸妹':
        cid = category['DX']
    elif self.menu.get() == '小翘臀':
        cid = category['XQT']
    elif self.menu.get() == '黑丝袜':
        cid = category['HSW']
    elif self.menu.get() == '美腿控':
        cid = category['MTK']
    elif self.menu.get() == '有颜值':
        cid = category['YYZ']
    elif self.menu.get() == '大杂烩':
        cid = category['DZH']
    return cid


3. 填写爬取页数

self.page = tk.Entry(self.window, width=5) # 定义一个文本框,存放爬取页数

后面把这个文本框中的值传给url即可


整体效果如下

Python爬虫:做一个界面爬虫小软件爬取图片

最后附上完整代码:

import requests
from requests.exceptions import RequestException
import tkinter as tk
from tkinter import ttk
from bs4 import BeautifulSoup
import bs4
from tkinter import *
from tkinter.filedialog import askdirectory
import os

class DB():
    def __init__(self):
        self.window = tk.Tk()  #创建window窗口
        self.window.title('Crawler Pics')  # 定义窗口名称
        # self.window.resizable(0,0)  # 禁止调整窗口大小
        self.menu = ttk.Combobox(self.window,width=6)
        self.path = StringVar()
        self.lab1 = tk.Label(self.window, text = '目标路径:')
        self.lab2 = tk.Label(self.window, text='选择分类:')
        self.lab3 = tk.Label(self.window, text='爬取页数:')
        self.page = tk.Entry(self.window, width=5)  # 定义一个文本框,存放爬取页数
        self.input = tk.Entry(self.window, textvariable = self.path, width=80)  # 创建一个输入框,显示图片存放路径
        self.info = tk.Text(self.window, height=20)   # 创建一个文本展示框,并设置尺寸

        self.menu['value'] = ('大胸妹','小翘臀', '黑丝袜', '美腿控', '有颜值','大杂烩')
        self.menu.current(0)

        # 添加一个按钮,用于选择图片保存路径
        self.t_button = tk.Button(self.window, text='选择路径', relief=tk.RAISED, width=8, height=1, command=self.select_Path)
        # 添加一个按钮,用于触发爬取功能
        self.t_button1 = tk.Button(self.window, text='爬取', relief=tk.RAISED, width=8, height=1,command=self.download)
        # 添加一个按钮,用于触发清空输出框功能
        self.c_button2 = tk.Button(self.window, text='清空输出', relief=tk.RAISED,width=8, height=1, command=self.cle)

    def gui_arrang(self):
        '''完成页面元素布局,设置各部件的位置'''
        self.lab1.grid(row=0,column=0)
        self.lab2.grid(row=1, column=0)
        self.menu.grid(row=1, column=1,sticky=W)
        self.lab3.grid(row=2, column=0,padx=5,pady=5,sticky=tk.W)
        self.page.grid(row=2, column=1,sticky=W)
        self.input.grid(row=0,column=1)
        self.info.grid(row=3,rowspan=5,column=0,columnspan=3,padx=15,pady=15)
        self.t_button.grid(row=0,column=2,padx=5,pady=5,sticky=tk.W)
        self.t_button1.grid(row=1,column=2)
        self.c_button2.grid(row=0,column=3,padx=5,pady=5,sticky=tk.W)

    def get_cid(self):
        '''选择爬取图片类型'''
        category = {
            'DX': 2,
            'XQT': 6,
            'HSW': 7,
            'MTK': 3,
            'YYZ': 4,
            'DZH': 5
        }
        cid = None
        if self.menu.get() == '大胸妹':
            cid = category['DX']
        elif self.menu.get() == '小翘臀':
            cid = category['XQT']
        elif self.menu.get() == '黑丝袜':
            cid = category['HSW']
        elif self.menu.get() == '美腿控':
            cid = category['MTK']
        elif self.menu.get() == '有颜值':
            cid = category['YYZ']
        elif self.menu.get() == '大杂烩':
            cid = category['DZH']
        return cid

    def select_Path(self):
        '''选取本地路径'''
        path_ = askdirectory()
        self.path.set(path_)

    def get_html(self, 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(self, 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(self, url):
        '''请求图片url,返回二进制内容'''
        print('正在下载', url)
        self.info.insert('end','正在下载:' url '\n')
        try:
            r = requests.get(url)
            if r.status_code == 200:
                return r.content
            return None
        except RequestException:
            return None

    def download(self):
        base_url = 'https://www./?'
        for i in range(1, int(self.page.get()) 1):
            url = base_url   'cid='   str(self.get_cid())   '&'   'page='   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 = self.get_html(url)
            # print(html)
            dictdata = self.parse_html(html, list_data)


            root_dir = self.input.get()
            case_list = ['大胸妹', '小翘臀', '黑丝袜', '美腿控', '有颜值', '大杂烩']
            for t in case_list:
                if not os.path.exists(root_dir   '/pics'):
                    os.makedirs(root_dir   '/pics')
                if not os.path.exists(root_dir   '/pics/'   str(t)):
                    os.makedirs(root_dir   '/pics/'   str(t))


            if self.menu.get() == '大胸妹':
                save_path = root_dir   '/pics/'   '大胸妹'
                for t in dictdata.items():
                    try:
                        # file_path = '{0}/{1}.{2}'.format(save_path, t[1], 'jpg')
                        file_path = save_path   '/'   t[0]   'q'   '.jpg'
                        if not os.path.exists(file_path):  # 判断是否存在文件,不存在则爬取
                            with open(file_path, 'wb') as f:
                                f.write(self.get_image_content(t[1]))
                                f.close()
                                print('文件保存成功')
                    except FileNotFoundError:
                        continue

            elif self.menu.get() == '小翘臀':
                save_path = root_dir   '/pics/'   '小翘臀'
                for t in dictdata.items():
                    try:
                        # file_path = '{0}/{1}.{2}'.format(save_path, t[1], 'jpg')
                        file_path = save_path   '/'   t[0]   'q'   '.jpg'
                        if not os.path.exists(file_path):  # 判断是否存在文件,不存在则爬取
                            with open(file_path, 'wb') as f:
                                f.write(self.get_image_content(t[1]))
                                f.close()
                                print('文件保存成功')
                    except FileNotFoundError:
                        continue

            elif self.menu.get() == '黑丝袜':
                save_path = root_dir   '/pics/'   '黑丝袜'
                for t in dictdata.items():
                    try:
                        # file_path = '{0}/{1}.{2}'.format(save_path, t[1], 'jpg')
                        file_path = save_path   '/'   t[0]   'q'   '.jpg'
                        if not os.path.exists(file_path):  # 判断是否存在文件,不存在则爬取
                            with open(file_path, 'wb') as f:
                                f.write(self.get_image_content(t[1]))
                                f.close()
                                print('文件保存成功')
                    except FileNotFoundError:
                        continue

            elif self.menu.get() == '美腿控':
                save_path = root_dir   '/pics/'   '美腿控'
                for t in dictdata.items():
                    try:
                        # file_path = '{0}/{1}.{2}'.format(save_path, t[1], 'jpg')
                        file_path = save_path   '/'   t[0]   'q'   '.jpg'
                        if not os.path.exists(file_path):  # 判断是否存在文件,不存在则爬取
                            with open(file_path, 'wb') as f:
                                f.write(self.get_image_content(t[1]))
                                f.close()
                                print('文件保存成功')
                    except FileNotFoundError:
                        continue

            elif self.menu.get() == '有颜值':
                save_path = root_dir   '/pics/'   '有颜值'
                for t in dictdata.items():
                    try:
                        # file_path = '{0}/{1}.{2}'.format(save_path, t[1], 'jpg')
                        file_path = save_path   '/'   t[0]   'q'   '.jpg'
                        if not os.path.exists(file_path):  # 判断是否存在文件,不存在则爬取
                            with open(file_path, 'wb') as f:
                                f.write(self.get_image_content(t[1]))
                                f.close()
                                print('文件保存成功')
                    except OSError:
                        continue

            elif self.menu.get() == '大杂烩':
                save_path = root_dir   '/pics/'   '大杂烩'
                for t in dictdata.items():
                    try:
                        # file_path = '{0}/{1}.{2}'.format(save_path, t[1], 'jpg')
                        file_path = save_path   '/'   t[0]   'q'   '.jpg'
                        if not os.path.exists(file_path):  # 判断是否存在文件,不存在则爬取
                            with open(file_path, 'wb') as f:
                                f.write(self.get_image_content(t[1]))
                                f.close()
                                print('文件保存成功')
                    except FileNotFoundError:
                        continue

    def cle(self):
        '''定义一个函数,用于清空输出框的内容'''
        self.info.delete(1.0,'end')  # 从第一行清除到最后一行


def main():
    t = DB()
    t.gui_arrang()
    tk.mainloop()

if __name__ == '__main__':
    main()

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约