python

安装配置

安装相关

python

1.windows 版本的 下载路径 https://www.python.org/downloads/windows/

pycharm

1.安装后 pycharm 的路径 C:\Program Files\JetBrains\PyCharm 2022.3.1\bin
2.pycharm 的 破解方法 https://www.exception.site/article/1702
3.破解文件在 chrome tomorrow\python\pycharm_steup\破解pycharm

配置相关

pycharm

1.配置 不同的 虚拟 python 解释器
	1.点设置 project 下面  python Interpreter
	2.点下来箭头 点 show all 点 + 号 选 add local interpreter
	3.location 表示 虚拟的位置 base interpreter 表示你要选择的 python 的版本
	4.可以 增加 删除 修改 过滤 修改可以修改 虚拟环境的名字 只是名字而已 和 路径 解释器 本身版本无关

基本操作

pycharm

pip基操
	pip list
	pip install requests
	pip install -r requirements.txt 
	pip freeze > requirements.txt # 导出依赖
	pip uninstall requests
	pip install –upgrade requests==2.1.0 
	pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple   #指定源
	pip --version # 查看版本
常见的安装源:
	https://pypi.tuna.tsinghua.edu.cn/simple # 清华
	https://mirrors.aliyun.com/pypi/simple/  # 阿里
	https://mirrors.163.com/pypi/simple/     # 网易
	https://pypi.douban.com/simple/          # 豆瓣
	https://mirror.baidu.com/pypi/simple/    # 百度
	https://pypi.mirrors.ustc.edu.cn/simple/  # 中科大
	https://mirrors.huaweicloud.com/repository/pypi/simple/ # 华为
	https://mirrors.cloud.tencent.com/pypi/simple/ # 腾讯
快捷键:
	格式化代码:"Ctrl+Alt+L"
	注释代码:"Ctrl+/"
	复制当前行或选定的代码块:"Ctrl+D"
	剪切当前行或选定的代码块:"Ctrl+X"
	粘贴剪贴板内容:"Ctrl+V"
	撤销上一步操作:"Ctrl+Z"
	重做上一步操作:"Ctrl+Shift+Z"
	查找文件:"Ctrl+Shift+N"
	查找类、方法或变量:"Ctrl+N"
	在文件中查找文本:"Ctrl+F"
	在文件中替换:"Ctrl+R"
	在整个项目中查找文本:"Ctrl+Shift+F"
	跳转到定义:"Ctrl+左键单击"
	显示参数信息:在函数或方法后面输入"("并按下"Ctrl+P"
	运行单元测试:在测试方法上点击右键,然后选择"Run"或按下快捷键"Ctrl+Shift+F10"
	调试单元测试:在测试方法上点击右键,然后选择"Debug"或按下快捷键"Shift+F9"
	跳到新的下一行 shift + 回车

python 语法

1.变量
	1.Python是动态语言,它处理变量的概念与一般静态语言不同。静态语言如C C++当定义变量时内存就会预留空间存储变量内容。
	2.变量所使用的是参照地址的概念,设定一个变量x=10时,Python会在内存某个地址存储10,此时我们简历变量x像是一个标志,
		其内容是存储10的内存地址。如果有另一个变量y=10 则y的标志内容也是存储10的内存地址。相当于变量时名称,不是地址。
		使用内置函数id()获取变量内存地址。
	3.x = 10
		y = 10
		print(id(x)) //21430544
		print(id(y)) //21430544
	4.命名规则
		1.必须有英文字母、_下划线或中文开头,建议用英文字母。
		2.只能由英文字母、数字、_下划线或中文组成,下划线开关的变量会被特别处理。
		3.英文字母大小写敏感,Name和name是两个变量名。
		4.Python系统保留字或关键字不能当做变量名,这会让程序报错。内置函数名不建议当变量名
		5.具体命名:
			命名:
			驼峰命名
			1.appName:第一个单词首字母小写 第二个单词首字母大写
			2.AppName (class):第一个单词首字母大写,第二个单词首字母大写,以此类推
			下划线命名
			app_name :用于函数名称 用下划线连接单词名称
			APP_NAME:全大写用于常量
			小结:
			变量命名:变量,函数用下划线 类用大驼峰
			全局变量(常量):大写,多个单词用下划线连接
	5.下划线变量
		_test
		这样定义为私有变量、函数或方法,不想直接被调用时用单下划线开头
		结尾下划线例如:
		dict_
		为了避免与系统关键字或内置函数名称相同
		前后双下划线例如:
		__test__
		这是python内部保留变量或方法
		前边双下划线例如:
		__test
		私有方法或变量的命名,无法直接使用本命存取
2.多重赋值
	可以多个变量等于一个值
	可以多个变量等于多个值 左右必须个数对称
	x = y = z = 10
	a, b = 10, 4
	print(x, y, z)
	print(a, b)
3.删除变量
	如果某个变量不再需要,可以使用del将其删除,并回收内存空间
		x = 1
		del x
		print(x) // 报错 UnboundLocalError: local variable 'x' referenced before assignment
4.常量
	与变量相反,常量是不可变的量
	但是在Python中,没有严格意义上的常量(constant)概念,即不能直接声明一个不可更改的值。
	然而,Python约定俗成地使用全大写字母命名的变量来表示常量,以表示这些变量的值不应该被修改。
	虽然这些变量的值可以被改变,但是开发者应该遵守约定,不去修改它们。
	例如,以下是使用全大写字母命名的变量作为常量的示例:
		PI = 3.1415926
	在实际使用中,开发者应该避免修改这些被视为常量的变量,以保持代码的可读性和一致性。
5.+ - * / %
	x = 1 + 2
	print("x:", x) # 3
	y = 6 - 5
	print("y:", y) # 1
	z = 3 * 4.5
	print("z:", z) # 13.5
	k = 10 / 3
	print("k:", k) #k: 3.3333333333333335
	l = 10 % 3
	print("l:", l) #l: 1
6.连续写法
	+=	a = a + b  可以写成a += b
	-=	a = a - b   可以写成a -= b
	*=	a = a * b   可以写成a *= b
	/=	a = a / b    可以写成a /= b
	%=	 a = a % b   可以写成a %= b
	//=    a = a // b    可以写成a //= b

7.关于注释
	1.三个引号 (单 双 都可以) #

8.编码问题导致输出中文乱码
	在程序的开头写入如下代码:
	# -*- coding:utf-8 -*-
	或者
	# coding=utf-8
9.查看数据类型 type
	1.常见
		x = 10
		y = x / 3
		print(type(x)) # <class 'int'>
		print(type(y)) # <class 'float'>
		print(type(type(x))) # <class 'type'>
	2.不仅仅是变量的数据类型可以看;函数,列表,字典,元组等都可以用这个内置函数查看它的类型
		def print_hi(name):
			a = ["1", "2"] # <class 'list'>
			b = ("2",) # <class 'tuple'>
			c = [1, 2, 3] #<class 'list'>
			d = {"a": '1'} #<class 'dict'>
			def e(): #<class 'function'>
				pass
			print(type(a))
			print(type(b))
			print(type(c))
			print(type(d))
			print(type(e))
