Python基础入门

     1.基本内容
         1.1环境安装
         1.2 注释
         1.3变量
         1.4常见五种数据类型
         1.5条件控制语句if
         1.6 逻辑运算
         1.7集合使用
         1.8字典和元祖
         1. 9 for循环和while循环
         1.92 字符串相关
         1.93 对象和继承
         1.94 异常处理
         1.95 支持http访问服务
         1.96 配置文件cfg
         1.97 全局变量
         1.98 @classmethod
         1.99 除法取整
         1.991 多线程
         1.992 自定义函数
         1.993 window中直接进入cmd指定目录方式
         1.994 枚举enumerate函数
     2.内置函数
         2.1 set集合
         2.2 正则表达式
                  2.2.1 查询页面中所有的hoverURL路径信息
         2.3 内容输入函数input
         2.4 范围函数range
         2.5 list集合
     3.模块以及模块引入
         3.1 os模块
         3.2 datetime模块
         3.3 tinker模块
         3.4 BeautifulSoup模块
         3.5 time模块
         3.6 request模块之请求重试
         3.7 excel操作openpyxl模块
     4.pycharm设置与快捷键
         4.1 去除PE8格式校验
         4.2 mian主函数快捷键
         4.3 命名大小写警告问题
         4.4 pycharm安装三方库
         4.5 pycharm控制台乱码处理
         4.6 pycharm导入关联svn后一直显示authentication required
         4.7 pycharm变更项目的Python版本
         4.8 pycharm复制浏览器header内容
         4.9 pycharm复制内容自动换行报错
     5.Python打包与部署
         5.1 Python项目单文件打包成exe
         5.2Python项目部署到Linux(ubantu)
     6.flask框架
         6.1基础入门:项目创建与启动
         6.2 get请求参数获取
         6.3 post请求体post参数获取
         6.3 post请求体表单参数获取
         6.3 post请求体表单参数获取
         6.5 指定响应参数
         6.6 post请求文件上传
         6.7 Blueprint分层
         6.7 Blueprint分层后配置设置与获取
     7.mysql数据库
         7.1查询
         7.2新增
         7.3修改
         7.4删除
         7.5工具类封装
     8.常见问题
         8.1 getImgUrlList() takes 1 positional argument but 2 were given
         8.2 Rangeerror:valid array length
     9.浏览器F12常用功能说明

1.基本内容

1.1环境安装

    Python解释器安装,版本3.10.x
    window下载地址:https://www.python.org/downloads/windows/
    官方文档:https://docs.python.org/zh-cn/3/index.html
下载安装完成之后配置环境变量,配置方式如下:

  1. 打开“此电脑”或“计算机”属性,点击“高级系统设置”;

  2. 在弹出的“系统属性”对话框中,点击“环境变量”按钮;

  3. 在“系统变量”中找到“Path”变量,点击“编辑”按钮;

  4. 在“编辑环境变量”对话框中,点击“新建”按钮,输入Python安装路径

在这里插入图片描述

    python三方库:https://pypi.org/
    开发工具:pycharm
    下载地址:https://www.jetbrains.com/pycharm/
下载使用社区版即可.
    项目创建步骤:
在这里插入图片描述
项目创建成功之后页面如下:在这里插入图片描述

1.2 注释

    关于三个引号实现的换行
