有小半个月没有发博客了,因为一直在研究python的GUI,买了一本书学习了一些基础,用我所学做了我的第一款GUI——微博图片爬取工具。本软件源代码已经放在了博客中,另外软件已经打包好上传到网盘中以供下载学习。

一.准备工作

本次要用到以下依赖库:re json os random tkinter threading requests PIL 其中后两个需要安装后使用

二.预览

1.启动

2.运行中

3.结果

这里只将拿一张图片作为展示。

三.设计流程

设计流程分为总体设计和详细设计,这里我会使用viso画出几个流程图,用以展示我的思路,其中详细设计部分,我列举了两个函数实现的具体流程。

1.总体设计

此图为整个系统的整体流程也是本GUI软件的使用过程。

2.详细设计

在此列举两个函数一个是搜索按钮触发的wb_search函数,一个是开始爬取按钮触发的wb_pics_parse函数。

2.1wb_search函数

2.2wb_pics_parse函数

四.源代码

import json

import random

import re

import os

from tkinter import *

from tkinter import messagebox

from tkinter import ttk

import requests

import threading

from PIL import Image,ImageTk

"""

1.07使用check button 实现下载完打开文件夹操作,注册了enter、esc热键,优化了一些体验

1.08 1.更新了关键字、磁盘、用户判断逻辑

2.将之前的线程池改为多线程来执行下载操作

1.13说明:如果在下载过程变慢,可能是软件正在解析图片地址或者就是您的网络不行

"""

class WeiBo_pics_Spider(object):

def __init__(self,start_url):

self.start_url=start_url

#解析出图片地址

def get_pics_url(self):

i = 1

global a_flag

a_flag = True

while True:

url = self.start_url + '&page={}'.format(i)

headers = {'User-Agent': get_ua()}

r = requests.get(url, headers=headers)

_json = json.loads(r.text)

items = _json["data"]["cards"]

flag = _json['ok']

if flag == 1 and a_flag: # 爬取数据标志+一个手动控制标志

for v in items:

picslist = v.get('mblog')

if picslist is not None:

img_urls = picslist.get('pics')

if img_urls != None:

for img_url_ in img_urls:

img_url = img_url_['large']['url']

yield img_url

else:

#1.06页数显示出现问题

t1.insert(END, f'***在第{i}页终止***\n')

t1.see(END)

t1.update()

if r1_var.get() == 1:

big_dir=disk+':/WeiBo_Pics'

os.startfile(big_dir)

break

i += 1

#下载图片

def download_pics(self,url,filename):

headers={'User-Agent': get_ua()}

r = requests.get(url, headers=headers)

big_dir=disk+':/WeiBo_Pics'

aim_path=big_dir+'/'+user_name_selected

try:

os.makedirs(aim_path)

except:

pass

with open(aim_path + '\\' + filename, 'wb')as f:

f.write(r.content)

# 保证焦点始终在最下

t1.see(END)

# 下载完一张刷新一次 防止界面卡死崩溃

t1.insert(END, f'{filename}\n')

window.update()

def get_ua():

first_num = random.randint(55, 62)

third_num = random.randint(0, 3200)

fourth_num = random.randint(0, 140)

os_type = [

'(Windows NT 6.1; WOW64)', '(Windows NT 10.0; WOW64)', '(X11; Linux x86_64)',

'(Macintosh; Intel Mac OS X 10_12_6)'

]

chrome_version = 'Chrome/{}.0.{}.{}'.format(first_num, third_num, fourth_num)

ua = ' '.join(['Mozilla/5.0', random.choice(os_type), 'AppleWebKit/537.36',

'(KHTML, like Gecko)', chrome_version, 'Safari/537.36']

)

return ua

def wb_search():

#先清空lsibox1内容,便于新内容显示

listb1.delete(0,END)

url1='https://m.weibo.cn/api/container/getIndex?containerid=100103type%3D3%26q%3D{}%26t%3D0'

headers={'User-Agent':get_ua()}

key_word = e1.get()

global user_id_list

user_id_list=list()

if len(key_word)!=0:

#若用户输入了user_id,则去获取screen_name

if re.match('\d{10}',key_word):

user_id_list.append(key_word)

url2 = f'https://m.weibo.cn/api/container/getIndex?uid={key_word}&containerid=100505{key_word}'

r1 = requests.get(url2, headers=headers)

_data = json.loads(r1.text)

screen_name = _data['data']['userInfo'].get('screen_name')

l3.place(x=120, y=42)

l3_var.set(f'搜索成功')

l3['background'] = 'green'

listb1.insert(END, screen_name)

#否则根据关键字去搜索用户信息,显示在listbox中

else:

aim_url=url1.format(key_word)

r=requests.get(aim_url,headers=headers)

_json=json.loads(r.text)

try:

#若出现了IndexError则表明没有检索到用户信息

users=_json['data']['cards'][1].get('card_group')

relevant_num=len(users)

l3.place(x=105, y=42)

l3_var.set(f'搜索到了 {relevant_num} 个用户')

l3['background']='green'

for user_ in users:

user_info=user_.get('user')

user_name=user_info.get('screen_name')

id = user_info.get('id')

"""

1.02的一种思路,使用一个列表存储screen_name和uid,两者用;(自定义字符,但应避免较少冲突)

当获取Uid时,直接切割字符串,取Listbox所选项索引,按索引在列表表值(uid)

#使用字符串拼接 格式:screen_name+';'+str(id)

# user_data = user_name + ';' + str(id)

"""

user_id_list.append(id)

listb1.insert(END,user_name)

except IndexError:#如果没有检索到用户,就会报列表索引错误

messagebox.showinfo(title='提示', message='没有检索到相关用户,请更换关键字或使用用户id搜索!')

l3.place(x=85, y=42)

l3_var.set(f'请更换关键字或用户id搜索!')

l3['background']='yellow'

#没有检索到用户的话,提示之后,e1获得焦点之后,清除用户之前输入

e1.bind('WM_TAKE_FOCUS', e1_clear())

else:#处理没有输入关键字

messagebox.showinfo(title='info',message='请输入关键字!')

l3.place(x=110, y=42)

l3_var.set(f'请输入关键字!')

l3['background'] = 'red'

def wb_pics_parse():

key_word=e1.get()

select_path=c1.get()

#1.先判断关键字是否输入

if len(key_word)!=0:

#2.再判断是否选择了磁盘

if len(select_path)==1:

#3.判断所选路径是否存在

if not os.path.exists(select_path):

#4.判断是否在列表框选择了用户名

try:

# 直接获取选中项目

"""1.05获取Listbox user_name_selected真费劲"""

global user_name_selected

user_name_selected=listb1.get(listb1.curselection())

user_name_index = listb1.curselection()[0]

user_id = user_id_list[user_name_index]

container_id = '107603' + str(user_id)

start_url = f'https://m.weibo.cn/api/container/getIndex?containerid={container_id}'

spider = WeiBo_pics_Spider(start_url)

t1.config(state='normal') # 将Text开启,置为可读可写状态

l3.place(x=120, y=42)

l3_var.set(f'正在运行......')

l3['background'] = 'green'

for pic_url in spider.get_pics_url():

filename = pic_url.split('/')[-1]

# 字符串切割,切割出前10个字符串

filename = filename[10:]

thread_it(spider.download_pics,pic_url,filename)

#搜索后,但是没选择用户,会报TclError错误,此except就用来捕获这个异常

except TclError:

messagebox.showwarning(title='警告', message='请选择一个用户!')

l3.place(x=105, y=42)

l3_var.set(f'请选择一个用户!')

l3['background'] = 'red'

#获取当前选中项目(使用索引)

else:

messagebox.showwarning(title='警告',message='请检查路径!')

l3.place(x=80, y=42)

l3_var.set(f'请检查路径!')

l3['background'] = 'red'

else:

messagebox.showwarning(title='警告', message='您未选择磁盘!')

l3.place(x=85, y=42)

l3_var.set(f'请检查是否选择了磁盘!')

l3['background'] = 'red'

else:

messagebox.showwarning(title='警告', message='请输入关键字!')

l3.place(x=110, y=42)

l3_var.set(f'请输入关键字!')

l3['background'] = 'red'

def open_disk():

disk=c1.get()

big_dir=disk+':/WeiBo_Pics'

if len(disk)==1:

try:

if not os.path.exists(big_dir):

os.mkdir(big_dir)

os.startfile(big_dir)

except:

messagebox.showwarning(title='警告',message='选中的磁盘不存在!')

l3.place(x=110, y=42)

l3_var.set(f'选中的磁盘不存在!')

l3['background'] = 'red'

else:

messagebox.showwarning(title='警告', message='您未选中磁盘!')

l3.place(x=115, y=42)

l3_var.set(f'您未选中磁盘!')

l3['background'] = 'red'

def window_quit():

ret=messagebox.askyesno(title='提示',message='是否要退出?')

if ret==True:

window.destroy()

window.quit()

def e1_clear():

e1.delete(0,END)

def print_path(event):

#要使用完整的路径

global disk

disk = c1.get()

disk_path=c1.get()+':/'

if len(disk)==1:

if os.path.exists(disk_path):

messagebox.showinfo(title='提示',message=f'文件将存储到:{disk}:/WeiBo_Pics目录下')

else:

messagebox.showerror(title='错误',message='选定磁盘不存在!')

l3.place(x=100, y=42)

l3_var.set(f'选中的磁盘不存在!')

l3['background'] = 'red'

else:

messagebox.showwarning(title='警告', message='请先选定磁盘!')

l3.place(x=120, y=42)

l3_var.set(f'请先选定磁盘!')

l3['background'] = 'red'

def switch():

if r1_var.get()==0:

r1_var.set(1)

else:

r1_var.set(0)

def escape(event):

window_quit()

def enter(event):

wb_search()

'''解决程序卡死的重要方法,避免子线程和Ui线程在同一个线程'''

def thread_it(func, *args):

'''将函数打包进线程'''

# 创建

t = threading.Thread(target=func, args=args)

# 守护 !!!

t.setDaemon(True)

# 启动

t.start()

# 阻塞--卡死界面!

# t.join()

window=Tk()

width=310

height=395

screenWidth = window.winfo_screenwidth() # 获取显示区域的宽度

screenHeight = window.winfo_screenheight() # 获取显示区域的高度

left = (screenWidth - width) / 2

top = (screenHeight - height) / 2

window.geometry("%dx%d+%d+%d" % (width, height, left, top))

window.resizable(0,0)

window.title('微博图片采集工具-v1.08')

#设置图标

ico_path=r'./rely/icon.ico'

window.iconbitmap(ico_path)

#插入图片到Label中

photo = Image.open("./rely/w_b.png") # 括号里为需要显示在图形化界面里的图片

photo = photo.resize((150, 40)) # 规定图片大小

img0 = ImageTk.PhotoImage(photo)

l1=ttk.Label(window,imag=img0,justify='center')

l1.pack()

l3_var=StringVar()

l3=ttk.Label(window,background='yellow',textvar=l3_var)

l3.place(x=120,y=42)

l3_var.set('还没搜索')

l1=ttk.Label(window,text='关键字或\n用户id:')

l1.place(x=13,y=60)

e1=ttk.Entry(window,justify='center')

e1.place(x=80,y=65)

l4=ttk.Label(window,text='磁盘:')

l4.place(x=13,y=100)

disk_list=['C','D','E','F','G','H','I']

c1=ttk.Combobox(window,justify='center',state='readonly',width=17,value=disk_list)

#Combobox默认选中索引为0的项目 即 C盘

c1.bind('<>', print_path)

c1.place(x=80,y=100)

r1_var=IntVar()

r1_var.set(1)#默认选中为1

check1=Checkbutton(window,text='下载完\n打开文件夹',command=switch)

check1.place(x=223,y=90)

b1=ttk.Button(window,text='搜索',command=lambda:thread_it(wb_search),width=7)

b1.place(x=230,y=63)

l5=ttk.Label(window,text='用户列表:')

l5.place(x=13,y=150)

lb1_var=StringVar()

listb1=Listbox(window,justify='center',listvariable=lb1_var,width=20,height=4)

listb1.place(x=80,y=135)

b2=ttk.Button(window,text='开始爬取',command=lambda :thread_it(wb_pics_parse,),width=7)

b2.place(x=230,y=160)

l6=ttk.Label(window,text='状态:')

l6.place(x=13,y=280)

t1=Text(window,width=23,font=('times new roman',10),state='disable')

t1.place(x=80,y=230,height=140)

b3=ttk.Button(window,text=' 打开\n文件夹',width=7,command=open_disk)

b3.place(x=230,y=230)

b3=ttk.Button(window,text='退出',width=7,command=window_quit)

b3.place(x=230,y=315)

f1 = ttk.LabelFrame(window)

f1.place(x=65,y=350)

l6=ttk.Label(f1,text='敬告:本软件仅供学习交流使用!',foreground='red')

l6.pack(anchor="w",fill=X)

#绑定esc键---退出

window.bind('',escape)

#使用return键给输入框Entry绑定enter事件---search搜索

e1.bind('',enter)

#加入主窗口销毁事件

window.protocol('WM_DELETE_WINDOW',window_quit)

window.mainloop()

五.总结说明

本软件仅供学习交流使用!图源水印,在此仅作举例!

由于这是第一次做GUI,因此遇到了一些问题,在此列举一下:

1.窗口布局问题(GUI基础)

2.主窗口执行一个比较耗时操作导致卡死、崩溃(线程问题)。

3.主窗口关闭后,后台线程还在运行(线程问题)。

以上问题已经全部解决,软件切实可用。

另外,本软件有四大亮点:

1.使用线程下载图片

2.智能标签提醒

3.输入关键字直接敲回车能够完成搜索

4.Esc快速退出软件

软件打包好了放在了蓝奏云https://wws.lanzous.com/iPSpzkchj5i

以上就是python制作微博图片爬取工具的详细内容,更多关于python 微博图片爬取的资料请关注脚本之家其它相关文章!