10.数据类型
	1.整数
		1.碎片知识
			整数的英文是integer,在计算机程序语言中用int表示,python和其他语言不一样,没有long,为什么呢?
			因为python3最牛逼,可以是任意值 也可以这么写
				a = 1_1_0
				print(a) # 110
			这么写的原因是?请看下边,你能一眼看出来这是多少吗?
				a = 1000000000000 等价于 a = 1_000_000_000_000 print(a) #1000000000000
		2.整数 强转函数 int()
			1.可以将一个字符串或者浮点数转换成整数
	2.浮点型
		1.强转函数 float()
		2.常见方法
			1.round(4.56,1) //4.6 保留一位小数 四舍五入
			2.is_integer(5.0) # True ; is_integer(5.1) # False
			3.is_integer(5.0) # True
			3.as_integer_ratio() 以元组的形式 返回一个小数的 分数
				1.print(0.5.as_integer_ratio()) # (1,2
				2.print(60.as_integer_ratio()) # (60,1)
	3.布尔型
		1.强转函数 bool
		2.Python中,布尔值是True和False 就python首字母大写!其他都是小写
		3.可以转换所有数据类型!包括列表字典元组,也不能说转换吧,他会输出True或者False
			如果定义的数据为空或者0  他就是输出False 反之则True
				print(bool("0") )#True
				print(bool([0])) #True
				print(bool({"a": 0})) #True
				print(bool((0,))) #True
				print(bool((0))) #False
				print(bool(())) #False
				print(bool({})) #False
				print(bool([])) #False
				print(bool(0))  #False
				print(bool(None)) #False
		4.逻辑运算符
			1.and or not
	4.字符串 str()
		0.字符串函数
			1.len
			2.字符串切片
				1.关于索引 正数 0 1 2 3 最后一个是 -1 -2 -3 -4
				2.一些切片的列子
					name = 'ab宇哥不是说相声的'
					print(len(name)) #10
					print(name[0]) #a
					print(name[-1]) #的
					print(name[0:2]) #ab 左开右闭 右边不被选中
					print(name[2:]) # 宇哥不是说相声的
					print(name[:-2]) # ab宇哥不是说相 仍然符合 右闭的特点 右边不被选中
					print(name[:2] + name[2:]) # ab + 宇哥不是说相声的
					print(name[:5] + name[5:]) # ab宇哥不 + 是说相声的
					print(name[10]) # 越界报错!因为最大索引是 9  ,IndexError: string index out of range
					print(name[2:20]) # 虽然后面越界 但是切片会自动处理 取最大数值 即可 # 宇哥不是说相声的
				3.关于切片的步长 (可以为 正数 也 可以为 负数)
					name = '宇哥不是说相声的'
					print(name[::]) # 宇哥不是说相声的
					print(name) # 宇哥不是说相声的
					print(name[0:-1:1]) # 宇哥不是说相声 默认步长是 1
					# 步长为正数
					name = '宇哥不是说相声的'
					print(name[0:-1:2]) # 宇不说声 隔一个取一个
					# 步长为负数
					name = '宇哥不是说相声的'
					print(name[6:1:-1]) # 声相说是不 等于反过来取了 字符串也是反的
					print(name[::-1]) # 的声相说是不哥宇 相当于反转字符串
			3.其他的一些函数
				a.strip()  返回去除字符串两端空格的版本。
				a.split() 将字符串按照空格分割成多个子字符串,并返回一个列表。
				a.join(iterable) 使用字符串作为连接符,将可迭代对象 `iterable` 中的元素连接成一个字符串。
				a.replace(old, new) 返回将字符串中所有出现的旧子串 `old` 替换为新子串 `new` 的版本。
				a.find(substring) 查找子串 `substring` 在字符串中第一次出现的索引位置,找不到返回 -1。
				a.count(substring) 统计子串 `substring` 在字符串中出现的次数。
				a.startswith(prefix)  检查字符串是否以指定前缀 `prefix` 开头,返回布尔值。
				a.endswith(suffix)  检查字符串是否以指定后缀 `suffix` 结尾,返回布尔值。
				a.lower() 返回字符串的小写。
				a.upper() 返回字符串的大写。
				a.capitalize() 返回字符串的首字母大写版本。
				a.title() 返回字符串中每个单词的首字母大写版本。
				a.islower() 检查字符串中的字母是否都是小写。
				a.isupper() 检查字符串中的字母是否都是大写。
				a.isdigit() 检查字符串是否只包含数字字符。
				a.isalpha() 检查字符串是否只包含字母字符。
				a.isnumeric()  检查字符串是否只包含数字字符(包括Unicode字符)。
				字符串更多方法参考文档:https://docs.python.org/zh-cn/3.9/library/stdtypes.html#string-methods
			4.print 函数
				1.print(value,...,sep=" ",end="\n",file=sys.stdout,flush=False)
					1.参数意义如下:
						value:表示想要输出的数据
						sep:当输出多个数据时,可以插入各个数据分隔字符,默认是一个空格。
						end:当数据输出结束时所插入的字符,默认回车。
						file:数据输出的位置。默认是sys.stdout,也就是屏幕,可以使用此设定输出导入其他文件或设备
						flush:是否清除数据流的缓冲器,预设是不清除
					2.比如 下面两个 会输出到一行 1 2 abc
						print("1","2",end = "\t")
						print("a","c",sep = "b")
				2.格式化输出 %输出
					1.常见的 %
						%s 格式化字符串输出
						%d 格式化整数输出
						%f 格式化浮点数输出
						%c 字符
						%u 无符号十进制整数
						%o 格式化8进制整数输出
						%x 格式化16进制整数输出
						%X 格式化大写16进制整数输出
						%e 科学计数法小写e
						%E 格式化科学计数法大写E的输出
						%g %f和%e的简写
						%G %f和%E的简写
					2.常见例子
							a = "123" ; print("%s 这是一个字符串格式化输出" % a) # 123 这是一个字符串格式化输出
							print("%d 这是一个整数格式化输出" % 111) #111 这是一个整数格式化输出
							print("这是多个格式化输出:整数:%d,字符串:%s" % (123,'www')) #这是多个格式化输出:整数:123,字符串:www
							text = "这是一个测试格式化输出的变量,字符串:%s,%s" % ("hello1","world") #这是一个测试格式化输出的变量,字符串:hello1,world
							text2 = "这是一个测试格式化输出的变量,字符串:%s"  ; print(text2 % "hello2") #这是一个测试格式化输出的变量,字符串:hello2
				3.{}和format() print("...输出格式区...".format( 变量系列区, ...))
					1.一些列子
						print("大爷!您今儿吃什么?,大爷说:吃{},{},{}".format("翔1","翔2","翔3")) #大爷!您今儿吃什么?,大爷说:吃翔1,翔2,翔3
						print("大爷!您今儿吃什么?,大爷说:吃{2},{1},{0}".format("翔1","翔2","翔3")) #大爷!您今儿吃什么?,大爷说:吃翔3,翔2,翔1
						#在format里边赋值
						print("大爷!您今天吃什么?,大爷说:吃{a},{b},{c}".format(a="翔1", b="翔2", c="翔3")) #大爷!您今天吃什么?,大爷说:吃翔1,翔2,翔3
				4.f-strings格式化字符串 在Python3.6x版后有一个改良format格式化方式,称f-strings
					name = "yuge"
					work = "dsb"
					print(f"{name}天天{work}") # yuge天天dsb

					name = "yuge"
					work = "dsb"
					print(f"{name=}天天{work=}") #name='yuge'天天work='dsb'
		1.碎片知识
			设定空字符串 x = str() x = str("ABC") # 同 x = "ABC"
			强制转换 x = str(123)  # 这里的123是int类型
		2.字符串拼接
			x = "hello"
			y = "world"
			print(x + "," + y + "!!!")
		3.多行字符串
			1.三个引号
				str3 = "你大爷还是你大爷。" \
					   "你大妈还是你大妈"
				print("str3:",str3)

				str4 = ("你大爷还是你大爷"
							"你大爷还是你二大爷")
				print("str4:",str4)
		4.转义字符
			1.例子
				print("Hello\nWorld")  # 输出两行,Hello和World分别位于不同行
				print("This is a\ttab")  # 输出带有制表符的文本
				print("She said, \"Hello!\"")  # 输出包含双引号的字符串
				print('He\'s happy')  # 输出包含单引号的字符串
				print("C:\\path\\to\\file")  # 输出包含反斜杠的字符串路径
			2.字符串加r 取消 转义 print(r"abc\nvvv") # abc\nvvv
		5.字符串相乘
			1.可以重复输出n次字符串 print("=" * 100)
	5. bytes数据
		1.碎片
			1.字节集的创建
				1.在Python中,bytes()是一个内置函数,用于创建一个不可变的字节对象。bytes()函数可以接受不同类型的参数,
					1.并将其转换为字节对象
				2.创建空的字节对象:empty_bytes = bytes() 下面两个等价:
					str_bytes = bytes("Hello", encoding="utf-8") # type 后 显示 <class 'bytes'>
					str_bytes1 = b"Hello" # type 后 显示 <class 'bytes'>
				3. 从可迭代对象创建字节对象:iterable_bytes = bytes([72, 101, 108, 108, 111]) # hello
				4. 从十六进制字符串创建字节对象 hex_bytes = bytes.fromhex("48656c6c6f")
							hex_bytes = bytes.fromhex("48656c6c6f")
							print(str(hex_bytes, "utf8")) #hello
				5.从已有的字节对象创建新的字节对象:existing_bytes = bytes(b"Hello")
		2.字节集可以转字符串
			iterable_bytes = bytes([72, 101, 108, 108, 111])
			print(str(iterable_bytes, 'utf-8')) # hello 可以把字节集转为 字符串 

			iterable_bytes1 = [72, 101, 108, 108, 111] #不可以直接把 list 转为字符串
			print(str(iterable_bytes1, 'utf-8')) # 这里报错 TypeError: decoding to str: need a bytes-like object
	6.数据类型总结
		几种数据类型:                                  转换用内置函数
			int类型:整数,如:1234567                   int()
			float类型:浮点数,小数,如:3.1415            float()
			String类型:字符串 如:'123' "321"            str()
			Bool类型:布尔类型 如:True False             bool()
			List类型: 列表 如:['哈哈','呵呵']             list()
				1.切片:	起始索引:结束索引:步长
					pc_list = ["爬虫","逆向","前端","后端","框架"]
					print(pc_list[0])
					print(pc_list[-1])

					pc_list = ["爬虫","逆向","前端","后端","框架"]
					print(pc_list[0:-1:2])
					print(pc_list[::-1]) # 反转
				2.append() al.append("22222") 末尾增加一个元素
				3.insert() al.insert(2,"这是三")
				4.extend() 将可迭代对象的元素分别插入到列表末尾
					al = [1, 2, "3", "4", 5, 6]
					al.extend(["123","333","444"])
					print(al) //[1, 2, '3', '4', 5, 6, '123', '333', '444']
				5.copy() 浅拷贝 复制列表
					fruits = ["apple", "banana", "orange"]
					fruits_copy = fruits.copy()
					print(fruits_copy)  // 输出: ["apple", "banana", "orange"]
				6.mergin = [1,2] + [3,4] 也属于浅拷贝
				7.List1 * 2 列表元素成倍增加
				8.len(List1) 列表长度
				9.remove() al.remove("3")
				10.pop() 删除指定位置的元素,如果不传参数,则删除最后一位
					al = [1, 2, "3", "4", 5, 6]
					al.pop(0)
					al.pop(-1)
					print(al) // [2, '3', '4', 5]
				11.clear() a.clear() 清空
					1.同样可以重新赋值达到清空的效果 a = []
				12.del语句
					a  = ["1","2","3",["4","5"]]
					del a[1] // ['1', '3', ['4', '5']]
					print(a)
					// 同上 清空
					del a[:]
					print(a) // []
				13.index()
					al = [1, 2, "3", "4", 5, 6]
					res = al.index(2) // 1
				14.count() 统计指定元素在列表中出现的次数
					name_list = ["小王","小张","小刘","小王吧","小王"]
					name_list_count = name_list.count("小王")
					print(name_list_count) //2
				15.sort() 排序 默认升序
					fruits = ["apple", "banana", "orange"]
					fruits.sort()
					print(fruits)  # 输出: ["apple", "banana", "orange"]

					a = [2,35,1,123,35,6]
					a.sort(reverse=False) # 是否反转,False就是正序
					a.sort(reverse=True)
					print(a)
				16.reverse() 反转列表 同[::-1]
					fruits = ["apple", "banana", "orange"]
					fruits.reverse()
					print(fruits)  # 输出: ["orange", "banana", "apple"]

					a  = ["1","2","3",["4","5"]]
					a[0:2] = "3","2","1" # ["3","2","1"]
					print(a) # ['3', '2', '1', '3', ['4', '5']]
					a  = ["1","2","3",["4","5"]]
					a[0:2] = "321"
					print(a) # ['3', '2', '1', '3', ['4', '5']]
					a[0] = "11111"
					print(a) # ['11111', '2', '1', '3', ['4', '5']]
				17.in 和not in in 判断一个元素是否在列表里返回布尔 
					a = ["1","2","3"]
					b = "1" in a
					c = "1" not in a
					print(b) # True
					print(c) # False
				18.is  ,is not
					a = 3
					print(a is 3) #True
					print(a is not 3) #False
				19.可循环
					l = []
					for i in ["hello","world"]:
						if i == "hello":
							l.append(i)
					print(l) #['hello']
				20.join 严格来说属于字符串的功能
					txt = ""
					l = ["hello","world","宇哥","爬虫"]
					print(txt.join(l)) # helloworld宇哥爬虫
					txt = ","
					l = ["hello","world","宇哥","爬虫"]
					print(txt.join(l)) # hello,world,宇哥,爬虫
				21.列表嵌套
					a = [1,2,3,4,5,[6,7,8]]
					print(a[5]) # [6,7,8]
					print(a[5][0]) # 6
			Dict类型:字典 如:{'a':'b'}                   dict()
				1.访问
					pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
					print(pc_dict["name1"]) #ppl
					print(pc_dict.get("name1")) #ppl
				2.keys()
					pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
					k = pc_dict.keys()
					print(type(k)) # <class 'dict_keys'>
					print(k) # dict_keys(['name1', 'name2', 'name3'])
				3.values()
					pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
					v = pc_dict.values()
					print(v) # dict_values(['ppl', 'pry', 'yuge'])
				4.items()
					pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
					kv = pc_dict.items()
					print(kv) # dict_items([('name1', 'ppl'), ('name2', 'pry'), ('name3', 'yuge')])
				5.get()
					pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
					aaa = pc_dict.get("aaa","bbb") # 不存在返回bbb
					print(aaa)
				6.pop()
					pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
					res1 = pc_dict.pop("name1")
					res2 = pc_dict.pop("123123","不存在")
					print(res1,res2) # ppl 不存在
					print(pc_dict) # {'name2': 'pry', 'name3': 'yuge'}
				7.update()
					1.将另一个字典中的键值对更新到当前字典中。如果键存在,则会覆盖对应的值;如果键不存在,则会添加新的键值对
						pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
						pc_dict.update({"name1":"ndy"})
						print(pc_dict)
					2.直接定义更新 pc_dict["name1"] = "ndy" # 有就更新没有就添加
				8.clear() del copy() len() 和 List中的用法相同 参考上面
				9.遍历
					pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
					for k,v in pc_dict.items():
						print(f"key:{k}")
						print(f"value:{v}")

					获取key
						pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
						for k in pc_dict.keys():
							print(f"key:{k}")

					// 什么都不加默认是key
						pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
						for k in pc_dict:
							print(f"key:{k}")

					// 获取value
						pc_dict = {"name1":"ppl","name2":"pry","name3":"yuge"}
						for v in pc_dict.values():
							print(f"value:{v}")
				10.字典推导式
						pc_dict = {k:v for k,v in  {"name1":"ppl","name2":"pry","name3":"yuge"}.items() if v == "ppl"}
						print(pc_dict) #{'name1': 'ppl'}
				11.enumerate会返回数据的index
						pc_dict = {k:v for k,v in  enumerate(["ppl","pry","yuge"])}
						print(pc_dict) # {0: 'ppl', 1: 'pry', 2: 'yuge'}
				12.字典嵌套
					pc = {"name": "sb56", "age": 100, "国籍": "xrz",
						  "额外": {"name": "23333",
								"name1": {
									 "name": "zs",
									 "name1": "li",
									}
								 }
						  }
					for k,v in pc["额外"]["name1"].items():
						 print(k,v) # name zs name1 li
			set类型:集合 如:{123,321321,4244,5432546}   set()
				1.一种无序且不重复的数据集合
					pc = {"爬虫","爬虫","JS逆向"} # 即使定义了相同数据,他也不会输出,因为是不重复的
					print(pc) # {'爬虫', 'JS逆向'}
				2.几个特性:
					无序性:集合中的元素是无序的,不能通过索引访问或修改特定位置的元素。
					唯一性:集合中的元素是唯一的,不会出现重复的元素。如果尝试向集合中添加已经存在的元素,集合不会发生改变。
					可变性:集合是可变的,可以添加、删除和修改元素。
					不可哈希性:集合本身是不可哈希的,因此不能作为字典的键或其他集合的元素
				3.定义
					pc = set()
					pc = {1,2,3,4,5,"爬虫"}
				4.取值 无序所以不能取 因为没有索引,而且元素也是唯一,通常用一下方式进行判断
					1.用in 来判断这个值是不是在集合里边
					2.遍历 为什么数字就有序,字符串就无序
				5.add pc.add("devtools")
				6.update pc1.update(pc2, pc3)
				7.remove() pc.remove("devtools") # 不存在会报错KeyError
				8.discard() 移除元素 和 remove 类型 pc.discard("sb56") # 重复删除或者删除了不存在的元素不会报错
				9.pop() 随机删除元素
				10.clear() 清空元素 pc.clear()
				11.copy() pc3.copy() 浅拷贝
				12.union() 或 | 并集 找出两个或多个集合的并集 就是两个集合加一起去掉重复的
						pc1 = {"爬虫","逆向","JS语言","Python语言","sb56"}
						pc2 = {"爬虫","逆向","JS","Python","sb"}
						print(pc1 | pc2) #{'JS', '逆向', 'sb56', 'Python', 'JS语言', 'Python语言', '爬虫', 'sb'}
						print(pc1.union(pc2)) #{'JS', '逆向', 'sb56', 'Python', 'JS语言', 'Python语言', '爬虫', 'sb'}

						print(pc1|pc2|pc3)
						print(pc1.union(pc2,pc3))
				13.intersection() 或 & 交集
						pc1 = {"爬虫","逆向","JS语言","Python语言","sb56"}
						pc2 = {"爬虫","逆向","JS","Python","sb"}
						print(pc1 & pc2) # {'爬虫', '逆向'}
						print(pc1.intersection(pc2)) # {'爬虫', '逆向'}
				14.difference() 或 - 前边集合有的后边集合没有的  取差集
						pc1 = {"爬虫","逆向","JS语言","Python语言","sb56"}
						pc2 = {"爬虫","逆向","JS","Python","sb"}
						print(pc1 - pc2) #{'sb56', 'Python语言', 'JS语言'}
						print(pc1.difference(pc2)) #{'sb56', 'Python语言', 'JS语言'}
						# 反过来结果不同
						print(pc2 - pc1) #{'sb', 'JS', 'Python'}
						print(pc2.difference(pc1)) #{'sb', 'JS', 'Python'}
				15.symmetric_difference() 或 ^ 对称差集 两个集合中不重复的元素的集合。
					1.对称差集包括了两个集合中除了交集部分之外的所有元素。换句话说,对称差集是两个集合的并集减去交集
						pc1 = {"爬虫","逆向","JS语言","Python语言","sb56"}
						pc2 = {"爬虫","逆向","JS","Python","sb"}
						print(pc1 ^ pc2) #{'Python', 'JS', 'sb56', 'Python语言', 'sb', 'JS语言'}
						print(pc1.symmetric_difference(pc2)) #{'Python', 'JS', 'sb56', 'Python语言', 'sb', 'JS语言'}
				16.isdisjoint() 判断两个集合的相同元素 没有返回 True 有一个相同的就返回 False
					pc3 = {"爬虫","爬爬乐"}
					pc4 = pc3.copy()
					print(pc4.isdisjoint(pc3)) #False

					pc1 = {"爬虫1","爬爬乐1"}
					print(pc1.isdisjoint(pc3)) #True
				17.issubset() 判断当前集合是否是另一个集合的子集 子集:一个集合内的所有元素被另一个集合所包含
					pc1 = {"爬虫","逆向","JS语言","Python语言","sb56"}
					pc2 = {"爬虫","逆向","JS","Python","sb"}
					pc3 = {"爬虫","逆向"}

					print(pc3.issubset(pc1)) #True
					print(pc3.issubset(pc2)) #True
					print(pc2.issubset(pc3)) #False
				18.issuperset() 用于判断当前集合是否是另一个集合的超集
					1.超集:如果一个集合A包含了另一个集合B的所有元素,那么集合A被称为集合B的超集。
						换句话说,集合A至少拥有集合B中的所有元素,可能还包含其他元素
						pc1 = {"爬虫","逆向","JS语言","Python语言","sb56"}
						pc2 = {"爬虫","逆向","JS","Python","sb"}
						pc3 = {"爬虫"}
						print(pc1.issuperset(pc3)) #True
						print(pc3.issuperset(pc2)) #False
						print(pc2.issuperset(pc3)) #True
				19.集合推导式
					1.将集合中的元素字符全变大写并且生成一个新的集合
						pc = {'sb56','halou','pc'}
						pc = {x.upper() for x in pc}
						print(pc) #{'SB56', 'HALOU', 'PC'}
					2.创建一个20以内单数集合
						seq = {x for x in range(1, 20) if x % 2 == 1} 
						print(seq) # {1, 3, 5, 7, 9, 11, 13, 15, 17, 19}
			Tuple类型:元组 如:(1,) (1,2,3,4,5,6) ('11','22')  tuple()
				1.元组的定义
					pc1 = ()
					pc2 = tuple()
					print(pc1,pc2) # () ()
					print(type(pc1),type(pc2)) # <class 'tuple'> <class 'tuple'>
				2.一个变量赋值多个值就会被打包成元组
					pc = "爬虫","逆向","JS"
					print(pc) # ('爬虫', '逆向', 'JS')
				3.取值
					1.切片 唯一不同的是 不能发生变化 也就是不能赋值
					2.遍历 for 不支持 for k,v in my_tuple
						my_tuple = (1, 2, 3)
						for item in my_tuple:
							print(item) # 1 2 3
				4.count() 取某个数值的个数
					pc = "爬虫","逆向","JS","爬虫"
					res = pc.count("爬虫")
					print(res) // 2
				5.index() 返回第一个出现的值的索引/下标
					pc = "爬虫","逆向","JS","爬虫"
					res = pc.index("爬虫")
					print(res) // 0
				6.len() 统计个数
					pc = "爬虫","逆向","JS","爬虫"
					print(len(pc)) // 4
				7.sorted(iterable, key=None, reverse=False) key 就是排序的函数
					1.排序并返回列表sorted() 适用于列表,元组,字典,字符串等可迭代对象
						my_list = [3, 1, 2, 5, 4]
						sorted_list = sorted(my_list)
						print(sorted_list)  # 输出: [1, 2, 3, 4, 5]

						my_tuple = (3, 1, 2, 5, 4)
						sorted_tuple = sorted(my_tuple)
						print(sorted_tuple)  # 输出: [1, 2, 3, 4, 5]

						my_string = "hello"
						sorted_string = sorted(my_string)
						print(sorted_string)  # 输出: ['e', 'h', 'l', 'l', 'o']
						# 按照绝对值排序
						my_list = [-3, 1, -2, 5, -4]
						sorted_list = sorted(my_list, key=abs)
						print(sorted_list)  # 输出: [1, -2, -3, -4, 5]
				8.最大值 max() 最小值 min()
						pc1 = (1,2,3,7,8,9,4,2,1)
						print(max(pc1)) // 9
						print(min(pc1)) // 1
				9.元组推导式
						sb56 = (x**2 for x in range(1, 6))
						print(sb56) #<generator object <genexpr> at 0x01A874C0>
						print(tuple(sb56)) #(1, 4, 9, 16, 25)

						strings = "爬虫爬数据,数据用爬虫爬"
						pc = tuple(char for char in strings if char == "爬")
						print(pc) #('爬', '爬', '爬', '爬')

