任务目标: 1. 抓取不同类型的图片 2. 编写一个GUI界面爬虫程序,打包成exe可执行文件 3. 遇到的难点 1. 分析如何抓取不同类型的图片 首先打开网站,可以看到有如下6个类型的菜单 点击不同菜单,发现url显示如下 大胸妹:https://www./?cid=2 小翘臀:https://www./?cid=6 可以看到每个类型图片对应不同的cid值 所以要想抓取不同类型的图片,只需要构造下url 将cid进行参数化,然后传给url即可 具体代码在下面给出 2. 利用tkinter进行GUI编程 之前有写过一些tkinter编程的随笔 例如 利用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()
效果如下 具体到这个例子, (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即可 整体效果如下
最后附上完整代码:
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()
|