python写图片爬取软件_python制作微博图片爬取工具相关推荐

  1. python写安卓游戏辅助软件_python微信跳一跳辅助软件

    python微信跳一跳辅助软件是一款跳一跳小游戏的刷分辅助工具应用,用户在微信玩跳一跳游戏的时候使用软件可以随意的修改其中的成绩分数,按照你自己的意愿进行相关的改变,更好的帮助你达成游戏的最高峰,喜欢 ...

  2. python软件界面-用Python写一个语音播放软件

    原标题:用Python写一个语音播放软件 单位经常使用广播进行临时事项的通知(将文字转换为语音然后通过功放广播),但是市面上多数语音播放软件都是收费的,要么发音失真,要么不够稳定--经常出现莫名其妙的 ...

  3. python编写一个软件-python写一个随机点名软件的实例

    最近有个随机点名软件的需求,故写了一个,上代码:github地址 # -*- coding: utf-8 -*- # @Time : 18-12-31 下午4:21 # @Author : Felix ...

  4. python写软件实例-python写一个随机点名软件的实例

    最近有个随机点名软件的需求,故写了一个,上代码:github地址 # -*- coding: utf-8 -*- # @Time : 18-12-31 下午4:21 # @Author : Felix ...

  5. 只需三步!使用3DCG软件Blender制作时尚图片

    你好,我是bpm,主要从事开发工作!这次我想介绍一下利用免费3DCG软件Blender制作时尚图片的方法. Blender的优点 先介绍一下,在接触了Blender一段时间后,为什么我会觉得用它来处理 ...

  6. gimp怎么更改已有文字_用GIMP软件怎么制作文字图片及其倒影?

    很多时候我们会想要制作文字图片,这样我们就能够用制作好的文字图片,把它当成是水印应用到其他的图片上,下面小编为大家带来用GIMP软件制作文字图片及其倒影的方法步骤,希望对大家有帮助? 制作文字图片方法 ...

  7. gimp怎么更改已有文字_gimp怎么更改已有文字_用GIMP软件怎么制作文字图片及其倒影?...

    很多时候我们会想要制作文字图片,这样我们就能够用制作好的文字图片,把它当成是水印应用到其他的图片上,下面小编为大家带来用GIMP软件制作文字图片及其倒影的方法步骤,希望对大家有帮助? 制作文字图片方法 ...

  8. python socket能做什么_用python写一个聊天小程序!和女朋友的专属聊天工具!

    原标题:用python写一个聊天小程序!和女朋友的专属聊天工具! 1.UDP简介 Internet协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP).UDP为应用程序提供了无需建立就可 ...

  9. python 循环 覆盖之前print内容_Python爬虫第二战---爬取500px图片

    前言: 如今的高速网络极大促进了信息的展示方式,高清图片,视频等成就了我们的视听盛宴.但是,我们获取到的图片或者视频可能是被压缩过的,所以总体上还是有点小瑕疵,今天呢,我给大家带来一篇使用Python ...

最新文章

  1. 求表达式1-1/2+1/3-1/4+1/5-1/6+1/7-...+1/n的值
  2. 《2021全球脑科学发展报告》发布
  3. linux下搭建vnc服务器,linux下搭建Vncserver
  4. python多个装饰器执行顺序_Python面试题之多个装饰器执行顺序
  5. 使用c++查看linux服务器某个进程正在使用的内存_Linux 系统管理
  6. 让beanshell和bashshell一起工作
  7. python基础08
  8. 动态规划算法实验报告_动态规划与中心扩展算法
  9. 计算机网络:数据链路层(2):MAC协议
  10. 交互式绘图软件源码开发,简单好用功能强大的绘图工具
  11. 进qq空间显示服务器失败,QQ空间找不到服务器-进空间找不到服务器的解决办法...
  12. MinIO分布式文件服务器搭建与入门
  13. BlackBerry上网初体验
  14. 指针、空指针、野指针
  15. Arnold Denoise流程
  16. java 字数_java 字数统计
  17. 掌优刷脸支付刷出移动支付新热度
  18. ARM-9 4412板、linux-3.14内核、usb转串口pl2303驱动的移植相关问题
  19. 5G C-V2X战役一触即发,广和通率先“上车”零碳商用快班车
  20. LimeSDR入门之软硬件安装

热门文章

  1. FastJson解析处理内部类问题
  2. Python爬虫抓包工具使用
  3. 破解Navicat并登录MySQL方法
  4. 编写程序描述兔子和青蛙
  5. android 开发 字体,Android开发使用自定义字体的实现方法
  6. Linux基础.umask,权限影响,文件类型,/根目录文件,环境变量,alias别名,man手册
  7. android 下载模拟器镜像文件遇到的问题
  8. 杰理-手表-AC701-watch-秒针匀速表盘
  9. uniapp 九宫格抽奖功能
  10. 树莓派原生系统安装ROS(含网络代理,ROS编译安装以及ROS小车制作过程)