11.文件操作
	1.open (open()是python中内置的函数,功能是打开一个文件,进行增删查改等操作)
		1.碎片
			1.知识
				file_obj = open(file_name,mode="r")
				file_name 就是文件名,如果不存在则会创建,不指定路径就在当前路径下
				mode就是打开文件的模式,r是读,w是写,a是追加,b则是打开二进制时需要添加的模式,
				x是打开一个新文件,如果打开的文件已经存在会报错,t打开文本文件模式(默认)
					r	只读,默认模式,文件不存在就报错
					w	只写,文件存在会覆盖内容,不存在则创建
					a	写追加,打开文件用于追加内容。如果文件不存在,会创建新文件。
					x	独占创建模式。打开文件用于写入,只能创建新文件,如果文件已存在则会引发 FileExistsError。
					b	二进制模式。以二进制格式打开文件。(图片,视频等)
					t	文本模式(默认)。以文本格式打开文件。
					+	读写模式。同时支持读取和写入操作。
					经常用的w+,a+,r+,rb,wb等
		2.常见用法
			1.print()输入到文件内(你们肯定没玩过,一般老师不会讲,因为知识点没这么宽)
				file_obj = open("1.txt",mode="w")
				print("dsadadsa",file=file_obj)
				file_obj.close() # 玩完了别忘了关闭
			2.write方法写数据到文件
				file_obj = open("1.txt",mode="w")
				file_obj.write("111111111111111111")
				file_obj.close()
			3.writelines 方法 这里如果是 write 会提示 TypeError: write() argument must be str, not list
				lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
				with open("example.txt", "w") as file:
					file.writelines(lines)
			4.writable()用于检查文件是否可写,返回布尔值
				with open("example.txt", "r") as file:
					print(file.writable())  # False
				with open("example.txt", "w") as file:
					print(file.writable())  # True
			5.read 读
				file_obj = open("1.txt",mode="r")
				txt = file_obj.read()
				print(txt)
				file_obj.close() # 关闭文件,不关闭会占用文件句柄
			6.readline() 逐行读
				1.readline() 方法用于逐行读取文件内容。每次调用 readline() 方法
					它会读取文件中的一行,并将其作为一个字符串返回。连续调用 readline() 方法可以逐行遍历文件的内容。
				file_obj = open("1.txt",mode="r")
				txt = file_obj.readline()
				txt1 = file_obj.readline()
				print(txt,txt1)
				file_obj.close()

				//去掉\n
				file_obj = open("1.txt",mode="r")
				txt = file_obj.readline().strip()
				print(txt)
				file_obj.close()
			7.readlines()
				1.方法用于一次性读取整个文件的所有行,并将每一行作为一个字符串存储在一个列表中返回。
					列表中的每个元素对应文件中的一行。
				file_obj = open("1.txt",mode="r")
				txt = file_obj.readlines()
				print(txt) # 存入列表中
				file_obj.close()

				// for循环遍历
				file_obj = open("1.txt",mode="r")
				for i in file_obj.readlines():
					print(i.strip())
				// txt = file_obj.readlines()
				// print(txt) # 存入列表中
				file_obj.close()
			8.readable() 用于检查文件是否可读,返回布尔值
			9.seek 指针定位seek
				1.file.seek(offset[, whence])
				2.offset参数表示偏移量,即指针要移动的字节数,可以是正数或负数;whence参数表示起始位置,可以是以下值之一:
					 1. 0:从文件开头开始偏移,默认值;
					-2. (0,1):从当前位置开始偏移;
					-3. (0,2):从文件末尾开始偏移。
					-4. 负数 :从文件末尾往开头(-1,2) 或这从当前位置往开头(-2,1)
							with open("1.txt", "a+") as file:
								# 用 with 不用主动关闭文件 自己会关闭 下面直接拿file操作
								# 读取文件的前5个字符
								print(file.read(5))  # "abcdefg"
								# 将指针移动到文件开头
								file.seek(0)
								# 读取整个文件内容
								print(file.read())  # "all file"
								# 将指针移动到文件末尾
								file.seek(0, 2)
								# 写入新的内容
								file.write("\nNice to meet you!")
								# 将指针移动到文件开头
								file.seek(0)
								# 读取整个文件内容
								print(file.read())
					5.需要注意的是,在使用 seek()方法改变指针位置之前,必须以读取模式或读写模式打开文件。
						如果文件以写入模式打开,使用 seek() 方法改变指针位置会导致文件内容被截断。
				3.关于负偏移量
					1.需要注意的是,在使用 seek()方法改变指针位置之前,必须以读取模式或读写模式打开文件。
						如果文件以写入模式打开,使用 seek() 方法改变指针位置会导致文件内容被截断。
					2.seek()方法的负偏移量或相对于末尾的位置在文本模式下是不被允许的。这是因为在文本模式下,
						文件的字节偏移与字符的解码方式有关,而负偏移量或相对于末尾的位置可能会导致无法正确解码字符。
					3.如果你需要在文本模式下进行定位操作,可以考虑使用其他方法,比如逐行读取文件并跟踪行号,
						或者使用tell()方法获取当前文件指针的位置。
					4.请注意,在以二进制模式('rb'、'wb'、'ab'等)打开文件时,seek()方法可以使用负偏移量或相对于末尾的位置
						进行定位操作。这是因为在二进制模式下,文件的字节偏移是明确的,不受字符解码的影响。
				5.with语句
					1.使用 with 语句可以确保文件在使用完后自动关闭,无需显式调用 close() 方法。
						with open("1.txt",mode="r") as f:
							text = f.read()
							print(text)