在这里插入图片描述
    也可以用作多行注释(单行注释可以直接用#)
在这里插入图片描述

1.3变量

变量赋值

    定义变量,直接变量名=变量值,变量名前面不用定义数据类型
在这里插入图片描述
    或是使用str函数进行转化成字符串就支持使用加号拼接了!

变量名命名规则

全部小写,不同单词之间用下划线隔开;另一种是驼峰式,推荐前者
第三方库使用说明
import+三方库名
三方库名.方法
方法的具体使用说明可以通过编辑器点击去看实现

import math
num1 = math.ceil(5.28)
num2 = math.ceil(5.68)
print('5.28向上取整之后值:',num1) # 结果:6
print('5.68向上取整之后值:',num2) # 结果:6

1.4常见五种数据类型

在这里插入图片描述
type函数可以获取数据类型,每种数据类型相当于一种函数,可以实现数据类型转化,可以参考上面的例子!

1.5条件控制语句if

格式:

if 条件: 	
	执行语句 
else: 	
	执行语句

示例:

# 条件控制语句
if 3 > 2:
    print("3 > 2成立")  # 输出:3 > 2成立
print("华丽的分隔线===========不使用else==========================")
if 3 > 2:
    print("3 > 2成立")
else:
    print("3 > 2不成立")  # 输出:3 > 2成立
print("华丽的分隔线=========使用else============================")
if 3 > 2:
    print("3 > 2成立")
    print("3 > 2成立不是理所应当?")
    """输出:3 > 2成立
        3 > 2成立不是理所应当?"""
#print("3 > 2成立") 语法错误
else:
    print("3 > 2不成立")
    print("3 > 2不成立")

多条件判断elif用法:

input_score=input("请输入分数:")
if int(input_score) < 60:
    print("不及格")
elif 60< int(input_score) < 85:
    print("良好")
else:
    print("优秀")

1.6 逻辑运算

支持的三种逻辑运算符:and or not

not相当于是取反

print(not(20 >6)) 打印结果:Fale

1.7集合使用

# 集合
person_list = []
person_list.append("小红")
person_list.append("小李")
print("添加元素之后集合:",person_list)
person_list.remove("小李")
print("删除元素之后集合:",person_list)
print("集合长度:",len(person_list))
person_list.append(1)
print("集合支持不同数据类型:",person_list)
# 集合常用方法最大值 最小值 排序
num_list=[5,8,2]
print("集合中最大值:",max(num_list))
print("集合中最小值:",min(num_list))
print("集合排序(默认升序):",sorted(num_list))
print("集合排序,倒序排列:",sorted(num_list,reverse=True))

打印结果:

添加元素之后集合: ['小红', '小李']
删除元素之后集合: ['小红']
集合长度: 1
集合支持不同数据类型: ['小红', 1]
集合中最大值: 8
集合中最小值: 2
集合排序(默认升序): [2, 5, 8]
集合排序,倒序排列: [8, 5, 2]

1.8字典和元祖

# 字典,相当于java中对象
person = {"name":"小李","age":20}
print("根据key(name)获取value",person["name"])
print("判断key是否存在:","name" in person)
del person["name"]
print("删除key(name)之后字典:",person)
# 元组,元组中元素不可变,不支持添加或删除
student = ("小李","小王")

打印结果:

根据key(name)获取value 小李
判断key是否存在: True
删除key(name)之后字典: {'age': 20}

1. 9 for循环和while循环

格式:

for 元素变量名 in 集合:
	执行语句

示例:

num_list=[2,5,6,7]
for num in num_list:
    print("num值:",num)

打印结果:

num值: 2
num值: 5
num值: 6
num值: 7

while循环

格式:

while 条件:
	执行语句

示例:

i =1
while i < 5:
    i=i+1
    print("i值:",i)

打印结果:

i值: 2
i值: 3
i值: 4
i值: 5

1.91 自定义函数

格式:

def 函数名(形参1,形参2):
	执行代码逻辑
	return 返回结果
# 函数调用
函数名(实参1,实参2)

1.92 字符串相关

三种常用的字符串格式化

# 格式化字符串
name = "王五"
# 方式一:使用%
print("你好,%s" % name)
# 方式2:使用format
print("你好,{}".format(name))
# 使用f
print(f"你好,{name}")
# 补充:字符串拼接中双引嵌套单引方式
# mysql中新增需要参数化处理,如果参数中含有特殊字符,会导致解析异常,所以需要进行单引号转化
  userId = 2
  type = 3
  fileName = "202311142159.pdf"
  # 错误拼接:实参中带有.,会导致解析异常,插入语句执行失败
 sql = "insert into tool_convert_record (user_id,type,file_name) values (%s,%s,%s)" % (userId, type, fileName)
 # 正确方式是使用转义处理双引转单引,两种方式都可以处理
 sql = "insert into tool_convert_record (user_id,type,file_name) values (%d,%d,\"%s\")" % (userId, type, fileName)
 sql = f"insert into tool_convert_record (user_id,type,\"file_name\") values ({userId},{type},{fileName})"

判断字符串是否存在于另一字符串中

使用 in 或not in ,判断方式如下:

使用in:

str1 ="hello world!"
if "wo" in str1:
     print("wo存在于str1")
else:
     print("wo不存在于str1")

使用not in:

str1 ="hello world!"
if "wo" not in str1:
     print("wo不存在于str1")
else:
     print("wo存在于str1")

字符串截取

字符串[截取开始索引:截取结束索引:步长]
步长一般为1

示例:

a = "background-image: url(https://img3.huamaocdn.com/upload/bizhi/images/280h/2023/02/202302241037414937.jpg);"
b = a[2:4:1]  # 输出内容:ck

注意:截取内容不包含开始索引内容,包含结束索引内容

字符串中获取某个字符的位置:

字符串.find(查找字符串)

示例:

a = "background-image: url(https://img3.huamaocdn.com/upload/bizhi/images/280h/2023/02/202302241037414937.jpg);"
b = a.find("(")

从最后开始查找:

字符串.rfind(查找字符串)
 img = 'https://img0.huamaocdn.com/upload/bizhi/images/280h/2022/08/202208081809353823.jpg'
    a = img.rfind("/")
    print(a)  # 输出:59

获取指定字符串所在索引

查询第三个l出现的索引

  s = "hello world look"
    count = 0
    index = s.find("l")
    print("首次:{index}",index)
    while index != -1:
        index = s.find("l",index+1)
        print("index:",index)
        count = count+1
        print("count:",count)
        if count == 2:
            print(f"第三个l索引位置:{index}")  # 打印9
            break

字符串转码:

浏览器地址栏经常看到汉字会转码成带有百分号的形式.

from urllib import parse
print(parse.quote("中国"))  // 打印内容:%E4%B8%AD%E5%9B%BD

字符串与整数相互转换:

numStr = "123"
    numInt= int(numStr)
    print("numInt:",numInt)
    print("numInt数据类型:",type(numInt))
    numStr=str(numInt)
    print("numStr:", numStr)
    print("numStr数据类型:", type(numStr))

输出内容:

numInt: 123
numInt数据类型: <class 'int'>
numStr: 123
numStr数据类型: <class 'str'>

字符串去除空格和换行符

字符串.strip()

1.93 对象和继承

定义类并创建对象

class Person:
    # 构造函数,名称固定__init__,参数self会自动添加,不可删除,表示类本身,调用类名创建对象时不需要赋值
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def say_hello(self):
        print(f"姓名:{self.name},年龄:{self.age} 说你好")
person=Person("小明",18)
print("姓名:",person.name)
print("年龄:",person.age)
person.say_hello()

打印内容:

姓名: 小明
年龄: 18
姓名:小明,年龄:18 说你好

继承

class Person:
    # 构造函数,名称固定__init__,参数self会自动添加,不可删除,表示类本身,调用类名创建对象时不需要赋值
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def say_hello(self):
        print(f"姓名:{self.name},年龄:{self.age} 说你好")
# 继承
class Student(Person):
    def __init__(self,age,name,score):
        super().__init__(age,name)
        self.score=score
    # 重写父类方法    
    def say_hello(self):
        print(f"姓名:{self.name},年龄:{self.age} 说你好,分数:{self.score}")
student = Student("小李",18,20)
print(f"姓名:{student.name}")
print(f"年龄:{student.age}")
student.say_hello()

打印结果:

姓名:小李
年龄:18
姓名:小李,年龄:18 说你好,分数:20

容易出错点:构造函数为__init__(),不是int,另外调用父类方法是super().init,不是super().init

1.94 异常处理

示例如下:

try:
	# 业务代码
    a = 1/1
except:
    print("有异常产生,执行此逻辑!")
else:
    print("没有异常产生,执行此逻辑!")
finally:
    print("无论是否有异常产生,必然会执行的逻辑!")

抛出异常:

raise ZeroDivisionError("除数不能为0")

pass

pass表示逻辑占位符,就是好比是暂时还不确定执行何种逻辑可以使用pass

if a > 1:
	pass

1.95 支持http访问服务

# 创建请求服务处理类,使用三方库http中server,继承BaseHTTPRequestHandler,实现doGet方法
import http.server
import datetime
import json
class CustomRequestHandle(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        # print(self.server)                # HTTPServer 实例
        # print(self.client_address)        # 客户端地址和端口: (host, port)
        # print(self.requestline)           # 请求行, 例如: "GET / HTTP/1.1"
        # print(self.command)               # 请求方法, "GET"/"POST"
        # print(self.path)                  # 请求路径, Host 后面部分
        # print(self.headers)               # 请求头, 通过 headers["header_name"] 获取值
        # self.rfile                        # 请求输入流
        # self.wfile                        # 响应输出流

        # 设置响应code
        self.send_response(200)
        # 设置请求头
        self.send_header("content-type" ,"text/html;charset=utf-8")
        self.end_headers()

        # 设置响应信息
        print("业务处理逻辑执行后组装返回参数")
        res = ResponseInfo(200,True,"操作成功","456")
        self.wfile.write(bytes(res.jsonFormat(),"utf-8"))
        return
class ResponseInfo:
    def __init__(self,code,success,msg,data):
        self.code=code
        self.success=success
        self.msg=msg
        self.data=data

    def jsonFormat(self):
        dictInfo={
            "code":self.code,
            "success":self.success,
            "msg":self.msg,
            "data":self.data,
        }
        # indent表示缩进空格长度 ensure_ascii=False处理中文转码为Unicode问题
        return json.dumps(dictInfo,indent=4,ensure_ascii=False)

class CustomServe:
    # 初始化
    def __init__(self,host,port):
        self.host = host
        self.port = port

    # 启动服务
    def start(self):
       print(f"{datetime.datetime.now()}:serve start on host:{self.host},port:{self.port}")
       httpd = http.server.HTTPServer((self.host,self.port),CustomRequestHandle)
       httpd.serve_forever()

if __name__ == '__main__':
    customServe = CustomServe("127.0.0.1", 8080)
    customServe.start()

1.96 配置文件cfg

.cfg文件和.ini文件作用相同,一般用作配置文件,比如说配置数据连接路径、账号密码等信息,格式如下:

# 节点名
[mine]  
# key=value形式存储
name = jack  
age = 256

cfg文件内容读取方式:
使用ConfigParser函数进行读取

from configparser import ConfigParser
config_parser = ConfigParser()
config_parser.read('pdfToWordConfig.cfg', encoding='utf-8')
config = config_parser['mine']
print(config['name'])  # 输出name
print(config['age'])   # 输出age

1.97 全局变量

变量默认是局部生效,仅在函数或是对象内部支持调用,如果想在函数外调用需定义为全局变量.定义方式:

global 变量

当前文件任意位置可用.
补充:也可以在定义类的init方法中将变量设置为类的一个成员变量,则初始化类之后可以从其他方法中调用.比如说下载按钮初始化是可以点击,但是点击之后是需要置灰的.

class APP:

    def __init__(self, windowWidth, windowHeight):

        # 控件内容设置
        self.button = tk.Button(frame_1, text="一键下载",
                           command=lambda: self.buttonDownImg())


    # 下载所有页
    def buttonDownImg(self):
     
        # 禁用下载按钮,此处button在class作为成员变量其他方法可以进行调用
        self.button.config(state=tk.DISABLED)
 


if __name__ == '__main__':
    # 初始化tinker,宽度高度均为400
    app = APP(windowWidth=400,windowHeight=400)
    # 禁止修改窗口大小
    app.window.resizable(False, False)
    # 窗口居中
    app.center()
    # 父窗口进入事件循环,可以理解为保持窗口运行,否则界面不展示
    app.window.mainloop()

1.98 @classmethod

@classmethod可以理解为java中的静态方法,不用实例化就可以调用带有此注解的方法,第一个参数为cls:对象本身


class Test():

   def sayHi(self):
        print("执行了hi方法")

   @classmethod
   def sayHello(cls):
       print("执行了hello方法")
if __name__ == '__main__':
    # 实例化执行sayHi方法
    Test().sayHi()  # 输出:执行了hi方法
    # 不用实例化执行sayHello方法,类似于java中的静态方法
    Test.sayHello()  # 输出:执行了hello方法

1.99 除法取整

Python中除法是/,获取的结果不一定是整除,如果想获取整除数可以用//

 a=5
 b=2
 print(a/b)  # 输出2.5
 print(a//b)  # 输出2

1.991 多线程

线程创建方式:

import threading
def funA():
    print(f"funA执行了")
def funB(param1):
     print(f"funB执行了")
def funC(param1,param2):
     print(f"funC执行了")
if __name__ == '__main__':
	# 线程A,注意target后面为要执行的函数,不能加括号
  threadA = threading.Thread(target=funA)
  threadA.start()
  	# 线程B,注意target后面为要执行的函数,不能加括号;函数传参需要用元组,只有一个参数则后面需要用逗号
  threadB = threading.Thread(target=funB,args=(param1,))
  threadB.start()
    # 线程C,注意target后面为要执行的函数,不能加括号;函数传参需要用元组
  threadC = threading.Thread(target=funC,args=(param1,param2))
  threadC.start()

1.992 自定义函数

自定义函数传参说明:
设置参数默认值,调用时不传递参数则为默认值

# 设置参数默认值,调用时不传递参数则为默认值        
def test1(param1,param2,param3=4):
    print(f"param1:{param1},param2:{param2},param3:{param3}")

if __name__ == '__main__':
    test1(5,6)  # 输出内容:param1:5,param2:6,param3:4
    # test1(5,6,7)  # 输出内容:param1:5,param2:6,param3:7

传递多个参数

# 传递多个参数    
def test2(*args):
    for arg in args:
        print(arg)
 if __name__ == '__main__':
    # test2("abc",5,6)   # 输出内容:abc 5 6

传递多个参数并对指定参数设置值

# 传递多个参数并对指定参数设置值
def test3(param1,param2,*args,**kwargs):
    print(f"param1:{param1}")
    print(f"param2:{param2}")
    for arg in args:
        print(f"arg:{arg}")
    for key, value in kwargs.items():
        print(f"key:{key},value:{value}")

if __name__ == '__main__'
    test3("abc",5,6,5,arg5='d', arg6='e')   
    # 输出内容: param1:abc
				param2:5
				arg:6
				arg:5
				key:arg5,value:d
				key:arg6,value:e

1.993 window中直接进入cmd指定目录方式

鼠标放到文件目录后直接
在这里插入图片描述

1.994 枚举enumerate函数

enumerate(集合,开始索引,不填默认从0开始)

 titles = ["姓名", "年龄", "性别"]
    for i, title in enumerate(titles):
        print(f"i:{i},title:{title}")

不指定索引,默认从0开始,输出内容如下:

i:0,title:姓名
i:1,title:年龄
i:2,title:性别

可以指定索引,遍历会从指定索引开始

  titles = ["姓名", "年龄", "性别"]
    for i, title in enumerate(titles,1):
        print(f"i:{i},title:{title}")

输出内容:

i:1,title:姓名
i:2,title:年龄
i:3,title:性别

2.内置函数

2.1 set

添加元素:add()
不存在获取指定元素方法,只能遍历获取
移除元素:pop()
注意此方法是随机移除,set集合本身是无序,返回值是移除的元素

2.2 正则表达式

常用正则表达式:

\d	匹配一个数字字符。等价于[0-9].  匹配除“\n”之外的任何单个字符。要匹配包括“\n”在内的任何字符,请使用像“[.\n]”的模式。
*  匹配前面的子表达式零次或多次。例如,zo*能匹配“z”以及“zoo”。*等价于{0,}+  匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}?  匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等价于{0,1}.*? 表示匹配任意字符到下一个符合条件的字符,正则表达式a.*?bbb 可以匹配 acbbb abbbbb accccccccbbb

点击查看更多正则表达式
re.match(正则表达式,字符串)
符合正则返回值是match对象,获取匹配内容使用group函数,不符合正则返回None

import re
a = "http://www.crazyant.net/456.html"
returnMsg = re.match("http://www.crazyant.net/\d*.html",a)
print(returnMsg.group())  # 打印http://www.crazyant.net/456.html
returnMsg = re.match("http://www.crazyant.net/\d*/.html",a)
print(returnMsg) # 打印None

2.2 查询页面中所有的hoverURL路径信息

部分页面内容:
在这里插入图片描述
处理方式:

		# re.S:匹配包括换行在内的所有字符
        pattern = re.compile('"hoverURL":"(.*?)"', re.S)
        img_link_list = pattern.findall(html)

打印内容(实际内容与上图不符,这里只展示处理完后的形式):

['http://t15.baidu.com/it/u=110354063,3745088155&fm=224&app=112&f=JPEG?w=500&h=500','https://img1.baidu.com/it/u=2719489460,2835928003&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1000']

2.3 内容输入函数input

input() 函数支持用户输入内容

在这里插入图片描述

2.4 range()

格式:

rang使用 range(开始索引,结束索引,步长)

开始索引不写默认从0开始,步长不写默认1,范围包含开始索引,不包含结束索引,可用做循环遍历

for i in range(5):  # 一个参数表示从0,开始到参数所在位置(不包含该参数)
    print(i) # 打印出:01234
print("*"*20)
for a in range(1,5):  # 两个参数表示起止索引,步长默认为1
    print(a) # 打印出:1234
print("*"*20)
for b in range(1,5,2):  # 三个参数表示起止索引,步长为2
    print(b) # 打印出:13

2.5 list集合

# 创建集合
a = []
# 添加元素
a.append(2)
a.append(3)
# 修改元素,索引从0开始
a[1]=4
# 移除元素
a.remove(2)
print(a) # 打印:[4]

3.模块以及模块引入

模块相当于是多个函数的集合,模块存在的意义就是将处理某一类问题的函数进行封装被其他逻辑调用.和内置函数一样,Python有内置模块,可以理解为Python自带,也有三方模块.
引入方式:

# 方式一: 引入模块名,模块名.函数名调用
import 模块名
	模块名.函数名或变量名
# 方式二:引入模块中的函数名,使用时直接调用函数名
from 模块名 import 函数名或变量名(如果使用*表示引入模块中所有函数或变量)
	代码逻辑

示例:
引入datetime模块查询当前日期,两种引用方式:

# 时间模块
import datetime
print("当前日期:",datetime.date.today())
from datetime import date
print("当前时间:",date.today())

如果内置模块仍然不能满足需求,可以使用三方模块,不过需要先下载到本地在按照上面的方式进行引入,下载方式:

pip install 三方模块名

3.1 os模块

os 模块是 Python 内置的与操作系统中的文件系统相关的模块,该模块依赖于操作系统。常用于用于文件操作,已图片下载本地简单讲述使用:
下载图片到本地示例:

import requests
import os
imgUrl ="http://nav.esggi.com//upload/images/dhnyggw/20201001/20201001175607027.jpg"
res = requests.get(imgUrl)
if res.status_code != 200:
    print("请求失败!")
# 下载图片到本地 TypeError: write() argument must be str, not bytes
imgName = os.path.basename("test.jpg")
with open(f"D:\mvImg\{imgName}","wb") as imgFile:
    resp = imgFile.write(res.content)
    print(resp)  # 打印15787

注意点:
   引入os模块,使用os.path.basename()创建文件名,否则会出现权限问题:

PermissionError: [Errno 13] Permission denied: 

   write()返回值为写入内容的行数
常用方法:
读取问目录下所有的文件和文件夹:

os.listdir(path)

获取文件的文件名和拓展名:

os.path.splitext(文件名.拓展名)

示例:

 for file in os.listdir("D:\convert"):
      print(f"目录下内容:{file}")
      for name in os.path.splitext(file):
          print(f"文件名:{name}")
          打印内容如下
          """
			目录下内容:202311051431.docx
			文件名:202311051431
			文件名:.docx
		"""

3.2 datetime模块

获取当前日期:

import datetime
print(datetime.date.today())
# 输出:2023-11-04

获取当前时间:

import datetime
print(datetime.datetime.now())
# 输出:2023-11-04 16:27:27.852732

将当前时间格式化:

print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
# 输出:2023-11-04 16:27:27

3.3 tinker模块

实现按钮间距分布

class APP:

    def __init__(self, windowWidth, windowHeight):
        self.windowWidth = windowWidth
        self.windowHeight = windowHeight
        # 创建tkinter对象
        self.window = tk.Tk()
        # 设置窗口标题
        self.window.title("图片下载")

        # Frame空间
        frame_1 = tk.Frame(self.window)
        frame_2 = tk.Frame(self.window)
        frame_3 = tk.Frame(self.window)

        # 控件内容设置
        button = tk.Button(frame_1, text="一键下载",
                           command=lambda: self.buttonDownImg())


        # 进度条标签
        progressLabel = tk.Label(frame_2, text="进度条标签:")


        # 设置进度条
        progressBar = Progressbar(frame_2,length=200, mode="indeterminate")
        progressBar.start()

        # 标签
         label = tk.Label(frame_3,fg="red", text='\n注意:支持大部分主流网站的图片下载!\n此软件仅用于交流学习,请勿用于任何商业用途!')

        # 控件布局
        frame_1.pack()
        frame_2.pack()
        frame_3.pack()
        button.grid(row=0, column=0,pady=60) # 设置距离顶部60像素
        progressLabel.grid(row=1, column=0)
        progressBar.grid(row=1, column=1)
        label.grid(row=2, column=0,pady=40) # 设置距离上个控件40像素
        
    # 函数说明:tkinter窗口居中
    def center(self):
        # 获取屏幕尺寸
        screenWidth = self.window.winfo_screenwidth()
        screenHeight = self.window.winfo_screenheight()

        # 计算窗体居中的坐标
        windowX = int((screenWidth - self.windowWidth) / 2)
        windowY = int((screenHeight - self.windowHeight) / 2)

        # 窗口大小(宽X高)以及窗口所在位置
        self.window.geometry(f"{self.windowWidth}x{self.windowHeight}+{windowX}+{windowY}")      

if __name__ == '__main__':
    # 初始化tinker,宽度高度均为400
    app = APP(windowWidth=400,windowHeight=400)
    # 禁止修改窗口大小
    app.window.resizable(False, False)
    # 窗口居中
    app.center()
    # 父窗口进入事件循环,可以理解为保持窗口运行,否则界面不展示
    app.window.mainloop()
       

在这里插入图片描述
组件间隔设置
在这里插入图片描述
gray方法中参数说明:

pady表示组件在垂直方向的间距.第一个frame组件为例,第一行关键字当前页设置pady为40表示这一行上下距离frame父组件的距离为40
padx表示组件在水平方向上的间距,第二个frame组件为例,三个按钮间隔一定距离5就是通过padx进行设置
ipadx表示水平方向的内边距.以第三个frame组件说明,想拉长一键下载按钮,可以通过设置ipadx来实现

相关代码:

import re
import time
import datetime
class APP:

    def __init__(self, windowWidth, windowHeight,pageNum):
        self.windowWidth = windowWidth
        self.windowHeight = windowHeight
        # 创建tkinter对象
        self.window = tk.Tk()
        # 设置窗口标题
        self.window.title("图片下载")
        # 当前下载完成图片数
        self.sucImgCount=0
        # 下载图片地址集合信息
        self.imgList=[]
        # 支持下载页数
        self.pageNum=pageNum
        # 搜索关键词
        self.keyWord=tk.StringVar()
        # 下载目标网址
        self.url = 'https://pic.sogou.com/napi/pc/searchList?mode=1&start={}&xml_len=48&query={}'
        self.word_parse = ''
        self.startIndex = 0  # 开始索引
        self.page = 1  # 当前页


        # Frame空间
        frame_1 = tk.Frame(self.window,background="green") # 无需设置宽高,子组件会自动撑开
        frame_2 = tk.Frame(self.window,background="red")
        frame_3 = tk.Frame(self.window,background="blue")
  

        #  搜索关键词
        self.keywordLabel = tk.Label(frame_1, text="关键词:")
        # 关键词输入框
        self.entry = tk.Entry(frame_1, textvariable=self.keyWord, highlightcolor='Fuchsia', highlightthickness=1, width=20)
        # 页数显示
        self.pageLabel = tk.Label(frame_1, text="当前页:")
        # 关键词输入框
        self.pageEntry = tk.Entry(frame_1, textvariable=self.page, highlightcolor='Fuchsia', highlightthickness=1,
                              width=5)

        # 首页
        self.firstButton = tk.Button(frame_2, text="首页",
                                     command=lambda: self.buttonDownImg())
        # 上一页
        self.lastButton = tk.Button(frame_2, text="上一页",
                                    command=lambda: self.buttonDownImg())
        # 下一页
        self.nextButton = tk.Button(frame_2, text="下一页",
                                command=lambda: self.buttonDownImg())

        # 控件内容设置
        self.button = tk.Button(frame_3, text="一键下载",
                           command=lambda: self.buttonDownImg())


        # 控件布局
        frame_1.pack()
        frame_2.pack()
        frame_3.pack()
     
        self.keywordLabel.grid(row=0, column=0,pady=40) # 该组件距离父组件frame_1的垂直间隔40像素
        self.entry.grid(row=0, column=1,pady=40) # 该组件距离父组件frame_1的垂直间隔40像素
        self.pageLabel.grid(row=0, column=2, pady=40)  # 该组件距离父组件frame_1的垂直间隔40像素
        self.pageEntry.grid(row=0, column=3, pady=40)  # 该组件距离父组件frame_1的垂直间隔40像素
        self.firstButton.grid(row=1, column=0,pady=10,padx=5) # 该组件距离父组件frame_2的垂直间隔40像素,距离父组件和lastButton水平间隔5px
        self.lastButton.grid(row=1, column=1,pady=10,padx=5) 
        self.nextButton.grid(row=1, column=2,pady=10,padx=5) 
        self.button.grid(row=2, column=0,pady=10,padx=5,ipadx=50) 
        

    # 函数说明:tkinter窗口居中
    def center(self):
        # 获取屏幕尺寸
        screenWidth = self.window.winfo_screenwidth()
        screenHeight = self.window.winfo_screenheight()

        # 计算窗体居中的坐标
        windowX = int((screenWidth - self.windowWidth) / 2)
        windowY = int((screenHeight - self.windowHeight) / 2)

        # 窗口大小(宽X高)以及窗口所在位置
        self.window.geometry(f"{self.windowWidth}x{self.windowHeight}+{windowX}+{windowY}")



if __name__ == '__main__':
    # # 初始化tinker,宽度高度均为400
    app = APP(windowWidth=400,windowHeight=400)
    # # 禁止修改窗口大小
    app.window.resizable(False, False)
    # # 窗口居中
    app.center()
    # 父窗口进入事件循环,可以理解为保持窗口运行,否则界面不展示
    app.window.mainloop()

3.4 BeautifulSoup模块

使用方式可以参考:
python入门实战:爬取图片到本地
总结一下find_all方法:
1.对于标签中有明确ID或class属性可以直接用标签name查找:

<div class="pic" style="background-image: url(https://img0.huamaocdn.com/upload/bizhi/images/280h/2022/05/202205261534164059.jpg);"></div>

查询方法:

# 查询div标签
 img_url_list = soup.find_all(name="div", class_="pic")
 # 获取标签的style属性
 style_info = imgUrl["style"]
 # 截取图片地址
 img = style_info[style_info.find("(") + 1:style_info.find(")")]

2.按照属性查询

<img data-original="图片.jpg" src="图片.jpg" alt="说明内容" style="display: inline;">

如果按照style="display: inline;"进行查找图片内容,可以按照属性的方式查询:

img_url_list = soup.find_all(attrs={"style":"display: inline;"})

3.查询指定标签下的指定内容
查询li标签下img标签中的src

    html="""<li class="pc-items-item item-undefined" data-itemid="674861494933">
	<a target="_blank" class="pc-items-item-a" >
		<img class="pc-items-item-img img-loaded" src="https://img.alicdn.com/imgextra/i1/27112229/O1CN01org81N1SKvaVGJzoI_!!0-saturn_solar.jpg_468x468q75.jpg_.webp">
		<div class="pc-items-item-title pc-items-item-title-row2">
			<span class="title-text">航天变形玩具长征运载火箭儿童飞机合体机甲机器人金刚全套装男孩</span>
		</div>	
		<div class="item-footer">
			<div class="item-tags"></div>
			<div class="sell-info">月销 10+</div>
		</div>
	</a>
</li>"""
    soup = bs4.BeautifulSoup(html, "html.parser")
    # 查询li标签下的img标签内容
    # 直接使用要定位的标签,可以跨过中间标签a
    # child = soup.select("li img")
    # 或是直接使用所有标签,中间线用>连接
    img = soup.select("li > a > img")
     print("img:", img)
    # 打印内容:img: [ < img class ="pc-items-item-img img-loaded" src="https://img.alicdn.com/imgextra/i1/27112229/O1CN01org81N1SKvaVGJzoI_!!0-saturn_solar.jpg_468x468q75.jpg_.webp" / >]

 
    # 返回值为集合,只有一个元素需要取第一个元素
    img = img[0]
    print("img:", img)
    # img: <img class="pc-items-item-img img-loaded" src="https://img.alicdn.com/imgextra/i1/27112229/O1CN01org81N1SKvaVGJzoI_!!0-saturn_solar.jpg_468x468q75.jpg_.webp"/>
    # 返回标签中src属性信息
    src = img.get('src')
    print("img src:",src)
    # img src: https://img.alicdn.com/imgextra/i1/27112229/O1CN01org81N1SKvaVGJzoI_!!0-saturn_solar.jpg_468x468q75.jpg_.webp
    # 获取div span 中的问文本内容
    spanContent= soup.select("li div span")[0].getText()
    print(spanContent)  # 航天变形玩具长征运载火箭儿童飞机合体机甲机器人金刚全套装男孩
    # 同一级存在多个相同标签处理方式:使用标签属性
     saleNum = soup.select('li div div[class="sell-info"]')[0].getText()
    print("saleNum:", saleNum) # 打印内容:月销 10+

4.获取多个span标签中的文本内容
在这里插入图片描述
处理方式:

    str ='<div class="Title--title--jCOPvpf"><span class="">进口赤霞珠干红葡萄酒<span style="color: rgb(255, 68, 0);">红酒</span>整箱原瓶进口正品14度女士甜型<span style="color: rgb(255, 68, 0);">红酒</span>送礼</span></div>'
    soup = bs4.BeautifulSoup(str, "html.parser")
    # soup.select('div span')会查询符合条件的标签以及子集标签
    for span in soup.select('div span'):
        print(f"span:{span}")
    #     获取span标签中的文本(含不带格式的子集文本),span.text与span.getText()打印内容相同
        print(f"span.text:{span.text}")
        print(f"span.getText():{span.getText()}")

打印内容:

span:<span class="">进口赤霞珠干红葡萄酒<span style="color: rgb(255, 68, 0);">红酒</span>整箱原瓶进口正品14度女士甜型<span style="color: rgb(255, 68, 0);">红酒</span>送礼</span>
span.text:进口赤霞珠干红葡萄酒红酒整箱原瓶进口正品14度女士甜型红酒送礼
span.getText():进口赤霞珠干红葡萄酒红酒整箱原瓶进口正品14度女士甜型红酒送礼
span:<span style="color: rgb(255, 68, 0);">红酒</span>
span.text:红酒
span.getText():红酒
span:<span style="color: rgb(255, 68, 0);">红酒</span>
span.text:红酒
span.getText():红酒

5.综合案例
爬取内容:在这里插入图片描述

 str ="""<div>
	<a>
		<div class="Card--doubleCard--wznk5U4">
			<div class="Card--mainPicAndDesc--wvcDXaK">
				<div class=" MainPic--mainPicWrapper--iv9Yv90">
					<div class="MainPic--mask--Yn060WJ MainPic--mainPicWrapper--iv9Yv90"></div>
					<img src="https://uploaded/0q90.jpg_.webp" class="MainPic--mainPic--rcLNaCv">
				</div>
				<div class="Title--descWrapper--HqxzYq0 ">
					<div class="Title--title--jCOPvpf">
						<img class="Title--iconPic--kYJcAc0" src="https://48.png">
						<span class="">卡其色毛呢<span style="color: rgb(255, 68, 0);">短裤</span>女春秋高腰a字裤外穿打底裤子小个子靴裤2024新款</span>
					</div>
				</div>
				<div class="Price--priceWrapper--Q0Dn7pN ">
					<span class="Price--unit--VNGKLAP">¥</span>
					<span class="Price--priceInt--ZlsSi_M">54</span>
					<span class="Price--priceFloat--h2RR0RK">.90</span>
					<span class="Price--realSales--FhTZc7U">100+人付款</span>
					<div>
						<span class="Price--procity--_7Vt3mX">广东</span>
					</div>
					<div>
						<span class="Price--procity--_7Vt3mX">广州</span>
					</div>
				</div>
			</div>
			<div class="SalesPoint--subIconWrapper--s6vanNY ">
				<div>
					<span>官方补贴5</span>
				</div>
				<div>
					<span>赠运费险</span>
				</div>
				<div>
					<span>包邮</span>
				</div>
			</div>
			<div class="ShopInfo--shopInfo--ORFs6rK ">
				<div class="ShopInfo--TextAndPic--yH0AZfx">
					<img src="https://SZTESuwWAVXa.jpg" class="ShopInfo--shopLogo--GfM9aLF">
					<a class="ShopInfo--shopName--rg6mGmy" >zenpp旗舰店</a>
				</div>
			</div>
		</div>
	</a>
</div>"""
    soup = bs4.BeautifulSoup(str, "html.parser")
    mainImg = soup.select('div a div div div img[class="MainPic--mainPic--rcLNaCv"]')[0].get("src")
    print(f"mainImg:{mainImg}")
    title=""
    region=""
    label=""
    for span in soup.select('div a div div div div[class="Title--title--jCOPvpf"] span'):
        title=span.text
        print(f"title:{title}")
        break
    priceInt = soup.select('div a div div div[class="Price--priceWrapper--Q0Dn7pN"] span[class="Price--priceInt--ZlsSi_M"]')[0].text
    print(f"priceInt:{priceInt}")
    priceFloat =soup.select('div a div div div[class="Price--priceWrapper--Q0Dn7pN"] span[class="Price--priceFloat--h2RR0RK"]')[0].text
    print(f"priceFloat:{priceFloat}")
    realSales = soup.select('div a div div div[class="Price--priceWrapper--Q0Dn7pN"] span[class="Price--realSales--FhTZc7U"]')[0].text
    print(f"realSales:{realSales}")
    for distinct in soup.select('div a div div div[class="Price--priceWrapper--Q0Dn7pN"] span[class="Price--procity--_7Vt3mX"]'):
        region+=distinct.text
    print(f"region:{region}")
    for span in soup.select('div a div div[class="SalesPoint--subIconWrapper--s6vanNY"] div span'):
        label+=span.text
    print(f"label:{label}")
    shopImg = soup.select('div a div div[class="ShopInfo--shopInfo--ORFs6rK"] div[class="ShopInfo--TextAndPic--yH0AZfx"] img')[0].get("src")
    print(f"shopImg:{shopImg}")
    shopName = soup.select('div a div div[class="ShopInfo--shopInfo--ORFs6rK"] div[class="ShopInfo--TextAndPic--yH0AZfx"] a')[0].getText()
    print(f"shopImg:{shopName}")

打印内容:

mainImg:https://uploaded/0q90.jpg_.webp
title:卡其色毛呢短裤女春秋高腰a字裤外穿打底裤子小个子靴裤2024新款
priceInt:54
priceFloat:.90
realSales:100+人付款
region:广东广州
label:官方补贴5元赠运费险包邮
shopImg:https://SZTESuwWAVXa.jpg
shopImg:zenpp旗舰店

6.按照元素class前缀查询
上述案例中根据页面返回内容发现,标签中class中前缀都是相同的,只有后缀不同,可以按照前缀元素查询.以查询图片为例:

mainImg = soup.select('img[class^="MainPic--mainPic"]')[0].get("src")

上述案例按照前缀查询处理后:

soup = bs4.BeautifulSoup(str(div), "html.parser")
    mainImg = soup.select('img[class^="MainPic--mainPic"]')[0].get("src")
    title = ""
    label = ""
    # 查询class以Title--title开头的div下面的所有span标签集合(含子标签)
    for span in soup.select('div[class^="Title--title--"] span'):
        title += span.text
    priceInt = soup.select('span[class^="Price--priceInt--"]')[0].text
    priceFloat = soup.select('span[class^="Price--priceFloat--"]')[0].text
    realSales = soup.select('span[class^="Price--realSales--"]')[0].text
    region = soup.select('span[class^="Price--procity--"]')[0].text
    for span in soup.select('div[class^="SalesPoint--subIconWrapper--"] div span'):
        label += span.text + " "
    shopName = soup.select('a[class^="ShopInfo--shopName--"]')[0].text
    print(f"title:{title},mainImg:{mainImg},price:{priceInt + priceFloat},realSales:{realSales},region:{region},label:{label},shopImg:{shopName}")

3.5 time模块

获取当前时间:

import time
print(time.strftime('%Y-%m-%d %H:%M:%S'))  # 输出内容:2023-12-23 21:20:04

获取当前时间时间戳:

import time
  timestamp = int(time.time())
  print("当前时间的时间戳为:", timestamp)  // 打印内容:1704245164

3.6 request模块之请求重试

请求重试,首先讲一下timeout

request中timeout表示连接超时(和服务端建立连接)和读取超时(和服务端建立连接后服务端响应客服端的时间).
可以统一设置,比如timeout=5表示连接超时和读取超时都是5秒,
也可以分别设置需要用元组形式,timeout(5,6)表示连接超时时间为6,读取超时为6

首先看一下自己可以实现的方式,重试次数3次(含首次请求):

def personReTry():
    i=1
    while i <=3:
        try:
            print(f"第{i}次请求")
            r = requests.get('https://www.google.n', timeout=5)
            print(r.text)
        except requests.exceptions.RequestException as e:
            print(f"请求异常{e}")
            i=i +1
if __name__ == '__main__':
    personReTry()           

打印内容:

1次请求
请求异常HTTPSConnectionPool(host='www.google.n', port=443): Read timed out. (read timeout=5)2次请求
请求异常HTTPSConnectionPool(host='www.google.n', port=443): Read timed out. (read timeout=5)3次请求
请求异常HTTPSConnectionPool(host='www.google.n', port=443): Read timed out. (read timeout=5)

也可以用request封装的方法,不过没办法表示第几次请求,只能通过方法执行时间判断执行了几次.示例:

import time
import requests
from requests.adapters import HTTPAdapter

def reTry():
    s = requests.Session()
    # max_retries表示最大尝试次数
    s.mount('http://', HTTPAdapter(max_retries=3))
    s.mount('https://', HTTPAdapter(max_retries=3))

    print(f"{time.strftime('%Y-%m-%d %H:%M:%S')}")
    try:
        r = s.get('https://www.google.n', timeout=5)
        print(r.text)
    except requests.exceptions.RequestException as e:
        print(f"请求异常{e}")
    finally:
        print(time.strftime('%Y-%m-%d %H:%M:%S'))
def normalRequest():
    print(time.strftime('%Y-%m-%d %H:%M:%S'))
    try:
        r = requests.get('https://www.google.n', timeout=5)
        print(r.text)
    except requests.exceptions.RequestException as e:
        print(f"请求异常{e}")
    finally:
        print(time.strftime('%Y-%m-%d %H:%M:%S'))
 if __name__ == '__main__':
   		 reTry()

打印内容:

2023-12-23 21:50:08
请求异常HTTPSConnectionPool(host='www.google.n', port=443): Max retries exceeded with url: / (Caused by ReadTimeoutError("HTTPSConnectionPool(host='www.google.n', port=443): Read timed out. (read timeout=5)"))
2023-12-23 21:50:28

设置正常超时时间为5秒,实际运行为20秒,所以加上首次总共是4次

3.7 excel操作openpyxl模块

    excel创建sheet并设置标题:

import openpyxl
 		# 创建一个新的工作簿
        workbook = openpyxl.Workbook()

        # 选择默认的工作表
        sheet = workbook.active
        # 创建一个名为Sheet1的工作表
        # sheet = workbook.create_sheet(title="Sheet1")
        # 设置标题行
        titles = ["商品标题", "商家", "商品主图", "商品价格", "销量", "地区", "服务"]
        for col, title in enumerate(titles, 1):
            sheet.cell(row=1, column=col).value = title

        # 保存工作簿到文件
        workbook.save(self.excelFilePath)

    在已创建标题的excel中按照标题内容添加数据:

		 # 打开Excel文件
        workbook = openpyxl.load_workbook(self.excelFilePath)

        # 选择第一个工作表
        # 选择默认的工作表
        sheet = workbook.active

        # 获取最后一行的行数
        last_row = sheet.max_row
        # 开始行跳过第一行的标题
        startLine = last_row + 1

        # 将文件内容按行分割并写入工作表中
        for i, line in enumerate(goodsArray):
            row = i + startLine
            sheet.cell(row=row, column=1, value=goodsArray[i]["title"])
            sheet.cell(row=row, column=2, value=goodsArray[i]["shopName"])
            sheet.cell(row=row, column=3, value=goodsArray[i]["mainImg"])
            sheet.cell(row=row, column=4, value=goodsArray[i]["price"])
            sheet.cell(row=row, column=5, value=goodsArray[i]["realSales"])
            sheet.cell(row=row, column=6, value=goodsArray[i]["region"])
            sheet.cell(row=row, column=7, value=goodsArray[i]["label"])
        # 保存工作簿到文件
        workbook.save(self.excelFilePath)

    excel读取的商品标题列和商品图片列数据:

# 图片存储信息
    imgJsonList=[]
    if not os.path.exists(self.excelFilePath):
        messagebox.showerror("图片下载:","图片下载失败,excel文件不存在!")
        return
    # 打开Excel文件
    workbook = openpyxl.load_workbook(self.excelFilePath)

    # 选择默认的工作表
    sheet = workbook.active

    # 获取A列商品标题以及C列图片信息(不包含第一行标题)
    for rowIndex in range(2,sheet.max_row):
        imgJson={}
        imgJson["title"]=sheet[f"A{rowIndex}"].value
        imgJson["img"]=sheet[f"C{rowIndex}"].value
        imgJsonList.append(imgJson)
    return imgJsonList

4.pycharm设置与快捷键

4.1 去除PE8格式校验

在这里插入图片描述

4.2 mian主函数快捷键

直接输入关键字main

4.3 命名大小写警告问题

用pyCharm时,常会出现警告信息:

function name should be lowercase --函数名应该是小写 字母

argument name should be lowercase --参数名应该是小写字母

variable in function should be lowercase --变量应该是小写字母

警告忽略的方法如下:

File →Settings→Editor→Inspections→Python→PEP 8 naming convention
violation

右下角有个"Ignored errors",增加:

N802

N803

N806 分别对应上面的三种提示。

4.4 pycharm安装三方库

file–setting–选择项目–python interpreter–添加三方库或是点击go to tool winodw.
遇到下载比较慢的情况,可以使用国内镜像,示例格式如下:

pip install torch==1.8.1 -i https://mirrors.aliyun.com/pypi/simple/

清华镜像: https://pypi.tuna.tsinghua.edu.cn/simple
阿里云镜像: https://mirrors.aliyun.com/pypi/simple/

注意:从terminal中输入以上指令,不是console

4.5 pycharm控制台乱码处理

尝试以下几种方式进行处理:
1.修改设置
在这里插入图片描述
2.在每一个py文件最顶部加入 :

# -- coding: utf-8 -- 

3.修改自定义配置
help—Edit Custom VM Options添加以下内容:

-Dfile.encoding=UTF-8

4.6 pycharm导入关联svn后一直显示authentication required

码云仓库检出到本地之后正常,但是导入到pycharm中确认过用户名密码正确,一直提示authentication required,:
在这里插入图片描述
按照以下方式进行处理
在这里插入图片描述

4.7 pycharm变更项目的Python版本

pycharm右下角会显示Python版本,如果导入的项目Python版本与本地Python不一致,执行pip命令就会显示:
No Python at ‘"安装python.exe’

在这里插入图片描述
处理方式按照以下操作:

在这里插入图片描述
或是切换到其他项目的虚拟环境

4.8 pycharm复制浏览器header内容

修改谷歌浏览器设置:
在这里插入图片描述
在这里插入图片描述

重新查看浏览器header信息(修改后注意关闭浏览器重启),会由第一个变更为第二个图效果
在这里插入图片描述
在这里插入图片描述
复制内容之后Pycharm中不要直接粘贴,选择:
在这里插入图片描述

以复制出来的内容为例进行演示:

 sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36

按照上面要求复制到pycharm中:

 headers ={
      sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
   }

具体操作以及输入内容如下:

(.?): (.)
“$1”:“$2”,

在这里插入图片描述
处理完成之后如下:

 headers ={
    "  sec-fetch-dest":"empty",
"sec-fetch-mode":"cors",
"sec-fetch-site":"same-site",
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
   }   

如果复制的header中value有字符串,可以单独处理.

4.9 pycharm复制内容自动换行报错

处理办法是使用三个引号
在这里插入图片描述
在这里插入图片描述

5.Python打包与部署

5.1 Python项目单文件打包成exe

以下操作都是基于创建项目时选择virtualenv这种虚拟环境下进行的打包
pycharm中使用pyinstaller打包,virtualenv虚拟环境创建的项目不用配置pyinstaller的环境变量,interminal中安装pyinstaller:

pip install pyinstaller

打包文件:

pyinstaller -F -w 目标文件.py

打包文件添加图标:

pyinstaller -F -w -i 目标.png 目标文件.py

-F 把整个软件(包括依赖的各种库文件)打包成单一文件;
-w 禁止Windows的命令行窗口。不然双击exe时会打开一个黑dos窗口;
-i 生成的exe文件会带有这个图标,目标图片.ico可以直接放到项目根目录下 打包成功后,exe文件存在于新增的dist文件中. 图标转换为icon格式参考: http://www.ico8.net/index.php?action=make

6.flask框架

6.1基础入门:项目创建与启动

导入flask模块,引用Flask函数,服务启动之后访问:http://localhost:8080/,返回hello word!

import requests
# 安装flask之后导入Flask模块
from flask import Flask

# 创建Flask实例
app = Flask(__name__)

# 指定路由
@app.route("/")
def test():  # 自定义方法
    return "hello word!"

if __name__ == '__main__':
    # 启动应用,debug:True表示有代码改动会重新进行加载(一般仅在测试环境,生产不会使用),可以理解为idea中的热部署.
    app.run(host="localhost",port=8080,debug=True)

补充:
pycharm中可以直接创建flask项目.创建方式如下:
在这里插入图片描述
注意,已此种方式创建的flask项目启动时默认的IP和端口是127.0.0.0:5000,

app.run(host="localhost",port=8080,debug=True)

会失效.处理方式是修改flask项目配置:

--host=0.0.0.0 --port=8080

在这里插入图片描述
启动点击调试按钮启动
在这里插入图片描述
如果要求支持https访问,可以添加证书
在这里插入图片描述

--host=0.0.0.0 --port=8084 --cert=证书.pem --key=证书.key

在这里插入图片描述
app.py中启动命令:

app.run(host="0.0.0.0",port=8084,ssl_context=('证书.pem','证书.key'))

证书是从阿里云申请的免费证书,下载类型是nginx证书

6.2get请求参数获取

from flask import Flask,request
@app.route("/")
def test():  # 自定义方法
    # 访问:ImmutableMultiDict([('userName', 'jack'), ('age', '28')])
    # 接收所有请求参数
    requestParam = request.args.__str__() # 返回内容:ImmutableMultiDict([('userName', 'jack'), ('age', '28')])
    # 接收指定请求参数
    # requestParam=request.args.get("userName")  # 返回内容:Jack
    requestParam=request.args.get("password","123456")  # 返回内容:TypeError: The view function for 'test' did not return a valid response.需要设置默认值:123456
    return  requestParam
if __name__ == '__main__':
    # 启动应用,debug:True表示有代码改动会重新进行加载(一般仅在测试环境,生产不会使用),可以理解为idea中的热部署.
    app.run(host="localhost",port=8080,debug=True)

6.3 post请求体json参数获取

@app.route("/testPost",methods=["POST"])
def testPost():
    # print(f"请求体内容:{request.stream.read()}")  # 请求体内容:b'{\r\n    "name":"jack",\r\n    "age":18\r\n}'
    # 打印内容为字节字符串,需要进行decode处理
    print(f"请求体json请求内容:{request.stream.read().decode()}")
    """请求体内容:{
                "name":"jack",
                "age":18
                }"""
    return "post success"
if __name__ == '__main__':
    # 启动应用,debug:True表示有代码改动会重新进行加载(一般仅在测试环境,生产不会使用),可以理解为idea中的热部署.
    app.run(host="localhost",port=8080,debug=True)

使用apifox传参:
在这里插入图片描述

6.4 post请求体表单参数获取

@app.route("/testPost",methods=["POST"])
def testPost():
    print(f"表单请求参数:{request.form}")
   # 表单请求参数:ImmutableMultiDict([('name', 'rose'), ('age', '18')])
   # 接收参数为嵌套字典,需要使用to_dict进行转化
   requestData = request.form.to_dict()
    print(f"请求参数name:{requestData['name']}") # 请求参数name:rose
    print(f"请求参数name:{requestData['age']}")  # 请求参数name:18
    return "post success"
if __name__ == '__main__':
    # 启动应用,debug:True表示有代码改动会重新进行加载(一般仅在测试环境,生产不会使用),可以理解为idea中的热部署.
    app.run(host="localhost",port=8080,debug=True)

使用apifox表单提交:
在这里插入图片描述

6.5指定响应参数

一般返回给客户端的都是json字符串,下面介绍一下组装方式

from flask import Flask,request,jsonify
@app.route("/testPost",methods=["POST"])
def testPost():
   print("指定相应内容")
   response = {"code":200,"success":True,"msg":'操作成功'}
   # jsonify 需要导入
   return jsonify(response)
if __name__ == '__main__':
    # 启动应用,debug:True表示有代码改动会重新进行加载(一般仅在测试环境,生产不会使用),可以理解为idea中的热部署.
    app.run(host="localhost",port=8080,debug=True)

响应结果:

{
    "code": 200,
    "msg": "操作成功",
    "success": true
}

6.6 post请求文件上传

import os.path

import requests
# 安装flask之后导入Flask模块
from flask import Flask,request,jsonify

# 创建Flask实例
app = Flask(__name__)
# 定义文件存储目录
app.config['imageStoragePath'] = 'static/image'
# 定义支持文件上传类型
app.config['imgSuffix'] = ['.jpg', '.png', '.gif']

@app.route("/uploadFile",methods=["POST"])
def uploadFile():
    # 获取文件
    imageFile = request.files['image']
    imageFileName= imageFile.filename

    # 校验文件格式是否合法
    if checkImageSuffix(imageFileName):
        # 保存图片到项目指定目录
        imageFile.save(os.path.join(app.root_path, app.config['imageStoragePath'], imageFileName))
        response = {"code": 200, "success": True, "msg": '操作成功'}

    else:
        response = {"code": 500, "success": True, "msg": '操作失败'}

    return jsonify(response)




# 校验图片文件是否合法
def checkImageSuffix(fileName):
    print(fileName[fileName.find("."):len(fileName)])
    if fileName[fileName.find("."):len(fileName)] in app.config['imgSuffix']:
        return True
    else:
        return False

if __name__ == '__main__':
    # 启动应用,debug:True表示有代码改动会重新进行加载(一般仅在测试环境,生产不会使用),可以理解为idea中的热部署.
    app.run(host="localhost",port=8080,debug=True)

需要提前从项目指定目录下创建文件夹:static/image
apifox请求:
在这里插入图片描述

6.7 Blueprint分层

springMVC模式会将项目结构进行分层,项目结构更加清晰,维护更加方便,那flask项目是否有分层处理,答案是一定的,Blueprint就是用于分层处理.
示例项目结构

controller
…商品模块:Goods.py
…订单模块:GoodsOrder.py
service
…商品实现GoodsServiceImpl.py
…商品订单实现GoodsOrderServiceImpl.py
启动类

示例代码:
启动类app.py:

from flask import Flask
# 导入controller中用到的包
from controller import Goods
from controller import GoodsOrder

# 创建Flask实例
app = Flask(__name__)

app.register_blueprint(Goods.goodsBp,url_prefix='/goods')
app.register_blueprint(GoodsOrder.goodsOrderBp,url_prefix='/goodsOrder')

if __name__ == '__main__':
    # 启动应用,debug:True表示有代码改动会重新进行加载(一般仅在测试环境,生产不会使用),可以理解为idea中的热部署.
    app.run(host="localhost",port=8080,debug=True)

商品模块Goods.py

from flask import Blueprint
from service.GoodsServiceImpl  import findGoodsListByService

goodsBp = Blueprint("goods", __name__)

# 商品列表查询
@goodsBp.route("/findGoodsList",methods=['GET'])
def findGoodsList():
    # 调用商品实现处理逻辑,实现方法名不可与controller方法名相同
    findGoodsListByService()
    response = {"code": 200, "success": True, "msg": '商品查询成功!'}
    return response

订单模块GoodsOrder.py

from flask import Blueprint
from service.GoodsOrderServiceImpl import findGoodsOrderListByService

goodsOrderBp = Blueprint("goodsOrder", __name__)

# 订单列表查询
@goodsOrderBp.route("/findGoodsOrderList",methods=['GET'])
def findGoodsOrderList():
	 # 调用商品订单实现处理逻辑,实现方法名不可与controller方法名相同
    findGoodsOrderListByService()
    response = {"code": 200, "success": True, "msg": '商品订单列表查询成功!'}
    return response

商品实现GoodsServiceImpl:

# 查询商品列表
def findGoodsListByService():
    print("GoodsServiceImpl查询商品列表信息执行!")

商品订单实现GoodsOrderServiceImpl:

# 查询商品订单列表
def findGoodsOrderListByService():
    print("GoodsOrderServiceImpl查询商品订单列表信息执行!")

请求测试:

在这里插入图片描述
在这里插入图片描述

Blueprint分层后配置设置与获取

配置从启动文件中定义,通过flask中current_app获取.具体操作如下:
启动文件:

from flask import Flask

from controller.GoodsController import goods

app = Flask(__name__)

# 配置信息
app.config["path"]="d:\\file_test"

app.register_blueprint(goods,url_prefix='/pdf')

if __name__ == '__main__':
    app.run(host="0.0.0.0",port=8080,debug=True)

配置获取文件:

from flask import current_app

def findGoodsList():
    print("获取商品列表成功!")
    print(current_app.config.get("path"))

7.mysql数据库

7.1查询

import pymysql

# 声明全局变量
conn =None
try:
    # 创建连接
    conn = pymysql.connect(
            host="mysql的IP",
		    user="mysql的用户名",
		    password="mysql的密码",
		    database="mysql数据库名",
		    port=3306,
		    charset="utf8mb4"
    )
    # 创建游标
    cursor = conn.cursor()
    # 执行查询
    cursor.execute("SELECT * FROM tool_convert_record")
    # 查询结果
    selectResult = cursor.fetchall()
    for row in selectResult:
        print(row)

except Exception as e:
    print(f"数据库异常:{e}")
	# 回滚事务
    conn.rollback()
finally:
    if conn:
        # 关闭连接
        conn.close()

查询打印内容:

(1, 1, 1, datetime.datetime(2023, 10, 25, 17, 54, 38), None, 1, '测试文件')
(2, 1, 1, datetime.datetime(2023, 10, 25, 17, 57, 41), datetime.datetime(2023, 10, 25, 17, 57, 48), 1, '测试文件')
(3, 20, 1, datetime.datetime(2023, 10, 26, 7, 15, 4), None, 1, '1.新岗位确认单20230815.pdf')
(4, 20, 1, datetime.datetime(2023, 10, 26, 7, 17, 39), datetime.datetime(2023, 10, 26, 7, 17, 56), 1, '1.新岗位、薪资变动确认单20230815.pdf')
(5, 20, 1, datetime.datetime(2023, 10, 26, 7, 20, 47), None, 1, '1.新岗位确认单20230815.pdf')
(6, 20, 2, datetime.datetime(2023, 10, 26, 7, 23, 53), datetime.datetime(2023, 10, 26, 7, 23, 56), 2, '1.新岗位确认单20230815.pdf')

7.2新增

import pymysql
# 创建连接
conn = pymysql.connect(
    host="mysql的IP",
    user="mysql的用户名",
    password="mysql的密码",
    database="mysql数据库名",
    port=3306,
    charset="utf8mb4"
)
# 创建游标
cursor = conn.cursor()
# 执行新增
insertSql = "insert into tool_convert_record (user_id,type,file_name) values (%s,%s,%s)"
insertParam=(1,1,"测试.pdf")
insertRow = cursor.execute(insertSql,insertParam)
print(f"新增入表执行的行数:{insertRow}")
# 提交事务(增删改)
conn.commit()
# 关闭连接
conn.close()

7.3修改

import pymysql
# 创建连接
conn = pymysql.connect(
    host="mysql的IP",
    user="mysql的用户名",
    password="mysql的密码",
    database="mysql数据库名",
    port=3306,
    charset="utf8mb4"
)
# 创建游标
cursor = conn.cursor()
# 执行修改
updateSql = "update tool_convert_record set finish_flag=2,update_time=now() where id=(%s)"
updateParam=(9)
updateRow = cursor.execute(updateSql,updateParam)
print(f"修改操作执行的行数:{updateRow}")
# 提交事务(增删改)
conn.commit()
# 关闭连接
conn.close()

7.4删除

import pymysql
# 创建连接
conn = pymysql.connect(
    host="mysql的IP",
    user="mysql的用户名",
    password="mysql的密码",
    database="mysql数据库名",
    port=3306,
    charset="utf8mb4"
)
# 创建游标
cursor = conn.cursor()
# 执行删除
deleteSql = "delete from tool_convert_record where id=(%s)"
deleteParam=(9)
deleteRow = cursor.execute(deleteSql,deleteParam)
print(f"删除操作执行的行数:{deleteRow}")
# 提交事务(增删改)
conn.commit()
# 关闭连接
conn.close()

7.5工具类封装

import pymysql

class DbUtil():

    conn = None

    # 获取连接
    @classmethod
    def getConn(cls):
        if cls.conn is not None:
            return cls.conn
        else:
            cls.conn = pymysql.connect(
               host="mysql的IP",
			    user="mysql的用户名",
			    password="mysql的密码",
			    database="mysql数据库名",
			    port=3306,
			    charset="utf8mb4"
            )
            return cls.conn

    # 关闭连接
    @classmethod
    def closeConn(cls):
        if cls.conn is not None:
            cls.conn.close
            cls.conn = None

    # 单个查询
    @classmethod
    def findOne(cls,sql):
        result = None
        try:
            conn = cls.getConn()
            cursor = conn.cursor()
            cursor.execute(sql)
            result = cursor.fetchone()
        except Exception as e:
            print(f"findOne执行失败:{e}")
        finally:
            cls.closeConn()
            return result

    # 查询全部
    @classmethod
    def findAll(cls, sql):
        result = None
        try:
            conn = cls.getConn()
            cursor = conn.cursor()
            cursor.execute(sql)
            result = cursor.fetchall()
        except Exception as e:
            print(f"findAll执行失败:{e}")
        finally:
            cls.closeConn()
            return result

    # 增删改
    @classmethod
    def crud(cls, sql):
        # 执行sql影响的行数
        affectLine = 0
        try:
            conn = cls.getConn()
            cursor = conn.cursor()
            # 执行sql
            affectLine = cursor.execute(sql)
            # 提交事务
            cls.conn.commit()
        except Exception as e:
            print(f"crud执行失败:{e}")
            cls.conn.rollack()
        finally:
            cls.closeConn()
            return affectLine

if __name__ == '__main__':
    # 查询全部
    result = DbUtil.findAll("select * from tool_convert_record")
    print(result)
    # 新增记录
    userId = 2
    type = 3
    fileName = "202311142159.pdf"
    # 新增记录方式一
    sql = "insert into tool_convert_record (user_id,type,file_name) values (%d,%d,\"%s\")" % (userId, type, fileName)
    # 新增记录方式二
    sql = f"insert into tool_convert_record (user_id,type,\"file_name\") values ({userId},{type},{fileName})"
    affectLine = DbUtil.crud(sql)
    print(f"影响行数:{affectLine}")
    # 执行修改
    fileName = "20231113"
    id = 8
    sql = "update tool_convert_record set file_name=%s,update_time=now() where id=%s" % (fileName, id)
    affectLine = DbUtil.crud(sql)
    print(f"影响行数:{affectLine}")

8.常见问题

8.1 getImgUrlList() takes 1 positional argument but 2 were given

class APP:
 def getImgUrlList(requestUrl):
        print(f"执行成功")
 def buttonDownImg(self):
        requestUrl = "https://www.baidu.com"
        # 打开地址
        self.getImgUrlList(requestUrl)
if __name__ == '__main__':
    app = APP()        
    app.buttonDownImg()

报错:TypeError: APP.getImgUrlList() takes 1 positional argument but 2 were given,原因是形参中默认给到self.
def getImgUrlList(self,requestUrl)中添加self即可

8.2 Rangeerror:valid array length

    格式化网站(https://www.json.cn/)中复制内容之后提示以上错误信息,处理方式是将最外边的大括号去掉,问题原因就是不是一个json格式;另外检查key是否是双引,单引也会不识别.可以用:https://www.sojson.com/,就算是有错误也会显示结构信息.

9.浏览器F12常用功能说明

1.保存请求
     preserve log勾选之后会保存请求信息,不会随着页面重新刷新丢失
2.快速请求
     不用打开postman或其他第三方请求发送工具快速发送请求,使用方式如下:
     控制台选择请求右键选择copy as fetch
在这里插入图片描述
     从控制台直接粘贴回车即可,会发现已经重新发送请求
在这里插入图片描述
3.根据页面元素快速定位元素所在接口位置
     控制台选择任意一个请求,然后按Ctrl+f.输入搜索关键字就可以过滤出所有相关的关键字
在这里插入图片描述
4.快捷键
F8调到下个断点
F10结束当前方法执行下个方法
F11进入到方法内部执行

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卖柴火的小伙子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值