12.输入 input()
		1.input函数功能与print()函数功能相反,这个函数会从屏幕读取用户从键盘输入的数据
			value = input("请输入一个爹:")
			//value是变量,所输入的数据会存储到这个变量中,input接收你输入的无论是字符串或者数字,一律为字符串类型,
				如果要执行数学运算需要int()转换为整形。
			//input里边的字符串是提示内容,对于输入的内容不影响
			print(f"类型为:{type(value)},{value}") #类型为:<class 'str'>,my
13.流程控制
	1.if elif else
		if x>3:
			print("x is greater than 3")
		elif x<3:
			print("x is less than 3")
		else:
			print("x is equal to 3")
	2.三元运算符
		1.you = '学爬虫' if nx > 0 else '学个毛'
		2.嵌套三元运算
			1.you = '学爬虫' if nx > 1 else '学个毛' if nx < 0  else '人才啊'
            2.等价于:
                if nx > 1:
                    you = '学爬虫'
                elif nx < 0:
                    you = '学个毛'
                else:
                    you = '人才啊'
    3.流程控制-循环语句for
        1.关键字 for x in y:
            for 是关键字
            x 是变量名
            in 是关键字 
            y 是一个可迭代对象类型
                range() 内置函数,用于生成一个整数序列,常用于循环的对象
                    range() 用于生成一个整数序列。最多接收三个参数。常用与for循环
                    第一个参数,起始值
                    第二个参数,结束值
                    第三个参数,步长
                列表
                元组
                字符串
                集合
                字典
      2.基本操作
          循环字符串
              message = "Hello, wocao!"
              for i in message:
                  print(i)
          循环列表
                hi = ["hello", "world", "wocao"]
                for h in hi:
                    print(h)
          循环字典
              person = {"name": "yg", "age": 30, "city": "BJ"}
              for key in person:
                  print(key)
              person = {"name": "yg", "age": 30, "city": "BJ"}
              for key, value in person.items():
                  print(key, value)
          循环集合
              p = {'hello',233,'world','wocao'}
              for i in p:
                  print(i)
          循环元组
              y = (1,2,3,4,5,6)
              for i in y:
                  print(i)
          支持多个变量循环
              a = ['1','2']
              b = ['3','4']
              for j,k in a,b:
                  print(j)
                  print(k)
          嵌套循环
              for i in range(10):
                  for j in range(10): 
                      print('j',j)
        3.break 和 continue 同其他语言
  4.while 语句
      while True:
          print("hello world")
14.函数
	1.格式定义
		def 函数名(参数1,参数2,参数n):
			"""函数批注"""
			程序代码                    # 缩进
			return 返回值
	2.解释
		关键字:def
		函数名:必须写而且唯一,后边必须加小括号,因为后续程序需要调用,命名规则和变量相同,
			按照PEP8的话建议第一个英文字母用小写
		参数:可有可无,根据程序需要是否传入参数进行处理,参数调用逗号分开。
		函数批注:可有可无,大型程序设计时建议添加批注,比如写参数传的类型,函数的功能等三个单引号和三个双引号都可以,
			可以是多行批注,写了就比较专业!
		return:可有可无,如果没有return的话,调用赋值打印只会输出一个None,所以我们每个函数应该有返回值,方便调用也方便调试。
	3.简单的函数
		def myPrint(txt):
			print(f"txt:{txt}")

		def url1(btm_ppre,bb,cc="cc.00"):
			url = "https://abc.com/control?"
			res = f"{url}btm_ppre={btm_ppre}&bb={bb}"
			return res

		url = url1("a0.b0.c0.d0","bb.bb") # 动态传参
	4.关键词参数 参数名=值 可以不按顺序传参 但是要以这种格式
		1.url = url1(bb="bb.bb",btm_ppre="a0.b0.c0.d0") # 动态传参
		2.默认传参 def url1(btm_ppre,bb,cc="cc.00") // cc 有个默认的数值 可以传可以不传
	5.指定参数类型(注解)
			1.可以让写代码的人和调用代码的人注意,应该传什么类型,代码并不会真的去验证,只是写代码的时候会变黄,规范性写法
			2.def url1(page: int, btm_ppre: str, btm_prem: str, btm_show_id: str) -> None:
					def url1(*pc):
						print(pc)
					url1("爬虫","JS","Python") # ('爬虫', 'JS', 'Python')
				1.指定返回为None
				
	6.参数传递的不能指定默认值 args和kwargs是约定俗成的接受传参的名字,也可以写成其他的
			def url1(*args,**kwargs):
				print(args) # ('爬虫', 'JS')
				print(kwargs) #{'bb': 'Python'}
			url1("爬虫","JS",bb="Python")
	7.函数当参数传递
			def f1():
				return "实现第一个功能"
			def f2(one):
				# print(one)
				return f"{one},实现第二个功能"
			res = f2(f1()) # 这里也可以 f2(f1)) 传函数 而不执行 到函数内部执行
			print(res) # 实现第一个功能,实现第二个功能
	8.函数传参与args参数结合
			def f1(*args):
				return sum(args[0])
			def f2(func, *args):
				return func(args)
			res = f2(f1, 1, 2, 3, 4, 5, 6)
			print(res) # 21
	9.返回 多个变量 tuple , Dict
			def abc():
				return 1,2,"a","b"
			print(abc()) # (1, 2, 'a', 'b')
	10.函数的嵌套
			def c_tmd(a):
				def string(x):
					return f"传入了一个字符串:{x}"
				def ints(x):
					return f"传入了一个数字:{x}"
				def lst(x):
					return f"传入了一个列表:{x}"
				def dicts(x):
					return f"传入了一个字典:{x}"
				res = type(a)
				print(res == str) # True 这里 type 的结果居然 真等于 str 虽然 print 显示 <class 'str'>
				if res == str:
					return string(a)
				elif res == int:
					return ints(a)
				elif res == list:
					return lst(a)
				elif res == dict:
					return dicts(a)
				else:
					print("处理不了当前的传值")
			res = c_tmd("123") 
			print(res) # 传入了一个字符串:123
	11.闭包
		1.具体来说,闭包包括以下几个要素:
			1.内部函数:在某个函数内部定义另一个函数。
			2.外部函数:定义内部函数的那个原始函数。
			3.变量引用:内部函数能够通过外部函数中的变量进行操作。
			4.返回值:当你在外部函数中使用`return`语句后,通常会返回一个指向内部函数的引用。
				def outer():
					b = 10
					def inner(x):
						return b + 1 + x
					return inner
				b = 2
				f = outer()
				print(f(b))
		2.用闭包写一个计数器
				def counter(start_at=0):
					count = [start_at]
					def incr():
						count[0] += 1
						return count[0]
					return incr
				calc = counter()
				print(calc()) // 1
				print(calc()) // 2
				print(type(calc())) // <class 'int'>
	12.递归
		1.写一个阶乘函数
			def factorial(n):
				# 基础情况
				if n == 0 or n == 1:
					return 1
				# 递归情况
				else:
					return n * factorial(n - 1)
			res  = factorial(5)
			print(res)
		2.斐波那契数列
			def fibonacci(n):
				# 基础情况
				if n <= 0:
					return 0
				elif n == 1:
					return 1
				# 递归情况
				else:
					return fibonacci(n - 1) + fibonacci(n - 2)
			print(fibonacci(5))

常见模块

1.requests
	1.主要特点:
		1.简单易学
		2.功能全
		3.会话管理,可以会话保持
		4.支持上传下载
		5.支持ssl证书验证
		6.支持代理
		7.支持cookie
		8.默认自动重定向
		9.异常处理
	2.pip install requests 安装
	3.请求
		1.get requests.get() 传入参数:
			1.url
			2.headers
			3.timeout
			4.data
			5.json
			6.parmas
			7.cookies
			8.verify
			9.proxies
				proxies = {
					  "http": "http://117.80.203.24:8118",
					  }
				 requests.get("http://httpbin.org/ip",  proxies = proxies,timeout=3)

			10.allow_redirects
		2.response 无论发送什么请求都会返回一个response对象
			response.text        响应文本
				返回的字符串数据,文本数据,json数据,包括密文数据。
				根据HTTP 头部对响应的编码推测的文本编码
				response.encoding="utf-8" 修改编码
			respones.content     响应二进制数据或bytes数据
				返回视频数据,图片数据,音乐数据等二进制数据
				print(response.content.decode("utf-8"))
				print(response.content.decode())
				print(response.text)
				content.decode("utf-8")解码
			response.status_code   http响应状态码
			response.headers     响应header
			response.cookies     响应的cookie
				1.print(requests.utils.dict_from_cookiejar(response.cookies)) 把cookies转化为字典
				2.print(response.cookies.get_dict()) 同上面作用一样
			response.encoding    响应网站字符集编码 赋值是设置 不赋值是打印当前
			response.json()        如果返回json可以直接用这个方法转成字典
			response.url             返回响应的最终 URL 重定向的时候有用
			response.raise_for_status() 如果状态码不是200会抛异常 主动结束程序运行
			response.request.headers  返回请求header
			response.request.body     返回请求body
			response.request.url      返回请求url
		session 请求
			// 创建一个会话对象
			session = requests.session()
			headers = {
				'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
			}
			response = session.get('https://www.baidu.com',headers=headers)
			print(response.cookies)
			response = session.get('https://www.baidu.com', params={'key': 'value'})
			可以在会话对象中设置全局参数,如超时时间
			session.timeout = 10
			print(response.request.headers)
	4.杂项
		1.报错
			1.请求https站点报错
				ssl.CertificateError开头的报错
				添加verify=False 让请求不验证服务器ssl证书
				response = requests.get(url,verify=False)
		2.代理
			1.常见的代理网站(仅用于学习)
				66免费代理网 http://www.66ip.cn/
				89免费代理 http://www.89ip.cn/
				站大爷 https://www.zdaye.com/free/
				无忧代理 http://www.data5u.com/
				云代理 http://www.ip3366.net/
				快代理 https://www.kuaidaili.com/free/
			2.代理分类
				透明代理(Transparent Proxy):不对请求做任何修改,客户端和服务器都知道对方的存在。
				匿名代理(Anonymous Proxy):隐藏客户端的真实 IP 地址,但服务器知道请求来自代理。
				高匿代理(Elite Proxy):隐藏客户端的真实 IP 地址,服务器无法知道请求来自代理
			3.传输协议分类
				HTTP代理:只能代理HTTP流量。
				HTTPS代理:可以代理HTTPS流量,支持SSL加密传输。
				SOCKS代理:支持多种协议的代理,如HTTP、HTTPS、FTP等
		3.retry
			from retrying import retry
			@retry(stop_max_attempt_number=3) // 尝试次数
			def parse_url():
				# 超市就会报错并且重试
				print("开始请求...")
				response = requests.post("https://www.baidu.com", timeout=3)
				assert response.status_code == 200, '状态码不正确'
				return response
		4.curl 复制后 可以在 splidertools.cn 转 python
2.json
	1.dumps
		1.正常把 字典 转为 字符串
			import json
			dict1 = {
				"name": "小明",
				"age": 18
			}
			j1 = json.dumps(dict1)
			print(type(j1)) #<class 'str'>
			print(type(dict1)) #<class 'dict'>
			print(dict1) # {'name': '小明', 'age': 18} 单引号 就算定义的时候是双引号
			print(j1) # {"name": "\u5c0f\u660e", "age": 18}
		2.参数
			1.dumps配置参数
				indent 美化输出指定缩进的空格数,用于美化输出的JSON字符串。例如,indent=4表示使用4个空格缩进,默认值为None,表示不缩进。
				ensure_ascii  不适用非ascii字符转义,也就是保持中文,别把中文转成Unicode, 默认不加他会自动转成Unicode编码
				sort_keys 指定是否按照键的字母顺序对JSON对象进行排序。默认值为False,表示不排序。如果设置为True,则会按照键的字母顺序进行排序。
				separators 指定分隔符的字符,用于控制JSON字符串中各个元素之间的分隔方式。
				默认separators=(",",":")
			2.代码举例
				import json
				data = {"name": "yg", "age": 18, "techang?": "长"}
				d = json.dumps(data,indent=4,ensure_ascii=False,sort_keys=True,separators=(",",":"))
				print(d)

	2.loads
		1.从字符串loads后转为字典
			import json
			data = '{"name": "yg", "age": 18, "techang?": "chang"}'
			json_data = json.loads(data)
			print(json_data)  #{'name': 'yg', 'age': 18, 'techang?': 'chang'}
			print(type(json_data)) #<class 'dict'>
		2.从文件读取JSON数据 load 注意不是 loads
			import json
			with open("1.txt", "r") as f:
				python_obj = json.load(f)
			print(python_obj)  # {'name': 'yg', 'age': 18, 'techang': 'chang'}
			print(type(python_obj))  # <class 'dict'>
		3.将字典以 json 格式 写入 文件
			import json
			data = {"name": "yg", "age": 18, "techang": "chang"}
			with open("2.txt", "w") as f:
				json.dump(data,f)
3.pyexecjs 模块 py运行js的pyexecjs模块
	1.代码1 compile 编译后 call 调用
		import execjs
		// 创建一个运行时环境
		ctx = execjs.compile(
		这里是三个引号
		function add(x, y) {
			return x + y;
		}
		这里是三个引号
		)
		// 调用JavaScript函数
		result = ctx.call("add", 1, 2)
		print(result)  # 输出3
	2.代码2 Node 环境
		import execjs
		# 获取Node.js运行时环境
		ctx = execjs.get("Node")
		print(ctx)
		# 编写和执行JavaScript代码
		result = ctx.eval("1 + 2")
		print(result)  # 输出3
	3.代码3 runtime
		import execjs
		# 获取一个可用的 JavaScript 运行时
		runtime = execjs.get()
		# 定义一个简单的 JavaScript 代码
		js_code = """
		function add(x, y) {
			return x + y;
		}
		return add(3, 4);
		"""
		# 使用 JavaScript 运行时执行 JavaScript 代码
		result = runtime.exec_(js_code)
		print(result)  # 7
	4.代码4 runtime
		import execjs
		runtime = execjs.get()
		result = runtime.eval("1 + 2")
		print(result) # 3
		runtime = execjs.get()
		result = runtime.eval("new Date().getTime()")
		print(result) #1713191124607
	5.代码5 编译 并调用外部的 js
		import subprocess
		# 这个类需要重写一下 目的就是改变一下编码 encoding="utf-8" 否则下面的调用会报错 默认 encoding=None
		class MySub(subprocess.Popen):
			def __init__(self,*args,**kwargs):
				super().__init__(encoding="utf-8",*args,**kwargs)
		subprocess.Popen = MySub

		import execjs
		node = execjs.get()
		# 创建运行时环境
		with open("S:\project 2021\other\ChromeHelper\chrome tomorrow\逆战宇\\try\\111.js",encoding="utf-8") as f:
			js_code = f.read()
		ctx = node.compile(js_code,cwd="S:\project 2021\other\ChromeHelper\chrome tomorrow\逆战宇\\try\\node_modules")
		# 调用外部 JavaScript 文件中的函数
		data = 'aaaaaaaa'
		result = ctx.call("callByPython",data) # 调用 111.js 里面的 函数 并传入参数 data js里面的 console.log() 不会执行
		print(result) # 正常输出 UVjxz7/6x...
4.re 正则表达式模块
	1.match 匹配不到返回 None
		import re
		data = "a测试数据:123456,hello222222,world"
		res = re.match('^a.*:(\d+),.*o(\d+),.*', data)
		print(res) # <re.Match object; span=(0, 30), match='a测试数据:123456,hello222222,world'>
		print(res.group(0)) # a测试数据:123456,hello222222,world
		print(res.group(1)) # 123456
		print(res.group(2)) # 222222
		print(f"{res.span()},{res.start()},{res.end()}") #(0, 30),0,30
	2.关于分组
		1.匹配分组
			1.| 匹配符号左右任意一个表达式
			2.(ab) 小括号中的字符作为一个分组
			3.\n 引用之前的分组匹配中的规则匹配到的结果当作规则匹配
					import re
					text = "hello hello"
					pattern = r"(\w+)\s\1" #\1 引用前面的子匹配
					matches = re.match(pattern, text)
					print(matches.group(0)) # hello hello
					print(matches.group(1)) # hello
			4.(?P) 是正则表达式中用于给捕获组命名
					import re
					text = "2024-03-24"
					pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
					matches = re.match(pattern, text)
					if matches:
						print("Year:", matches.group('year')) # Year: 2024
						print("Month:", matches.group('month')) # Month: 03
						print("Day:", matches.group('day')) # Day: 24
					else:
						print("No match found.")
			5.(?P=name) 引用之前命名的捕获组
	3.关于第三个参数 正则表达式修饰符
		1.re.I 忽略大小写
		2.re.M 匹配多行
		3.re.S 。可以匹配所有 包括换行
5.time 模块
	1.代码
		import time
		ts = time.time()
		print(ts) # 1713201793.921693
		print(type(ts)) #<class 'float'>
		print(int(ts)) #1713201793 10位
		print(int(ts*1000)) #1713201793921 13位
		ts = time.localtime()
		print(ts) #time.struct_time(tm_year=2024, tm_mon=4, tm_mday=16, tm_hour=1, tm_min=22, tm_sec=24, tm_wday=1, tm_yday=107, tm_isdst=0)
		print(f"{ts.tm_year},{ts.tm_mon},{ts.tm_mday}") #2024,4,16
		print(time.mktime(ts)) #1713201793.0
		print(time.strftime("%Y-%m-%d %H:%M:%S")) #2024-04-16 01:27:36
		print(time.strptime('2018-05-10',"%Y-%m-%d")) # time.struct_time(tm_year=2018, tm_mon=5, tm_mday=10, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=130, tm_isdst=-1)
		print(time.strptime("2018-01-24 11:31:16","%Y-%m-%d %H:%M:%S")) #time.struct_time(tm_year=2018, tm_mon=1, tm_mday=24, tm_hour=11, tm_min=31, tm_sec=16, tm_wday=2, tm_yday=24, tm_isdst=-1)
		time.sleep(0.5)
6.lxml 模块 xpath
	from lxml import etree
	html = etree.HTML(text)
	# print(html) # <Element html at 0x2004fc8>
	# print(etree.tostring(html).decode("utf-8")) # 打印出网站代码
	res = html.xpath('//*') # [<Element html at 0x1f24d68>, <Element head at 0x2101528>]
	res = html.xpath('//tr/td')# [<Element td at 0x1721768>, <Element td at 0x17216c8>]
	#获取指定节点用text()方法取值
	print(res[0].xpath("./text()")) # ['\n            111.225.152.47\n        ']
	#获取子节点
	res = html.xpath("//tr[1]/td[1]/text()") # ['\n            111.225.152.47\n        ']
	#获取父节点
	res = html.xpath("//tr[1]/td[1]/../td") # 等价于 html.xpath("//tr[1]/td")
	#属性匹配
	res = html.xpath("//tr[1]/td[1]/parent::*/td[@class='ip']/text()") # parent::* 回到了 tr
	#属性获取
	res = html.xpath("//a/text()") #['去百度', '去百度1']
	res1 = html.xpath("//a/@href") # ['http://www.baidu.com', 'http://www.baidu1.com']
	#属性多值匹配 contains 和 and  or 搭配
	res = html.xpath("//a[@class=a]") # 如果有两个 class a a1 写一个匹配不到
	# res = html.xpath("//a[@class=‘a a1’]") # 这么写两个直接报错
	print("-------------------")
	res = html.xpath("//a[contains(@class,'a a1')]/text()") #['去百度'] 一个属性值还是多个属性值都可以用
	res = html.xpath("//a[contains(@class,'a')]/text()")  #['去百度'] 一个属性值还是多个属性值都可以用
	res = html.xpath("//a[contains(@name,'a2') and contains(@class,'a')]/text()") #contains 类似 寻找文本
	res = html.xpath("//a[contains(@name,'a2') and contains(@name,'a3')]/text()") # and
	res = html.xpath("//a[contains(@name,'a2') or @names='qbd']/text()") # or
	res = html.xpath("//a[not(text()='去百度')]/text()") # not 取反
	res = html.xpath("//a[last()]/text()") # 最后一个
	res = html.xpath("//a[last()-1]/text()") #倒数第二个
	res = html.xpath("//a[position()>1]/text()") # position() 位置  > < = 某个位置
	res = html.xpath("//a[position()>1 and position()<4]/text()") # 精确选择 选第2和3节点
	#条件取值 通过 [text()=] 和 [@xxx=] [@xxx!=]都可以
	res = html.xpath("//tr/td[3][text()='河北省张家口市']/text()")
	res = html.xpath("//a[@href='http://www.baidu.com']/@href")
	res = html.xpath("//a[@href!='http://www.baidu.com']/@href")
7.selenium自动化工具
	1.简介
		1.Selenium是一个用于自动化Web应用程序测试的工具。它提供了一组API(应用程序编程接口),允许开发人员以多种编程语言(如Python、Java、C#等)编写测试脚本,用于模拟用户在浏览器中的操作。这些操作可以包括点击链接、填写表单、提交数据等,从而可以对Web应用程序进行功能测试、回归测试等。
		2.Selenium支持多种浏览器,包括Chrome、Firefox、Edge等主流浏览器,可以在不同的浏览器中运行测试脚本。它还支持不同的操作系统,如Windows、Linux、macOS等。
		3.除了自动化测试外,Selenium还可以用于网页数据抓取、网页内容提取等应用场景。由于其灵活性和强大的功能,Selenium被广泛应用于软件开发和测试领域。
	2.安装
		以谷歌浏览器为例:
		新版本安装:https://chromedriver.com/
		老版本安装:https://chromedriver.storage.googleapis.com/index.html
	3.打开 python 在执行完毕代码后 chrome 浏览器会自动关闭 如果想让chrome不关闭 想办法让 py 代码一只执行
		from selenium import webdriver
		browser = webdriver.Chrome()
		browser.get("https://www.baidu.com")

		from selenium import webdriver
		from selenium.webdriver.chrome.service import Service
		CHROMEDRIVER_PATH = r"G:\Python3.9.13\chromedriver.exe"
		svc = Service(executable_path=CHROMEDRIVER_PATH)
		browser = webdriver.Chrome(service=svc)
		browser.get("https://www.baidu.com")
	4.基础语法
		1.声明浏览器对象
			from selenium import webdriver
			browser = webdriver.Chrome()
			browser = webdriver.Firefox()
			browser = webdriver.Edge()
			browser = webdriver.PhantomJS()
			browser = webdriver.Safari()
		2.访问网页
			from selenium import webdriver
			browser = webdriver.Chrome()
			browser.get("https://www.baidu.com")
			browser.get("https://spidertools.cn/#/curl2Request")
			browser.get("https://extfans.com/search/?q=listen")
		3.查找element对网页进行操作
			1.基本用法
				from selenium.webdriver.common.by import By
				from selenium import webdriver
				browser = webdriver.Chrome()
				browser.get("https://www.baidu.com")
				# find_element是查询一个 send_keys 在标签内输入 
				browser.find_element(By.NAME,'wd').send_keys("python")
				# .click() 点击当前标签
				browser.find_element(By.ID,"su").click()
			2.这里还可以不用By.xx因为这只是一个字符串的对应关系
				ID = "id"
				XPATH = "xpath"
				LINK_TEXT = "link text"
				PARTIAL_LINK_TEXT = "partial link text"
				NAME = "name"
				TAG_NAME = "tag name"
				CLASS_NAME = "class name"
				CSS_SELECTOR = "css selector"
				browser.find_element("name",'wd').send_keys("python")
			3.元素定位
				1.找到元素后 不能用 /text() 取文本 要用自己的方法
						res = browser.find_element(By.XPATH,"//tr/td[1]")
						print(res.get_attribute("class")) # 取类名
						res1 = res.get_attribute("innerHTML") # 取元素代码
						res1 = res.get_attribute("innerText") # 取元素文本

		4.截屏
			1.browser.get_screenshot_as_file('bd.png')) 全屏幕截图
			2.form1.screenshot("form1.png")#给这个元素截图

		5.关闭浏览器
			browser.quit() # 退出
			browser.close()# 关闭
		6.cookie操作
			1.获取cookie
				1.browser.get_cookies()
					1.区别get_cookies()直接调用 会返回一个cookis的json 列表套字典
						[{'domain': 'www.baidu.com', 'httpOnly': False, 'name': '666', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': '999'}, {...]
						cookies = browser.get_cookies()
						cookies_dict = {cookie['name']:cookie["value"] for cookie in cookies}
				2.browser.get_cookie()
					1.zfy = browser.get_cookie("ZFY")
			2.删除cookie
					browser.delete_all_cookies()
					browser.delete_cookie("ZFY")
			3.设置cookie
				add_cookie() 传入一个字典 传name和value
				{"name":"xx","value":"xx"} 如果name
		7.获取网页源代码
			browser.page_source
			browser.page_source.encode('utf-8')
		8.执行js代码
			js_code1 = "var a = navigator.webdriver;alert(a);"
			browser.execute_script(js_code1)
			time.sleep(5)
		9.切换标签页
			1.代码
				browser.switch_to.window(browser.window_handles[1])
				browser.switch_to.window(browser.window_handles[2])
			2.可以通过判断是否还有标签页 让 py 代码处于执行状态 关闭所有tab页后 就为 0 了
				while len(browser.window_handles) > 0:
					pass
			3.不同页面切换 和 在切换到的tab下面 打开新的网址
				browser.get('https://www.baidu.com')
				time.sleep(1)
				browser.execute_script('window.open("https://www.taobao.com")')
				time.sleep(2)
				browser.switch_to.window(browser.window_handles[0])
				browser.get('https://www.jd.com')
				time.sleep(1)
				browser.switch_to.window(browser.window_handles[1])
				browser.get('https://www.baidu.com')
				time.sleep(10)
		10.前进后退
			borwser.forward() # 前进
			borwser.back()    #后退
		11.滑动
			1.常见代码
				window.scrollBy(x,y)
				window.scrollBy(0,300) # 运行一次就滑动一次
				window.scrollTo(0,300) # 一步到位,多次运行也是一样结果
				driver.execute_script('window.scrollBy(0, 1000);')
			2.滑动到底部
				# 向下滑动到页面底部
				browser.execute_script('window.scrollTo(0, document.body.scrollHeight);') # 最大body距离 document.body.scrollHeight
				# 滑动到顶部
				browser.execute_script('window.scrollTo(0,0);')
				# 当前y轴位置
				y = browser.execute_script("return window.scrollY")
				print(y)
			3.慢慢滚
				for i in range(10):
					time.sleep(0.5)
					browser.execute_script(f'window.scrollTo(0,{i * 300})')
	5.经验用法
		1.配置项 使用配置对象
			1.不让浏览器提示 有自动化程序控制 的提示
				option = webdriver.ChromeOptions()
				# 解决谷歌浏览器提示“Chrome正在受到自动化测试软件的控制”
				option.add_experimental_option("useAutomationExtension", False)
				option.add_experimental_option("excludeSwitches", ["enable-automation"])
				# option.add_argument(‘–headless’) # 给chrome_options添加headless参数
				browser = webdriver.Chrome(options=option)
			2.综合配置项
				from selenium.webdriver.common.by import By
				from selenium import webdriver
				import time
				from selenium.webdriver.support.ui import WebDriverWait
				from selenium.webdriver.support import expected_conditions as EC

				options = webdriver.ChromeOptions()
				# 解决谷歌浏览器提示“Chrome正在受到自动化测试软件的控制”
				options.add_experimental_option("useAutomationExtension", False)
				options.add_experimental_option("excludeSwitches", ["enable-automation"])

				# 无头模式 在后台运行 装逼用的
				# options.add_argument("-headless")
				# 设置代理
				# options.add_argument("--proxy-server=http://123.33.251.23:8080")
				# 设置浏览器大小
				options.add_argument("--window-size=1920,1080")
				# 禁用浏览器通知
				options.add_argument("--disable-notifications")
				# 通过设置user-agent
				ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537111111.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36'
				options.add_argument(f'user-agent={ua}')
				# 禁用扩展程序
				options.add_argument("--disable-extensions")
				# 设置浏览器语言
				options.add_argument("--lang=zh-CN")
				# 启用开发者模式 打开的时候自动开启f12
				options.add_argument("--auto-open-devtools-for-tabs")

				# 禁止自动化提示
				options.add_experimental_option("excludeSwitches", ["enable-automation"])
				options.add_experimental_option("useAutomationExtension", False)
				# 禁用自动化控制接口实现防止被检测
				options.add_argument('--disable-blink-features=AutomationControlled')

				# 禁止图片
				prefs = {"profile.managed_default_content_settings.images": 2}
				options.add_experimental_option("prefs", prefs)
				# 安装插件
				extension_path = r'S:\project 2021\other\ChromeHelper\chrome tomorrow\commonPlugs\xpath\xpath.crx'
				options.add_extension(extension_path)

				# 初始化配置
				browser = webdriver.Chrome(options=options)
				# 将浏览器最大化显示
				# browser.maximize_window()
				browser.get("https://www.baidu.com")
				# 设置宽高
				# browser.set_window_size(480, 800)
				# 通过js新打开一个窗口
				# browser.execute_script('window.open("http://httpbin.org/ip");')

		2.稍微综合用法
			browser.get("https://www.baidu.com/")
			browser.find_element(By.NAME,'wd').send_keys("python")
			browser.find_element(By.ID,"su").click()
			print(browser.page_source.encode('utf-8')) #获取网页源码
			print(browser.get_cookies()) # 获取cookies
			print(browser.get_screenshot_as_file('123.png')) # 保存图片
			print(browser.current_url) #获取当前路径
			time.sleep(10)
		3.等待 某个/全部 元素加载完毕
			1.基本代码
				# 等待某个标签加载,如果没加载就抛出异常
					wait.until(EC.presence_of_element_located((By.ID,"key")))
				# 等待符合条件的标签全部加载完成
					wait.until(EC.presence_of_all_elements_located((By.ID,"key")))
			2.用法举例
				from selenium.webdriver.common.by import By
				from selenium import webdriver
				import time
				from selenium.webdriver.support.ui import WebDriverWait
				from selenium.webdriver.support import expected_conditions as EC

				option = webdriver.ChromeOptions()
				# 解决谷歌浏览器提示“Chrome正在受到自动化测试软件的控制”
				option.add_experimental_option("useAutomationExtension", False)
				option.add_experimental_option("excludeSwitches", ["enable-automation"])
				# option.add_argument(‘–headless’) # 给chrome_options添加headless参数
				browser = webdriver.Chrome(options=option)

				wait = WebDriverWait(browser,10)
				browser.get("https://www.baidu.com")
				# 等待某个标签加载,如果没加载就抛出异常
				wait.until(EC.presence_of_element_located((By.NAME,"key")))
				# 等待符合条件的标签全部加载完成
				wait.until(EC.presence_of_all_elements_located((By.ID,"key")))
			3.用法举例2
				from selenium import webdriver
				from selenium.webdriver.common.by import By
				from selenium.webdriver.support.ui import WebDriverWait  # available since 2.4.0
				from selenium.webdriver.support import expected_conditions as EC  # available since 2.26.0
				from selenium.webdriver.chrome.options import Options
				from selenium.webdriver.remote.webelement import WebElement
				from time import sleep
				import traceback

				chrome_options = Options()
				chrome_options.add_argument('--headless')
				# chrome_options.add_argument('--disable-gpu')
				driver = webdriver.Chrome(options=chrome_options)
				# driver.maximize_window()
				# driver.get("https://www.baidu.com")
				driver.get("https://www.baidu.com")
				print(driver.title)
				# 繁体字
				html = driver.execute_script("return document.documentElement.outerHTML")
				try:
					element = WebDriverWait(driver, 360).until(EC.presence_of_element_located((By.CLASS_NAME, "s-top-left-new")))
					# driver.find_element_by_id("").
					eles = driver.find_elements(By.XPATH, "//ul[@id='hotsearch-content-wrapper']/li")
					print(eles)
					eles = [ele.text for ele in eles]
					for ele in eles:
						print(f"news:{ele}")
				except (Exception, e):
					traceback.print_exc()
				html = driver.execute_script("return document.documentElement.outerHTML")
				sleep(3)
8.csv 模块
	import csv
	with open('data.csv', 'r+', encoding='utf-8',newline="") as f:
		# 第一种 写法
		# data = ["id","name","age"]
		# writer = csv.writer(f)
		# writer.writerow(data)
		# writer.writerow(["1","zs",50])
		# writer.writerow(["2","zs1",51])
		# writer.writerows([["3","zs2",52],["4","zs3",53]])
		# 第二种 写法
		# writer = csv.DictWriter(f,fieldnames=["id","name","age"])
		# writer.writeheader()
		# writer.writerow({"id":"1","name":"zs","age":50})
		# writer.writerow({"id":"2","name":"zs2","age":51})
		# writer.writerow({"id":"3","name":"zs3","age":52})

		#第一种 读法
		# reader = csv.reader(f)
		# for row in reader:
		#     print(row) # ['id', 'name', 'age']

		#第二种 读法
		reader = csv.DictReader(f)
		for row in reader:
			print(row) # {'id': '3', 'name': 'zs3', 'age': '52'}

杂项相关

1.路径相关
	1.路径一般情况下不用转义 但是 遇到 \try 这种就需要写成 \\try \111.js \\111.js 数字也需要转义
2.字符串相关
	1.字符串前面有r a = r"a\tb" r表示的是这个字符串是原始字符串 所有的\不具备转义 功能
		import re
		text1 = "app le"
		matches1 = re.match('app\\sle', text1)
		print(matches1)  # <re.Match object; span=(0, 6), match='app le'>
		matches1 = re.match(r'app\\sle', text1)
		print(matches1)  # None
	2.b"123" == "123".encode("utf-8") # True 结果 都是字节集
3.关于混淆
	1.常见的代码混淆手段
		1.压缩代码
		2.字符串加密(AES Base64)
		3.代码分拆和重组(将原始代码分拆为很多片段 以不同的顺序重组)
		4.变化语法来增加代码复杂性
		5.无意义的代码插入
		6.控制流混淆 (JavaScript Obfuscator 和 Closure Compiler)
		7.代码加密 (WASM)
	2.混淆的弊端
		1.增大代码的体积 浪费流量
	3.混淆的网址
		1.https://www.jsjiami.com/jsfuck.html
4.关于各种编码
	1.encode 结果是返回的字节集
		a = "123"
		print(a.encode("utf-8"))
5.异常处理
	1.代码
		try:
			a = 1/0
		#except Exception as e: 这种写法任意错误都可以 当然错误分很多种
		except ZeroDivisionError as e:
			print(e) #division by zero 零不能作除数 所以报错
		else:
			print("No exception") # 如果不发生异常 走这里
		finally:
			print("Finally") # Finally 无论怎样都走这里
		print("over")
6.装饰器
	1.装饰器代码
		#定义装饰器 被装饰的函数 当作参数 传入到 return 的函数 中去
		def outer(func):
			 def wrapper(*args, **kwargs):
				 print('begin')
				 func(*args, **kwargs)
				 print('end')
			 return wrapper

		@outer
		def login(*args,**kwargs):
			print("login.....")
		#输出结果
		#begin
		#login.....
		#end
		if __name__ == '__main__':
			login(user='admin',pwd='123')
7.类
	1.类的三个属性
		1.__doc__ 参数说明
		2.__name__ print(__name__) # 如果是执行文件 __main__ 如果是类的话 __main__ 是包名
			class Animal(object):
				def __init__(self):
					self.name = __name__
				def __str__(self):
					return "Anmial Info"

			animal = Animal()
			print(animal.name) # __main__ 如果在类文件里面调用

			from test import Animal
			animal = Animal()
			print(animal.name) # test 如果 在引用类的文件里面调用 会输出 两条 test 也就是说 上面的 __main__ 也会变
				1.所以有  if __name__ = "__main__" 来判断  说明在类内部运行
		3.__str__
			class Animal(object):
				def __init__(self):
					self.name = __name__
				def __str__(self):
					return "Anmial Info"

			if __name__ == "__main__":
				animal = Animal()
				print(animal.name)  # __main__
				print(Animal()) # "Anmial Info"
python 简单的类结构
class Car:
    def __init__(self, make, model, year):
        self.__make = make      # 私有变量
        self.__model = model    # 私有变量
        self.__year = year      # 私有变量

    def get_make(self):
        return self.__make     # 通过公共方法访问私有变量

    def set_make(self, make):
        self.__make = make     # 通过公共方法修改私有变量

car = Car("Toyota", "Camry", 2022)
print(car.get_make())         # 输出: Toyota

car.set_make("Honda")
print(car.get_make())         # 输出: Honda

# 尝试直接访问私有变量
print(car.__make)             # 报错: AttributeError: 'Car' object has no attribute '__make'

简单的 继承 Animal Dog
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.__age = age
    def speak(self):
        print("I am an animal")
    def say_name(self):
        print(f"My name is {self.name},age is {self.__age}")

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)
        self.breed = breed
    def speak(self):
        print("I am a dog")

dog = Dog("FuGui", 3, "Labrador")
dog.speak() # I am a dog
dog.say_name() # My name is FuGui,age is 3
print(dog.name) # FuGui
print(dog.__age) # AttributeError: 'Dog' object has no attribute '__age' 私有 属性外部不可以访问
复杂的 Animal Dog 继承
class Animal:
    def __init__(self, name="animal", age=99):
        Person("Animal Constructor")
        self.name = name
        self.__age = age
    def speak(self):
        print("I am an animal")
    def say_name(self):
        print(f"My name is {self.name},age is {self.__age}")
    def stand(self):
        print("Animal is standing")
    def aniaml_id(self):
        print("Animal id is 123")
class Person:
    def __init__(self, name, age):
        print("Person Constructor")
        self.name = name
        self.__age = age
    def stand(self):
        print("Person is standing")

class Dog(Person,Animal): # 多继承 谁在前面 谁的方法 优先 比如 stand 可以理解为 作用域链 找到就不再继续找了
    def __init__(self, name, age, breed):
        super().__init__(name, age) # 这里的 super() 是父类 Person 谁在前面执行 谁的构造方法
        #整个过程 Animal super() 的 构造函数没有执行 也就是说 构造方法没有执行
        # 想调用 Animal 的构造函数
        self.breed = breed
    def speak(self):
        print("I am a dog")
    def eat():
        print("Dog can eat")

dog = Dog("FuGui", 3, "Labrador")
dog.stand()
dog.speak() # I am a dog
dog.aniaml_id() # Animal id is 123 虽然 Animal 的 构造函数  __init__ 没有执行 但是方法依然是继承了
# dog.say_name() # My name is FuGui,age is 3 如果 Dog 多继承时候 Animal 放后面 由于 constructor 没有执行 所以这个方法报错
print(dog.name) # FuGui
# print(dog.__age) # AttributeError: 'Dog' object has no attribute '__age' 私有 属性外部不可以访问
Dog.eat() # Dog can eat 不需要 私有属性装饰器 @staticmethod 好像也没问题
8.模块的封装
	1.单文件 Animal.py
		1.代码
			class Animal(object):
				def __init__(self,name,brand,age):
					self.name = name
					self.age = age
					self.brand = brand
				def speak(self):
					print("I am a {} and I am {} years old".format(self.name,self.age))
			def add(a,b):
				print(a+b)

			import Animal
			animal = Animal.Animal("Dog", "Brown", 4)
			animal.speak() # I am a Dog and I am 4 years old
			Animal.add(1,2) # 3
			animal.add(2,3) # ttributeError: 'Animal' object has no attribute 'add'

			from Animal import Animal
				1.如果用这种模式调用 Animal.add(1,2) # 这个也会报错 因为只是调用了文件Animal 里面的 类
	2.多文件
		1.其实就是一个文件夹下面有很多个 py 文件
		2.需要文件夹下有一个 __init__.py 的空文件 即可
		3.代码
			#add.py
			def add(a,b):
				return a + b

			#Animal.py
			class Animal(object):
				def __init__(self,name,brand,age):
					self.name = name
					self.age = age
					self.brand = brand
				def speak(self):
					print("I am a {} and I am {} years old".format(self.name,self.age))

			#MulDiv.py
			def mult(a,b):
				return a*b
			def div(a,b):
				return a/b

			#调用文件
			from myMath.Animal import Animal
			from myMath.add import add
			from myMath.MulDiv import mult,div
			animal = Animal("dog","wangwang",3)
			animal.speak()
			print(add(1,2)) # 3
			print(mult(3,2)) #
			print(div(3,2)) # 1.5
9.数据库
	1.mysql
		1.代码
			import pymysql
			import time
			db = pymysql.connect(host='localhost',user='root',password='abc',db='abc')
			cursor = db.cursor() # 需要 cursor 去执行 语句 但是 提交 commit 和 close 需要 db
			#查询
			res = cursor.execute("select * from de_data limit 205,50") # 返回查询到的条数
			data = cursor.fetchall() # 获取到查询的所有结果

			for i in data:
				print(list(i)) # tuple 结果 每条
				pass

			#插入
			sql = "insert into de_data (email,other_pwd) values (%s,%s)" # 返回查询到的条数
			values = ('python001@gmail.com','abcdefg') # 数据单独写进values
			res = cursor.execute(sql,values) # 执行sql并替换 values 执行后的结果返回一个整数 表示影响的行数
			res = db.commit() # 然后 db 提交 不返回任何东西 None
			db.close() # 关闭 Db
	2.mongodb
		1.代码
			import pymongo
			client = pymongo.MongoClient(host="localhost", port=27017) # MongoClient(host=['localhost:27017']...)
			db = client["tt"] # 选择数据库 Database(MongoClient(host=['localhost:27017'],... 'tt')
			table = db["abc_1"] # 选择表 Collection(Database(MongoClient(host=['localhost:27017'], ... 'tt', 'abc_1')

			# 插入数据
			data = {"name": "zhangsan", "age": 18, "sex": "男"} # 数据的列表可以没有 没有就自动添加一行

			res = table.insert_one(data) # InsertOneResult(ObjectId('662793daf302de51214b7247'), acknowledged=True)

			data2 = [{"name": "lisi", "age": 20, "sex": "女"}, {"name": "wangwu", "age": 22, "sex": "男"}]
			res = table.insert_many(data2)
			print(res) #InsertManyResult([ObjectId('6627943d0f8ccbc8eb75f552'), ObjectId('6627943d0f8ccbc8eb75f553')])

			res = table.find()
			for i in res:
				print(i) # {'_id': ObjectId('662797f32f994fd3350c0615'), 'name': 'zhangsan', 'age': 18, 'sex': '男'}

课件相关

https://docs.qq.com/sheet/DREJyckVrcEV6WVlU?tab=000001 
教学案例(随用随更):【腾讯文档】爬虫百例-宇哥实战 :群文件自取 
测试练习题 :【腾讯文档】测试练习题 (都是实战) 
https://docs.qq.com/doc/DRGR0cENDWk9xd21R 
课件资料:群文件自取 
ps:没有基础或基础不好不要跳着看 
Python课件更新中:https://docs.qq.com/doc/DREFKSHFSc2ZQTll4
posted @ 2024-03-22 17:53  闭区间  阅读(7)  评论(0编辑  收藏  举报