当前位置: 首页 > news >正文

网站怎么做域名解析建设的比较好的档案馆网站

网站怎么做域名解析,建设的比较好的档案馆网站,欣赏网站,路由器做网站服务器获取笔记链接 Python超详细的学习笔记 一#xff0c;逆向加密模块 1#xff0c;Python中运行JS代码 1.1 解决中文乱码或者报错问题 import subprocess from functools import partial subprocess.Popen partial(subprocess.Popen, encodingutf-8) import execjs1.2 常用…获取笔记链接 Python超详细的学习笔记 一逆向加密模块 1Python中运行JS代码 1.1 解决中文乱码或者报错问题 import subprocess from functools import partial subprocess.Popen partial(subprocess.Popen, encodingutf-8) import execjs1.2 常用函数 print(execjs.get().name) # 获取js代码执行环境res execjs.eval(js) # 执行一段js代码#先编译 jj execjs.compile( function an(a, b){return a b } ) # call() 运行代码中的xxx函数. 后续的参数是xxx的参数 ret jj.call(an, 10, 20)#读取js文件 f open(01.js,moder,encodingutf-8) js_code f.read() # 执行js代码函数 js execjs.compile(js_code) js.call(函数)obj re.compile(rwindow\._INIT_STATE__ (?Pcode.*?);,re.S) # 正则表达式 code obj.search(js_code).group(code) #匹配正则表达式 print(type(code)) #这里的code是字符串# execjs这个库会把运行的结果自动转化成对象 result execjs.eval(code)# 拿到的是一个JS代码运行的结果 print(result) #是个字典Python会自动转换成字典 print(type(result)) # dictexecjs._exceptions.ProgramError: Error: Malformed UTF-8 data js报错了返回的数据两端有引号或者双引号需要去掉2CryptoJS加密特征 function b(a, b) {var c CryptoJS.enc.Utf8.parse(b), d CryptoJS.enc.Utf8.parse(0102030405060708), e CryptoJS.enc.Utf8.parse(a), f CryptoJS.AES.encrypt(e, c, {iv: d,mode: CryptoJS.mode.CBC});return f.toString()}#转换为UTF8 CryptoJS.enc.Utf8 # 转换为base64 CryptoJS.enc.Base643RAS加密特征 setMaxDigits, RSAKeyPair, encryptedString4md5加密解密 from hashlib import md5obj md5() obj.update(alex.encode(utf-8)) # obj.update(wusir.encode(utf-8)) # 可以添加多个被加密的内容bs obj.hexdigest() print(bs)# 加盐 from hashlib import md5 salt 我是盐.把我加进去就没人能破解了obj md5(salt.encode(utf-8)) # 加盐 obj.update(alex.encode(utf-8))bs obj.hexdigest() print(bs)5傻系列加密 sha1,sha256,sha512用法跟md5一样 from hashlib import sha1, sha256 sha sha256(bsalt) sha.update(balex) print(sha.hexdigest())6URLencode from urllib.parse import quote, unquote, quote_plus, unquote_plus, urlencode# 单独编码字符串 用 quote wq 米饭怎么吃 print(quote(wq)) # %E7%B1%B3%E9%A5%AD%E6%80%8E%E4%B9%88%E5%90%83 print(quote(wq, encodinggbk)) # %C3%D7%B7%B9%D4%F5%C3%B4%B3%D4# 多个数据统一进行编码 用urlencode ,比如字典进行编码 dic {wq: 米饭怎么吃,new_wq: 想怎么吃就怎么吃 }print(urlencode(dic)) # wq%E7%B1%B3%E9%A5%AD%E6%80%8E%E4%B9%88%E5%90%83new_wq%E6%83%B3%E6%80%8E%E4%B9%88%E5%90%83%E5%B0%B1%E6%80%8E%E4%B9%88%E5%90%83 print(urlencode(dic, encodingutf-8)) # 也可以指定字符集# 一个完整的url编码过程 base_url http://www.baidu.com/s? params {wd: 大王 }url base_url urlencode(params) print(url) # http://www.baidu.com/s?wd%E5%A4%A7%E7%8E%8B#解码 s http://www.baidu.com/s?wd%E5%A4%A7%E7%8E%8B print(unquote(s)) # http://www.baidu.com/s?wd大王print(quote(a /b/c, safe)) # 传递safe 可以保持和浏览器一致 print(quote_plus(a /b/c))7base64编码 import base64bs 我要吃饭.encode(utf-8) # 把字节转化成b64 print(base64.b64encode(bs).decode())# 把b64字符串转化成字节 s 5oiR6KaB5ZCD6aWt print(base64.b64decode(s).decode(utf-8))#base64报错问题 import base64s ztKwrsTj0b0 bb base64.b64decode(s) print(bb)此时运行出现以下问题 Traceback (most recent call last):File D:/PycharmProjects/rrrr.py, line 33, in modulebb base64.b64decode(s)File D:\Python38\lib\base64.py, line 87, in b64decodereturn binascii.a2b_base64(s) binascii.Error: Incorrect padding# 解决办法s ztKwrsTj0b0 s ( * (4 - len(s) % 4)) print(填充后, s) bb base64.b64decode(s).decode(gbk) print(bb)# 注意事项 由于标准的Base64编码后可能出现字符和/但是这两个字符在URL中就不能当做参数传递所以就出现了Base64URL下面是它们的区别1. Base64编码后出现的和/在Base64URL会分别替换为-和_ 2. Base64编码中末尾出现的符号用于补位这个字符和queryString中的keyvalue键值对会发生冲突所以在Base64URL中符号会被省略去掉后怎么解码呢因为Base64是把3个字节变为4个字节所以Base64编码的长度永远是4的倍数因此需要加上把Base64字符串的长度变为4的倍数就可以正常解码了。我们的应对方案: 在处理base64的时候.如果遇到了没有和/的情况. 可以采用下面的方案来替换掉和/ b64 base64.b64decode(mi, b-_)8AES加密 1加密规则 第一种 # AES加密 from Crypto.Cipher import AES import base64长度16: *AES-128*24: *AES-192*32: *AES-256*MODE 加密模式.常见的 ECB 可以没有ivCBC 需要iv的# 创建加密器 注意秘钥和iv必须是16个字节 aes AES.new( key balexissbalexissb, modeAES.MODE_CBC, ivb0102030405060708) # 分别是秘钥模式iv data 我吃饭了# 加密的内容必须是字节所以先进行编码 data_bs data.encode(utf-8)# 需要加密的数据必须是16的倍数 # 填充规则: 缺少数据量的个数 * chr(缺少数据量个数) pad_len 16 - len(data_bs) % 16 data_bs (pad_len * chr(pad_len)).encode(utf-8) # 再对编码后的字节进行加密 bs aes.encrypt(data_bs) #用base64对结果进行编码 result base64.b64encode(bs).decode()第二种用pad对字节进行填充达到规定的长度 # AES加密 from Crypto.Cipher import AES import base64 from Crypto.Util.Padding import pad长度16: *AES-128*24: *AES-192*32: *AES-256*MODE 加密模式.常见的 ECB 可以没有ivCBC 需要iv的# 创建加密器 注意秘钥和iv必须是16个字节 aes AES.new( key balexissbalexissb, modeAES.MODE_CBC, ivb0102030405060708) # 分别是秘钥模式iv data 我吃饭了# 加密的内容必须是字节所以先进行编码 data_bs data.encode(utf-8)# 需要加密的数据必须是16的倍数 # 用pad工具进行填充 data_bs pad(data_bs,16) # 再对编码后的字节进行加密 bs aes.encrypt(data_bs) #用base64对结果进行编码 result base64.b64encode(bs).decode() print(result)2, 加密结果转换base64,hex # 转换成base64 bs是AES加密得到的字节 result base64.b64encode(bs).decode()#转换成16进制 import binascii res binascii.b2a_hex(bs).decode()# 也可以转换成16进制跟上面一个效果一样 bs.hex()3解密规则 from Crypto.Util.Padding import pad,unpad# base64编码后的密文 s 9noPO0fcQizMbPkXcVOTDg # 创建解密器 aes AES.new(key balexissbalexissb, modeAES.MODE_CBC, ivb0102030405060708) # 首先把base64编码转换成正常的字节 data base64.b64decode(s) res aes.decrypt(data) # 明文有可能有问题因为字节是填充过得 # 用unpad 去除填充的内容注需要导入unpad res unpad(res,16) # 得到明文 mingwen res.decode(utf-8) print(mingwen)9DES加密 1加密规则 from Crypto.Cipher import DES from Crypto.Util.Padding import pad,unpad import base64 mingwen 艾尼在学爬虫# DES key 是 8个字节 # iv 在CBC 模式下使用 长度8个字节 des DES.new(keybaininora, modeDES.MODE_CBC,ivbainiaini)# 明文进行编码 data mingwen.encode(utf-8) # 对编码后的字节进行填充 r pad(data,8) # 对填充后的字节进行des加密后的字节 res des.encrypt(r) # 对加密后的字节进行base64编码 base64_res base64.b64encode(res).decode() print(base64_res)2DES解密规则 from Crypto.Cipher import DES from Crypto.Util.Padding import pad,unpad import base64#base64密文 miwen t4TYyzRnIkmVmI81ncdsVQfprHN5AtG #转换成base64字节 base64_byt base64.b64decode(miwen) # 创建解密器对象 des DES.new(keybaininora, modeDES.MODE_CBC,ivbainiaini) # 进行解密 r des.decrypt(base64_byt) # 得到的结果去掉填充部分 data unpad(r,8) # 对得到的字节进行解码 mingwen data.decode(utf-8) print(mingwen)注DES3 与AESDES加密解密规则一样都是兄弟 注js里的秘钥可以超过8位js默认去前八位进行解密 10RSA加密 1RSA生成秘钥和公钥 #生成和处理秘钥的 from Crypto.PublicKey import RSA # 加密和解密 from Crypto.Cipher import PKCS1_v1_5import base64# 生成私钥 #bits 2048 是秘钥的长度 rsa_key RSA.generate(bits2048) # 把秘钥导出来 # 秘钥的本质是字节# export_key 有个参数叫format,默认为PEM背后的含义是把秘钥转换成了base64 key rsa_key.export_key().decode()with open(./rsa_miyao.pem,modew,encodingutf-8) as f:f.write(key)# 把format换成DER,拿到的是字节 # key rsa_key.export_key(formatDER)# 把字节手动转换成base64 # result base64.b64encode(key).decode()#生成公钥 public_key rsa_key.public_key() # 把公钥导出来 p_key public_key.export_key()with open(./rsa_gongyao.pem,modewb) as f:f.write(p_key) 2, RSA进行加密 #加密解密 from Crypto.Cipher import PKCS1_v1_5 #加载key from Crypto.PublicKey import RSAimport base64# 导入的key可以是PEM格式的秘钥或者是直接形式的秘钥也可以 # 读取秘钥 f open(./rsa_gongyao.pem,moder,encodingutf-8) # 拿到已经生成好的秘钥 pub_key f.read() f.close()mingwen 我要好好学习爬虫rsa_key RSA.importKey(pub_key) # 生成加密对象 rsa PKCS1_v1_5.new(keyrsa_key) # 对明文进行编码处理成字节 mingwen_bs mingwen.encode(utf-8) # 对明文字节进行加密,得到密文字节 mi_bs rsa.encrypt(mingwen_bs) # 转换成base64 base_64 base64.b64encode(mi_bs).decode() #rsa每次加密后的结果可能不一样 print(base_64)# 如果用了没有填充的算法那每一次算出来的结果固定的 # 如果同一个明文反复计算结果是一样的那么考虑用js来完成逆向工作2.1 第二中加密方法 // JSEncrypt // setPublicKey// 用的是固定的第三方库库的名字叫jsencrypt // 但是这个库只能在浏览器环境使用 // 我们用的是Node环境所以不能直接是哟和// 我们需要换一个库 名字叫 node-jsencrypt // 安装 npm install node-jsencryptvar {JSEncrypto} require(node-jsencrypt) var o new JSEncrypt o.setPublicKey(xxxxxxxxxxxxxxxxxxxxxxxx) r o.encrypt(加密的内容)// 可以直接把网站的内容拿过来 3RSA特殊解密 3.1 第一特征 1如果用了没有填充的算法那每一次算出来的结果固定的 2如果同一个明文反复计算结果是一样的那么考虑用js来完成逆向工作 // 特征 // 010001 - 这是16进制 - 65537 // setMaxDigits // RSAKeyPair // encryptedStringconst {setMaxDigits,RSAKeyPair,encryptedString } require(./Ras加密);function c(a,b,c){var d,e;return setMaxDigits(131),d new RSAKeyPair(b,,c),e encryptedString(d,a) }3用RSA.js文件解决问题 例如网易云案例 const CryptoJS require(crypto-js) var window thisconst {setMaxDigits,RSAKeyPair,encryptedString } require(./Ras加密); !function() {function a(a) {var d, e, b abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789, c ;for (d 0; a d; d 1)e Math.random() * b.length,e Math.floor(e),c b.charAt(e);return c}function b(a, b) {var c CryptoJS.enc.Utf8.parse(b), d CryptoJS.enc.Utf8.parse(0102030405060708), e CryptoJS.enc.Utf8.parse(a), f CryptoJS.AES.encrypt(e, c, {iv: d,mode: CryptoJS.mode.CBC});return f.toString()}function c(a, b, c) {var d, e;return setMaxDigits(131),d new RSAKeyPair(b,,c),e encryptedString(d, a)}function d(d, e, f, g) {var h {}, i a(16);return h.encText b(d, g),h.encText b(h.encText, i),h.encSecKey c(i, e, f),h}function e(a, b, d, e) {var f {};return f.encText c(a e, b, d),f}window.asrsea d,window.ecnonasr e }();var params {csrf_token: ,encodeType: aac,ids: [1325905146],level: standard}var second 010001var third 00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7var forth 0CoJUm6Qyw8W8judfunction fn(params) {return window.asrsea(JSON.stringify(params),second,third,forth)4, RSA普通解密 #加密解密 from Crypto.Cipher import PKCS1_v1_5 #加载key from Crypto.PublicKey import RSAimport base64f open(./rsa_miyao.pem,moder,encodingutf-8) # 拿到已经生成好的秘钥 pri_key f.read() f.close() # 拿到秘钥 rsakey RSA.importKey(pri_key) # 生成解密器对象 rsa PKCS1_v1_5.new(keyrsakey) miwen mmf28CJEtFU2Y6C/qx10xoaRmsiY2at3LBjHR5DFdnG9V5sGPFaMGDGM4OBVWKKJNuSFZgGL9Y409mbh32IKRL4TZYnc0RvJH/0t38d7AmnqnHAyTRUvpKlPzzJg559md6BcTA/ZpYZ4WAtXRuysMvuPTdlRvog2ceGJDXURajU3KyzHXFA9HcAamVL75DYKrOB6n9YeV7n4DK5mqouNlLp6Plee39vYBzN0IKkzyD6RatmVVUIxJCsUJmeJgIdnBGEuRA9bGNOG3VQa7NF/syWjiRNbKYzKZHxRtQ9GuzmPhtJbjh8anPeR2kzNwgfD1HiKhIBDQKVQH/eA #对密文进行base64解码转换成字节 base64_2bs base64.b64decode(miwen) #对拿到的字节进行rsa解密得到明文字节 # 解密第二个参数给个None意思是解密时出错了返回None mingwen_bs rsa.decrypt(base64_2bs,None) #对明文字节进行解码得到明文 mingwen mingwen_bs.decode(utf-8) print(mingwen)11 异步框架特征 ## 异步框架 ---- 固定逻辑 ## next 表示下一步是哪里 ## return 语句表示给下一步传递的消息 ## sent是接受上一步return返回的东西 ## abrupt 第一个参数是return 表示该异步逻辑彻底结束返回值为第二个参数 ## stop 表示彻底终结该异步框架return d().wrap((function(e) {for (; ; ) // 死循环switch (e.prev e.next) {case 0: // 第一次一定执行case 0return e.next 2, // 表示下一步执行哪里表示下一步执行case 2返回的内容是传递给case 2)me.search.getSearchSalaryList(pe(pe({}, y), {}, {pageNum: f.current,limit: 15}));case 2:t e.sent, // 上一步return的东西上一步返回的内容100%是promise对象a t.resdata,1 t.rescode a (n a.salarys,r a.pageCount,c a.totalCountStr,l a.company,s a.recCompany,x((function(e) {return (0,z.JO)(f.current, e, n)})),F(r || 0),K(c || ),Z(l || null),D(s || []),J(!1));case 6:case end:return e.stop() // 彻底停止}}), e)二网页解析模块二 1re正则 1、匹配单个字符与数字 匹配说明.匹配除换行符以外的任意字符当flags被设置为re.S时可以匹配包含换行符以内的所有字符[]里面是字符集合匹配[]里任意一个字符[0123456789]匹配任意一个数字字符[0-9]匹配任意一个数字字符[a-z]匹配任意一个小写英文字母字符[A-Z]匹配任意一个大写英文字母字符[A-Za-z]匹配任意一个英文字母字符[A-Za-z0-9]匹配任意一个数字或英文字母字符[^lucky][]里的^称为脱字符表示非匹配不在[]内的任意一个字符1以[]中内的某一个字符作为开头\d匹配任意一个数字字符相当于[0-9]\D匹配任意一个非数字字符相当于[^0-9]\w匹配字母、下划线、数字中的任意一个字符相当于[0-9A-Za-z_]\W匹配非字母、下划线、数字中的任意一个字符相当于[^0-9A-Za-z_]\s匹配空白符(空格、换页、换行、回车、制表)相当于[ \f\n\r\t]\S匹配非空白符(空格、换页、换行、回车、制表)相当于[^ \f\n\r\t] 2、匹配锚字符 锚字符:用来判定是否按照规定开始或者结尾 匹配说明^行首匹配和[]里的^不是一个意思$行尾匹配 3、限定符 限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。 匹配说明(xyz)匹配括号内的xyz作为一个整体去匹配 一个单元 子存储x?匹配0个或者1个x非贪婪匹配x*匹配0个或任意多个xx匹配至少一个xx{n}确定匹配n个xn是非负数x{n,}至少匹配n个xx{n,m}匹配至少n个最多m个xx|y|表示或的意思匹配x或y 通用flags修正符 值说明re.I是匹配对大小写不敏感re.S使.匹配包括换行符在内的所有字符 ^a 匹配a开头的 2 匹配一个小写字母a并且a作为开头等同于^a [^a] 匹配一个小写字母a以外的任意字符 4匹配符总结 1 []原子表 [a] 匹配一个小写字母a [1] 匹配一个数字1 [ab] 匹配一个小写字母a或者b [a1] 匹配一个小写字母a或者数字1 [123] 匹配一个数字1或者2或者3 [a-z] 匹配任意一个小写字母 [A-Z] 匹配任意一个大写字母 [a-zA-Z] 匹配任意一个字母 [0-9] 匹配任意一个数字 0-9 [a-zA-Z0-9] 匹配任意一个数字 0-9或者任意一个字母 以上不管[]中有多少内容 只匹配一个2 {m} 限定符 不能单独使用 限定前面那个正则的m次 a 匹配一个小写字母a ab 匹配小写字母ab aa 匹配2个小写字母a a{2} 匹配2个小写字母a ab{2} 匹配小写字母abb a{2}b{2} 匹配小写字母aabb [a-zA-Z]{5} 匹配任意5个字母3 {m, n} 限定符 不能单独使用 限定前面那个正则的m-n次 [a-zA-Z]{3,5} 匹配任意3-5个字母4 {m,} 限定符 不能单独使用 限定前面那个正则的m次 [a-zA-Z]{3,} 至少匹配任意3个字母5 ^ 以...开始 abc 匹配abc三个字母 ^abc 匹配以abc开头的三个字母 ^[a] 匹配一个小写字母a并且a作为开头 等同于 ^a [^a] 匹配一个小写字母a以外的任意字符6 $ 以...结尾 abc 匹配abc三个字母并且作为结尾 ^abc 匹配以abc开头的三个字母 abc$ 匹配abc三个字母并且作为结尾7 ^$ 一般组合使用 (完全匹配) 匹配手机号 1[3-9][0-9]{9} ^1[3-9][0-9]{9}$8 ? 匹配前面的正则0次或1次 相当于 {0,1} -?[1-9] 匹配正负1-99 . 匹配换行符以外的任意字符10 * 匹配任意次 {0,}11 .* 匹配除换行符以外任意字符任意次 贪婪模式12 .*? 匹配除换行符以外任意字符任意次 拒绝贪婪模式 (用的多)13 匹配至少一次 相当于{1, }14 . 匹配除换行符以外任意字符至少1次 贪婪模式15 .? 匹配除换行符以外任意字符至少1次 拒绝贪婪模式16 () 子存储(会把括号里的值单独的保存下来) 一个单元 (ab)|(cd)17 \w 匹配一位数字字母下划线 [a-zA-Z0-9_]18 \W19 \d 匹配一位数字 [0-9]20 \D 和上面相反 [^0-9]21 \s 匹配空白符22 \S 和上面相反5、贪婪与非贪婪 #贪婪模式 #贪婪概念匹配尽可能多的字符# . 匹配换行符以外的字符至少一次 # .* 匹配换行符以外的字符任意次res re.search(b./b, b/bbb标签/b) res re.search(b.*/b, bb标签/bbb标签/bbb标签/bbb标签/b)# .? 匹配换行符以外的字符至少一次 拒绝贪婪 # .*? 匹配换行符以外的字符任意次 拒绝贪婪res re.search(b.?/b, bb标签/bbb标签/b) res re.search(b.*?/b, bb标签/bbb标签/bbb标签/bbb标签/b)6正则用到的方法 1re.search # re.search # 返回第一个匹配的结果 res re.search(a,abcdef343) # 返回一个对象 re.Match object; span(0, 1), matcha # 匹配上才可以用group拿结果不然的话匹配不上返回None,不能用group要不然会报错 print(res.group()) # a2re.match res re.match(\d{2},123) print(res.group())#match函数 # match 必须第一位就开始匹配 否则匹配失败 # 给当前匹配到的结果起别名 s 3G4HFD567 x re.match((?Pvalue\d),s) print(x.group(0)) # 3 print(x.group(value)) # 33re.findall # findall str br加粗1/brbr加粗2/brbr加粗3/brbr/br res re.findall(br.*?/br,str) # [br加粗1/br, br加粗2/br, br加粗3/br, br/br] res re.findall(br.*/br,str) # [br加粗1/brbr加粗2/brbr加粗3/brbr/br] res re.findall(br.?/br,str) # [br加粗1/br, br加粗2/br, br加粗3/br] res re.findall(br./br,str) # [br加粗1/brbr加粗2/brbr加粗3/brbr/br]Str a hrefhttp://www.baidu.com百度/a A hrefhttps://www.taobao.com淘宝/A a hrefhttps://www.sina.com新 浪/a # 1匹配出所有小写a的超链接 print(re.findall(a href.*?.*?/a,Str)) # [a hrefhttp://www.baidu.com百度/a]# .*? 匹配任意字符任意次拒绝贪婪 print(re.findall(a href.*?.*?/a,Str,flagsre.S)) # [a hrefhttp://www.baidu.com百度/a, a hrefhttps://www.sina.com新\n浪/a]# 2匹配所有小写a或者大写A的超链接 print(re.findall([aA] href.*?.*?/[aA],Str,flagsre.S)) # [a hrefhttp://www.baidu.com百度/a, A hrefhttps://www.taobao.com淘宝/A, a hrefhttps://www.sina.com新\n浪/a]# 用 re.I 匹配大小写字符 re.S 可以匹配换行符 print(re.findall(a href.*?.*?/a,Str,flagsre.S | re.I)) # [a hrefhttp://www.baidu.com百度/a, A hrefhttps://www.taobao.com淘宝/A, a hrefhttps://www.sina.com新\n浪/a]# 3获取网址和名称 给谁加括号谁就返回 print(re.findall((a href(.*?)(.*?)/a),Str,flagsre.S | re.I)) # [(a hrefhttp://www.baidu.com百度/a, http://www.baidu.com, 百度), (A hrefhttps://www.taobao.com淘宝/A, https://www.taobao.com, 淘宝), (a hrefhttps://www.sina.com新\n浪/a, https://www.sina.com, 新\n浪)]4finditer res re.finditer([a-z],asdjgedksa43g) print(res) # 返回一个迭代器 callable_iterator object at 0x0000015D8995F790 print(next(res)) # re.Match object; span(0, 1), matcha 是一个对象用group来取值 print(next(res).group()) # sfor i in res:print(i) # 返回一个迭代器 callable_iterator object at 0x0000015D8995F790print(i.group()) # 返回结果 5group 和 groups 区别 # group 取第一个匹配的 print(re.search(b.*?/b,b加粗/b).group()) # b加粗/b print(re.search(b(?Pval.*?)/b,b加粗/b).group()) # b加粗/b print(re.search(b(?Pval.*?)/b,b加粗/b).group(0)) # b加粗/b print(re.search(b(?Pval.*?)/b,b加粗/b).group(1)) # 加粗 # print(re.search(b(?Pval.*?)/b,b加粗/b).group(2)) # 报错 print(re.search(b(?Pval.*?)/b,b加粗/b).group(val)) # 加粗# goups 返回所有括号中的值 print(re.search(a href(.*?)(.*?)/a,a hrefwww.baidu.com百度/a).groups()) # (www.baidu.com, 百度)6re.split 正则拆分 print(re.split(\d,fdas3fedsa5fd45fdsa34fg4)) # [fdas, fedsa, fd, , fdsa, , fg, ]7re.sub 正则替换 print(re.sub(\d,---,ab1fdsa456fdsa34fds65as35)) # ab---fdsa---------fdsa------fds------as------8re.compile # compile函数 re_phone re.compile(r(0\d{2,3}-\d{7,8}))s1 luckys phone is 010-88888888 s2 kaiges phone is 010-99999999 ret1 re_phone.search(s1) ret2 re_phone.search(s2)2xpath解析 2-1 导入使用 #导入和使用 from lxml import etree html_tree etree.HTML(html字符串) html_tree.xpath() # 使用xpath路径查询信息返回一个列表from lxml import etree # 第一种方式 parse etree.HTMLParser(encodingUTF-8) tree etree.parse(./素材/豆瓣.html, parserparse) print(tree)# 第二种 推荐 data open(./素材/豆瓣.html, r, encodingUTF-8).read() tree etree.HTML(data) print(tree) 2-2 xpath 的使用 2-2-1 特定路径匹配 # 找登陆 获取当前路径下的所有匹配的a a_list tree.xpath(/html/body/div/div/div/a)for a in a_list:print(a) # Element a at 0x2bdd868bc00print(a.text) # 登录 获取文本## 想要把节点转换成看得懂的字符串标签数据print(etree.tostring(a, encodingUTF-8).decode(UTF-8)) # a hrefhttps://www.douban.com/accounts/login?sourcebook classnav-login relnofollow登录/aa_list tree.xpath(/html/body/div/div/div/a) a_list tree.xpath(/html/body/div/div/div/div/p/text()) a_list tree.xpath(/html/body/div/div/div[1]/a[1]/text()) a_list tree.xpath(/html/body/div/div/div//a/text())2-2-2 获取当前路径下的文本 # 第一种 a_list tree.xpath(/html/body/div/div/div/a/text())# 第二种 a_list tree.xpath(/html/body/div/div/div/a) for a in a_list:print(a.text) #获取文本2-2-3 // # 不考虑当前所在位置# 我想获取当前对象里所有的a a_list tree.xpath(//a) a_list tree.xpath(//a/text())2-2-4 获取属性 # 获取img的src属性值 img_src tree.xpath(//ul/li/a/img/src) img_src tree.xpath(//ul/li//a/img/src)2-2-5 添加条件 # 添加class条件 img_src tree.xpath(//ul[classcover-col-4 clearfix]/li/div/h2/a/text()) img_src tree.xpath(//ul[classcover-col-4 clearfix]/li/div[classdetail-frame]/h2/a/text())2-2-6 位置查找 # 获取第一个li li tree.xpath(//ul[classcover-col-4 clearfix]/li[1]/div/h2/a/text())# 获取第二个li li tree.xpath(//ul[classcover-col-4 clearfix]/li[2]/div/h2/a/text())# 获取最后一个li li tree.xpath(//ul[classcover-col-4 clearfix]/li[last()]/div/h2/a/text())# 获取倒数第二个li li tree.xpath(//ul[classcover-col-4 clearfix]/li[last()-1]/div/h2/a/text())# 获取前俩个li li tree.xpath(//ul[classcover-col-4 clearfix]/li[position()3]/div/h2/a/text())# 可以使用列表切片解决啊 li tree.xpath(//ul[classcover-col-4 clearfix]/li/div/h2/a/text())[0] li tree.xpath(//ul[classcover-col-4 clearfix]/li/div/h2/a/text())[0:2]2-2-7 ./ .// # 一个完整的xpath路径但是可以拆分 li tree.xpath(//ul[classcover-col-4 clearfix]/li/div/h2/a/text())# 先匹配到li 再继续往下匹配 li_list tree.xpath(//ul[classcover-col-4 clearfix]/li) for li in li_list:print(li) # xpath 对象# 从当前位置向下匹配print(li.xpath(./div/h2/a/text()))print(li.xpath(.//div/h2/a/text()))2-2-8 属性一般用不到 # 获取ul的class属性为cover-col-4 clearfix的ul下面的儿子li li_list tree.xpath(//ul[classcover-col-4 clearfix]/li)# 选取所有ul具有class属性的节点 li_list tree.xpath(//ul[class])# 获取所有ul具有aa属性的节点 li_list tree.xpath(//ul[aa]) 2-2-9 多条件 and or | # 多个条件 and or print(tree.xpath(//div[iddb-global-nav])) print(tree.xpath(//div[classglobal-nav]))# 获取同时满足id为db-global-nav class为global-nav 的ul print(tree.xpath(//div[classglobal-nav and iddb-global-nav]))# 获取满足id为db-global-nav 或 class为global-nav 的ul print(tree.xpath(//div[classglobal-nav or iddb-global-nav]))# | print(tree.xpath(//div[iddb-global-nav] | //div[classglobal-nav]))2-3 xpath语法 2-3-1 路径表达式 路径表达式结果/ul/li[1]选取属于 ul子元素的第一个 li元素。/ul/li[last()]选取属于 ul子元素的最后一个 li元素。/ul/li[last()-1]选取属于 ul子元素的倒数第二个 li元素。//ul/li[position()❤️]选取最前面的两个属于 ul元素的子元素的 li元素。//a[title]选取所有拥有名为 title的属性的 a元素。//a[title‘xx’]选取所有 a元素且这些元素拥有值为 xx的 title属性。 2-3-2 选取未知节点 XPath 通配符可用来选取未知的 XML 元素。 通配符描述*匹配任何元素节点。 一般用于浏览器copy xpath会出现*匹配任何属性节点。node()匹配任何类型的节点。 实例 在下面的表格中我们列出了一些路径表达式以及这些表达式的结果 路径表达式结果/ul/*选取 ul元素的所有子元素。//*选取文档中的所有元素。//title[*]选取所有带有属性的 title 元素。//node()获取所有节点 选取未知节点 路径表达式结果//book/title | //book/price选取 book 元素的所有 title 和 price 元素。//title | //price选取文档中的所有 title 和 price 元素。/bookstore/book/title | //price选取属于 bookstore 元素的 book 元素的所有 title 元素以及文档中所有的 price 元素。 2-3-3 逻辑运算 查找所有id属性等于head并且class属性等于s_down的div标签 //div[idhead and classs_down]选取文档中的所有 title 和 price 元素。 //title | //price注意: “|”两边必须是完整的xpath路径 2-3-4 属性查询 查找所有包含id属性的div节点 //div[id]查找所有id属性等于maincontent的div标签 //div[idmaincontent]查找所有的class属性 //class//attrName //li[namexx]//text() # 获取li标签name为xx的里面的文本内容获取第几个标签 索引从1开始 tree.xpath(//li[1]/a/text()) # 获取第一个 tree.xpath(//li[last()]/a/text()) # 获取最后一个 tree.xpath(//li[last()-1]/a/text()) # 获取倒数第二个2-3-5 内容查询 查找所有div标签下的直接子节点h1的内容 //div/h1/text()属性值获取 //div/a/href 获取a里面的href属性值获取所有 //* #获取所有 //*[classxx] #获取所有class为xx的标签获取节点内容转换成字符串 c tree.xpath(//li/a)[0] resultetree.tostring(c, encodingutf-8) print(result.decode(UTF-8))3bs4解析 1导入和使用 from bs4 import BeautifulSoup soup BeautifulSoup(html_doc, lxml) # html进行美化 print(soup.prettify())# 可以传入一段字符串或一个文件句柄. from bs4 import BeautifulSoup soup BeautifulSoup(open(index.html)) soup BeautifulSoup(htmldata/html, lxml)# beautifulsoup lxml from bs4 import BeautifulSoupf open(./素材/豆瓣.html, r, encodingUTF-8) data f.read() # 第一种方式 建议使用这种 soup BeautifulSoup(data, lxml)# 第二种方式 soup BeautifulSoup(open(./素材/豆瓣.html, r, encodingUTF-8), lxml) print(soup) print(type(soup))2浏览器结构化数据 2-1 .语法 soup对象.标签名 ## .标签和.find 只获取第一个soup.title # 获取标签title # titleThe Dormouses story/titlesoup.title.name # 获取标签名称 # titlesoup.title.string # 获取标签title内的内容 # The Dormouses storysoup.title.parent # 获取父级标签soup.title.parent.name # 获取父级标签名称 # headprint(soup.title) print(soup.div) print(soup.a) print(soup.img) print(soup.abc) # 不存在则为None 2-2 soup.find # find 上面的.标签名 是当前find的简写 find可以给条件 .标签和.find 只获取第一个 print(soup.find(title)) print(soup.find(div)) # 获取soup对象中的第一个img标签 print(soup.img) print(soup.find(img))2-3 获取属性 .语法或者find都只获取第一个print(soup.div.attrs) # {id: db-global-nav, class: [global-nav]} print(soup.div.attrs[id]) # db-global-nav print(soup.div.attrs[class]) # [global-nav] print(soup.div[id]) # db-global-nav print(soup.div[class]) # [global-nav]2-4 find 条件查找 print(soup.find(a, class_cover)) # 查找第一个class为cover的a标签 print(soup.find(p, class_rating)) print(soup.find(div, idwrapper)) print(soup.find(div, iddb-global-nav, class_global-nav))## 可以用字典的形式查找满足多个属性的标签 print(soup.find(div, attrs{id: db-global-nav, class: global-nav}))# class为多个的中间空格隔开就行 print(soup.find(ul, attrs{class: cover-col-4 clearfix})) print(soup.find(ul, attrs{class: caover-col-4 clearfix}))2-5 find 和 .语法组合使用 print(soup.find(a, class_cover)) print(type(soup.find(a, class_cover))) # class bs4.element.Tag bs4对象才可以用组合使用 print(soup.find(a, class_cover).find(img)) # 获取第一个a标签里的第一个img print(soup.find(a, class_cover).img) # 获取第一个a标签里的第一个img print(soup.find(a, class_cover).img.attrs) # {src: https://img3.doubanio.com/mpic/s29535271.jpg} print(soup.find(a, class_cover).img.attrs[src]) # https://img3.doubanio.com/mpic/s29535271.jpg print(soup.find(a, class_cover).img[src]) # https://img3.doubanio.com/mpic/s29535271.jpg2-6 写入到文件 # 写入本地需要注意的点 with open(img.html, w, encodingUTF-8) as f:f.write(str(soup.find(a, class_cover).img)) ## 写入本地需要先转换为字符串要不然会报错# f.write(soup.title.string)2-7 获取文本 print(soup.title) # title新书速递/title print(soup.title.string) # 新书速递 print(type(soup.title.string)) # class bs4.element.NavigableString print(soup.title.strings) # generator 对象 print(list(soup.title.strings)) # [新书速递]print(soup.title.text) # 新书速递 print(soup.title.get_text()) # 新书速递 print(soup.title.stripped_strings) # generator 对象 print(list(soup.title.stripped_strings)) # [新书速递]2-8 多层嵌套标签 ## string 和 strings 区别 print(soup.find(div, class_detail-frame)) print(soup.find(div, class_detail-frame).string) # None print(soup.find(div, class_detail-frame).strings) # generator 对象 print(list(soup.find(div, class_detail-frame).strings)) # 获取子子孙孙的文本 生成器返回# text , get_text() , stripped_strings 区别 print(soup.find(div, class_detail-frame).text) # 返回所有文本字符串 包含非打印字符 print(soup.find(div, class_detail-frame).get_text()) #和text一样 返回所有文本字符串 包含非打印字符 print(list(soup.find(div, class_detail-frame).stripped_strings)) # 返回所有去除空白字符后的文本2-9 prettify 美化 print(soup.find(div, class_detail-frame)) print(soup.find(div, class_detail-frame).prettify())2-10 find_all # 查找所有 和find区别就是 查找所有 参数一样使用 find返回一个 find_all返回列表 print(soup.find_all(img)) # 返回列表 print(soup.find_all(div, iddb-global-nav, class_global-nav)) print(soup.find_all(div, attrs{id: db-global-nav, class: global-nav})) print(soup.find_all(div, limit2)) # 取几个值 没啥用(我们用切片就完事了) print(soup.find_all([h2, img])) # 获取h2和img标签2-11 select # select 查找所有 条件是选择器 print(soup.select(img)) print(soup.select(.cover)) print(soup.select(#db-global-nav)) print(soup.select(.cover-col-4.clearfix)) print(soup.select(.cover-col-4.clearfix#abc)) print(soup.select(ul[classcover-col-4 clearfix])) print(soup.select(.cover-col-4.clearfix li img))三常用工具模块 1os模块 import os # 判断文件是否存在 os.path.exists() # 判断文件或者文件夹是否存在返回布尔值os.path.join() # 路径拼接 os.path.join(path1,path2,path3)os.makedirs() # 创建文件夹os.getcwd() # 获取当前工作目录即当前python脚本工作的目录路径 os.chdir(dirname) # 改变当前脚本工作目录相当于shell下cd os.curdir # 返回当前目录: (.) os.pardir # 获取当前目录的父目录字符串名(..) os.makedirs(dirname1/dirname2) # 可生成多层递归目录 os.removedirs(dirname1) # 若目录为空则删除并递归到上一级目录如若也为空则删除依此类推 os.mkdir(dirname) # 生成单级目录相当于shell中mkdir dirname os.rmdir(dirname) # 删除单级空目录若目录不为空则无法删除报错相当于shell中rmdir dirname os.listdir(dirname) # 列出指定目录下的所有文件和子目录包括隐藏文件并以列表方式打印 os.remove() # 删除一个文件 os.rename(oldname,newname) # 重命名文件/目录 os.stat(path/filename) # 获取文件/目录信息 os.sep # 输出操作系统特定的路径分隔符win下为\\,Linux下为/ os.linesep # 输出当前平台使用的行终止符win下为\t\n,Linux下为\n os.pathsep # 输出用于分割文件路径的字符串 win下为;,Linux下为: os.name # 输出字符串指示当前使用平台。win-nt; Linux-posix os.system(bash command) # 运行shell命令直接显示 os.environ # 获取系统环境变量 os.path.abspath(path) # 返回path规范化的绝对路径 os.path.split(path) # 将path分割成目录和文件名二元组返回 os.path.dirname(path) # 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) # 返回path最后的文件名。如何path以或\结尾那么就会返回空值。即os.path.split(path)的第二个元素os.path.exists(path) # 如果path存在返回True如果path不存在返回False os.path.isabs(path) # 如果path是绝对路径返回True os.path.isfile(path) # 如果path是一个存在的文件返回True。否则返回False os.path.isdir(path) #如果path是一个存在的目录则返回True。否则返回False os.path.join(path1[, path2[, ...]]) # 将多个路径组合后返回第一个绝对路径之前的参数将被忽略 os.path.getatime(path) # 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) # 返回path所指向的文件或者目录的最后修改时间 os.path.getsize(path) # 返回path的大小2json模块 ## JSON格式兼容的是所有语言通用的数据类型不能支持单一数据类型# JSON ---------字典 dic json.loads(s)# 字典-----------JSON s json.dumps(dic)import json ## 有时保存下来的中文数据打开后发现变成ASCII码这是需要将ensure_ascii参数设置成Falsedata {name : name,age : 20,}json_str json.dumps(data,ensure_asciiFalse)# josn.dumpdata {name:name,age:20,}#讲python编码成json放在那个文件里filename a.txtwith open (filename,w) as f:json.dump(data ,f)## json.load data {name:name,age:20}filename a.txtwith open (filename,w) as f:json.dump(data,f)with open (filename) as f_:print(json.load(f_)) 2.1 猴子补丁S ### 在入扣文件处进行猴子补丁 import json import ujsondef monkey_patch_json():json.__name__ ujsonjson.dumps ujson.dumpsjson.loads ujson.loadsmonkey_patch_json()3random模块 a random.choice(abcdefghijklmn) # 参数也可以是个列表a abcdefghijklmnop1234567890 b random.sample(a,3) # 随机取三个值返回一个列表num random.randint(1,100)1random.random() # 得到的是 0----1 之间的小数 -------------- 0.6400374661599008 2random.randint(1,3) # 范围是 [1,3] 包头包尾 3random.randrange(1,2) # 范围是 [1,3) 顾头不顾尾 4random.chioce(abcdefghijklmn) # 参数也可以是个列表 5random.sample([a,b,c,d],3) # 随机取三个值返回一个列表6random.uniform(1,3) # 得到 1-------3 之间的浮点数item [1,2,3,4,5,6,7,8,9] 7random.shuffle(item) # 洗牌打乱顺序 [4, 1, 2, 9, 7, 5, 6, 3, 8]4string模块 string.ascii_letters # 返回小写字母大写字母字符串 # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZstring.ascii_uppercase # 返回大写字母的字符串 # ABCDEFGHIJKLMNOPQRSTUVWXYZstring.ascii_lowercase # 返回小写字母的字符串 # abcdefghijklmnopqrstuvwxyzstring.punctuation # 打印特殊字符 # !#$%()*,-./:;?[\]^_{|}~string.digits # 打印数字 # 01234567895异常处理 5.1 错误类型 ## 语法错误 SyntaxError ## 逻辑错误 NameError IndexError ZeroDivisionError ValueError## 一种是语法上的错误SyntaxError这种错误应该在程序运行前就修改正确if File stdin, line 1if^ SyntaxError: invalid syntax# ------------------------------------------------------------------------------------------- # TypeError数字类型无法与字符串类型相加 1’2’# ValueError当字符串包含有非数字的值时无法转成int类型numinput(: ) #输入helloint(num)# NameError引用了一个不存在的名字xx# IndexError索引超出列表的限制l[egon,aa]l[3]# KeyError引用了一个不存在的keydic{name:egon}dic[age]# AttributeError引用的属性不存在class Foo:passFoo.x# ZeroDivisionError除数不能为01/05.1 逻辑错误两种处理方式 5.1.1 错误时可以预知的 age input(:).strip()if age.isdigit(): ## 可以用if 判断避免错误出现age int(age) ## age必须是数字才能转换为int类型if age 18:print(猜大了)else:print(猜小了)5.1.2 错误时不可预知的 ## 只要抛出异常同级别的代码不会往下运行try:##有可能抛出异常的子代码块except 异常类型1 as e:pass except 异常类型2 as e:pass.... else:## 如果被检测的子代码块没有异常发生则运行else finally:## 无论有没有异常发生都会运行此代码## --------------------------------------------------------------------------------------------## 用法一 try:print(11111111111)l [aaa,bbbb]l[3] ## 抛出异常IndexError该码块同级别的后续代码不会运行print(222222222222222)xxxprint(3333333333333333333)dic {a:1}dic[a]print(end) except IndexError as e:print(异常处理了)print(e) except NameError as e:print(异常处理了)print(e)## -------------------------------------------------------------------------------------- # 用法二print(start) try:print(11111111111)l [aaa,bbbb]l[3] ## 抛出异常IndexError该码块同级别的后续代码不会运行print(222222222222222)# xxxprint(3333333333333333333)dic {a:1}dic[a]print(end) except (IndexError,NameError) as e:print(异常处理了) except KeyError as e:print(字典的key不存在,e)## ------------------------------------------------------------------------------------------ ## 用法三 ## 万能异常print(start) try:print(11111111111)l [aaa,bbbb]l[3] ## 抛出异常IndexError该码块同级别的后续代码不会运行print(222222222222222)# xxxprint(3333333333333333333)dic {a:1}dic[a]print(end) except Exception as e: ## 万能异常都能匹配上print(万能异常) ## ----------------------------------------------------------------------------------------## 方法四 ##tyr 不能跟 else 连用try:print(11111111111111)print(33333333333)print(2222222222222222222) except Exception as e:print(所有异常都能匹配到) else:print()print(end...........)## ------------------------------------------------------------------------------------------## 方法五 ## finally 可以单独与try配合使用print(start) try:print(11111111111)l [aaa,bbbb]l[3] ## 抛出异常IndexError该码块同级别的后续代码不会运行print(222222222222222)xxxprint(3333333333333333333)dic {a:1}dic[a]print(end) finally: ## 应该把被检测代码中回收系统化资源的代码放这里print(我不处理异常无论是否发生异常我都会运行)6打码平台使用 import base64 import json import requests def base64_api(uname, pwd, img, typeid):with open(img, rb) as f:base64_data base64.b64encode(f.read())b64 base64_data.decode()data {username: uname, password: pwd, typeid: typeid, image: b64}result json.loads(requests.post(http://api.ttshitu.com/predict, jsondata).text)if result[success]:return result[data][result]else:#注意返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别return result[message]return if __name__ __main__:img_path ./code.pngresult base64_api(unamexxxxx, pwdxxxxx, imgimg_path, typeid3)print(result)import base64 import json import requests # 一、图片文字类型(默认 3 数英混合) # 1 : 纯数字 # 1001纯数字2 # 2 : 纯英文 # 1002纯英文2 # 3 : 数英混合 # 1003数英混合2 # 4 : 闪动GIF # 7 : 无感学习(独家) # 11 : 计算题 # 1005: 快速计算题 # 16 : 汉字 # 32 : 通用文字识别(证件、单据) # 66: 问答题 # 49 :recaptcha图片识别 # 二、图片旋转角度类型 # 29 : 旋转类型 # # 三、图片坐标点选类型 # 19 : 1个坐标 # 20 : 3个坐标 # 21 : 3 ~ 5个坐标 # 22 : 5 ~ 8个坐标 # 27 : 1 ~ 4个坐标 # 48 : 轨迹类型 # # 四、缺口识别 # 18 : 缺口识别需要2张图 一张目标图一张缺口图 # 33 : 单缺口识别返回X轴坐标 只需要1张图 # 五、拼图识别 # 53拼图识别 def base64_api(uname, pwd, img, typeid):with open(img, rb) as f:base64_data base64.b64encode(f.read())b64 base64_data.decode()data {username: uname, password: pwd, typeid: typeid, image: b64}result json.loads(requests.post(http://api.ttshitu.com/predict, jsondata).text)if result[success]:return result[data][result]else:#注意返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别return result[message]return if __name__ __main__:img_path C:/Users/Administrator/Desktop/file.jpgresult base64_api(uname你的账号, pwd你的密码, imgimg_path, typeid3)print(result)7时间模块 7.1 time 模块 import time# 时间戳 从1970年到现在经过的秒数 time.time() # 时间戳---------用于计算# 按照某种格式显示时间 2020-03-30 11:11:11 AM || PM time.strftime(%Y-%m-%d %H:%M:%S %p) # 2023-06-27 14:24:38 PM time.strftime(%Y-%m-%d %X) # 2023-06-27 14:24:38#结构化时间 res time.localtime() ## --------------获取年月日 print(res) ## time.struct_time(tm_year2023, tm_mon6, tm_mday27, tm_hour14, tm_min26, tm_sec17, tm_wday1, tm_yday178, tm_isdst0)print(res.tm_year) ## 年 print(res.tm_mon) ## 月 print(res.tm_mday) ## 日 print(res.tm_hour) ## 小时 print(res.tm_min) ## 分钟 print(res.tm_sec) ## 秒 print(res.tm_wday) print(res.tm_yday) print(res.tm_isdst) 7.2 datetime 模块 import datetimedatetime.datetime.now() ## 2023-06-27 14:38:31.929938datetime.datetime.now() datetime.timedelta(days 3) ## 三天后的时间 2023-06-30 14:40:55.794329 # 参数有 days || secondes || weeks || hours || minutes # days 3 || -3 参数可以 为负数 7.3 时间格式的转换 import time1时间戳 ----------------- 结构化时间# 结构化时间 ------------------------- 时间戳s_time time.localtime() # 结构化时间res time.mktime(s_time)print(res) # 1687848357.0# 时间戳 --------------------------------- 结构化时间tp_time time.time()res time.localtime(tp_time)print(res) # time.struct_time(tm_year2023, tm_mon6, tm_mday27, tm_hour14, tm_min48, tm_sec36, tm_wday1,tm_yday178, tm_isdst0) # 时间戳 -------------------------------- 世界标准时间 --------- 跟本地时间差8小时tp_time time.time()res time.gmtime(tp_time)print(res) # time.struct_time(tm_year2023, tm_mon6, tm_mday27, tm_hour6, tm_min50, tm_sec35, tm_wday1,tm_yday178, tm_isdst0)2, 结构化 ------------------------- 格式化时间## time.strptime(%Y-%m-%d %H:%M:%S %p,time.localtime())res time.strptime(1988-03-03 11:11:11,%Y-%m-%d %H:%M:%S)print(res)## time.struct_time(tm_year1988, tm_mon3, tm_mday3, tm_hour11, tm_min11, tm_sec11, tm_wday3, tm_yday63, tm_isdst-1)1988-03-03 11:11:11 7 ----------------------- 结构化时间s_time time.strptime(1988-03-03 11:11:11,%Y-%m-%d %H:%M:%S) # 结构化时间miao time.mktime(s_time) 7 * 86400 ## 得到时间戳struct_time time.localtime(miao) ## 得到结构化时间res time.strftime(%Y-%m-%d %X,time.localtime(miao)) # 格式化时间print(res) # 1988-03-10 11:11:11 7.4 了解 import time ## linix 操作系统上常见 print(time.asctime()) # Tue Jun 27 15:26:23 20238, sys模块 1 sys.argv # 命令行参数List第一个元素是程序本身路径用于获取终端里的参数 2 sys.exit(n) # 退出程序正常退出时exit(0) 3 sys.version # 获取Python解释程序的版本信息 4 sys.maxint # 最大的Int值 5 sys.path # 返回模块的搜索路径初始化时使用PYTHONPATH环境变量的值 6 sys.platform # 返回操作系统平台名称8.1 打印进度条 import timedef process():recv_size 0total_size 333333while recv_size total_size:# 下载了1024个字节数据time.sleep(0.05)recv_size 1024if recv_size total_size:recv_size total_sizepercent recv_size / total_sizeres int(50 * percent) * ## 打印进度条print(\r[%-50s] %d%% % (res,100 * percent) ,end)process()## [##################################################] 100%9shutii 模块 import shutill# 将文件内容拷贝到另一个文件中 shutil.copyfileobj(open(old.xml,r), open(new.xml, w))# 仅拷贝权限。内容、组、用户均不变 shutil.copymode(f1.log, f2.log) #目标文件必须存在# 拷贝文件 shutil.copyfile(f1.log, f2.log) #目标文件无需存在# 仅拷贝状态的信息包括mode bits, atime, mtime, flags shutil.copystat(f1.log, f2.log) #目标文件必须存在# 拷贝文件和权限 shutil.copy(f1.log, f2.log)# 拷贝文件和状态信息 shutil.copy2(f1.log, f2.log)# 递归的去拷贝文件夹shutil.copytree(folder1, folder2, ignoreshutil.ignore_patterns(*.pyc, tmp*)) # 目标目录不能存在注意对folder2目录父级目录要有可写权限ignore的意思是排除shutil.copytree(f1, f2, symlinksTrue, ignoreshutil.ignore_patterns(*.pyc, tmp*))通常的拷贝都把软连接拷贝成硬链接即对待软连接来说创建新的文件 #递归的去删除文件 shutil.rmtree(folder1)#递归的去移动文件它类似mv命令其实就是重命名。 shutil.move(folder1, folder3)# 创建压缩包并返回文件路径例如zip、tar # 创建压缩包并返回文件路径例如zip、tarbase_name 压缩包的文件名也可以是压缩包的路径。只是文件名时则保存至当前目录否则保存至指定路径# 如 data_bak 保存至当前路径# 如/tmp/data_bak 保存至/tmp/ format 压缩包种类“zip”, “tar”, “bztar”“gztar” root_dir 要压缩的文件夹路径默认当前目录 owner 用户默认当前用户 group 组默认当前组 logger 用于记录日志通常是logging.Logger对象#将 /data 下的文件打包放置当前程序目录 ret shutil.make_archive(data_bak, gztar, root_dir/data)#将 /data下的文件打包放置 /tmp/目录 ret shutil.make_archive(/tmp/data_bak, gztar, root_dir/data) #shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的详细 import zipfile# 压缩z zipfile.ZipFile(laxi.zip, w)z.write(a.log)z.write(data.data)z.close()# 解压z zipfile.ZipFile(laxi.zip, r)z.extractall(path.)z.close()import tarfile# 压缩ttarfile.open(/tmp/egon.tar,w)t.add(/test1/a.py,arcnamea.bak)t.add(/test1/b.py,arcnameb.bak)t.close()# 解压ttarfile.open(/tmp/egon.tar,r)t.extractall(/egon)t.close()10pickle模块(有兼容性问题了解就行) import pickleres pickle.dumps({1,2,3,4,5}) print(res) # b\x80\x04\x95\x0f\x00\x00\x00\x00\x00\x00\x00\x8f\x94(K\x01K\x02K\x03K\x04K\x05\x90.res pickle.loads(res) print(res) # {1, 2, 3, 4, 5}# coding:utf-8 import picklewith open(a.pkl,modewb) as f:# 一在python3中执行的序列化操作如何兼容python2# python2不支持protocol2默认python3中protocol4# 所以在python3中dump操作应该指定protocol2pickle.dump(你好啊,f,protocol2)with open(a.pkl, moderb) as f:# 二python2中反序列化才能正常使用respickle.load(f)print(res) 11xml模块 ?xml version1.0? datacountry nameLiechtensteinrank updatedyes2/rankyear2008/yeargdppc141100/gdppcneighbor nameAustria directionE/neighbor nameSwitzerland directionW//countrycountry nameSingaporerank updatedyes5/rankyear2011/yeargdppc59900/gdppcneighbor nameMalaysia directionN//countrycountry namePanamarank updatedyes69/rankyear2011/yeargdppc13600/gdppcneighbor nameCosta Rica directionW/neighbor nameColombia directionE//country /dataxml协议在各个语言里的都 是支持的在python中可以用以下模块操作xml # print(root.iter(year)) #全文搜索 # print(root.find(country)) #在root的子节点找只找一个 # print(root.findall(country)) #在root的子节点找找所有import xml.etree.ElementTree as ETtree ET.parse(xmltest.xml) root tree.getroot() print(root.tag)#遍历xml文档for child in root:print(,child.tag,child.attrib,child.attrib[name])for i in child:print(i.tag,i.attrib,i.text)#只遍历year 节点for node in root.iter(year):print(node.tag,node.text) #---------------------------------------import xml.etree.ElementTree as ETtree ET.parse(xmltest.xml) root tree.getroot()#修改for node in root.iter(year):new_yearint(node.text)1node.textstr(new_year)node.set(updated,yes)node.set(version,1.0)tree.write(test.xml)#删除nodefor country in root.findall(country):rank int(country.find(rank).text)if rank 50:root.remove(country)tree.write(output.xml)#在country内添加append节点year2import xml.etree.ElementTree as ETtree ET.parse(a.xml)roottree.getroot()for country in root.findall(country):for year in country.findall(year):if int(year.text) 2000:year2ET.Element(year2)year2.text新年year2.attrib{update:yes}country.append(year2) #往country节点下添加子节点tree.write(a.xml.swap)自己创建xml文档import xml.etree.ElementTree as ETnew_xml ET.Element(namelist)name ET.SubElement(new_xml,name,attrib{enrolled:yes})age ET.SubElement(name,age,attrib{checked:no})sex ET.SubElement(name,sex)sex.text 33name2 ET.SubElement(new_xml,name,attrib{enrolled:no})age ET.SubElement(name2,age)age.text 19et ET.ElementTree(new_xml) #生成文档对象et.write(test.xml, encodingutf-8,xml_declarationTrue)ET.dump(new_xml) #打印生成的格式12configparser模块导入某种格式的配置文件 ## 配置文件内容[section1] k1 v1 k2:v2 useregon age18 is_admintrue salary31[section2] k1 v1 12.1 读取 import configparserconfigconfigparser.ConfigParser() config.read(a.cfg) # 读取配置文件#查看所有的标题 resconfig.sections() #[section1, section2] print(res)#查看标题section1下所有keyvalue的key optionsconfig.options(section1) print(options) #[k1, k2, user, age, is_admin, salary]#查看标题section1下所有keyvalue的(key,value)格式 item_listconfig.items(section1) print(item_list) #[(k1, v1), (k2, v2), (user, egon), (age, 18), (is_admin, true), (salary, 31)]#查看标题section1下user的值字符串格式 valconfig.get(section1,user) print(val) #egon#查看标题section1下age的值整数格式 val1config.getint(section1,age) print(val1) #18#查看标题section1下is_admin的值布尔值格式 val2config.getboolean(section1,is_admin) print(val2) #True#查看标题section1下salary的值浮点型格式 val3config.getfloat(section1,salary) print(val3) #31.0 12.2 改写 import configparserconfigconfigparser.ConfigParser() config.read(a.cfg,encodingutf-8)#删除整个标题section2 config.remove_section(section2)#删除标题section1下的某个k1和k2 config.remove_option(section1,k1) config.remove_option(section1,k2)#判断是否存在某个标题 print(config.has_section(section1))#判断标题section1下是否有user print(config.has_option(section1,))#添加一个标题 config.add_section(egon)#在标题egon下添加nameegon,age18的配置 config.set(egon,name,egon) config.set(egon,age,18) #报错,必须是字符串#最后将修改的内容写入文件,完成最终的修改 config.write(open(a.cfg,w))13 hashlib 模块 # hash是一类算法该算法根据传入的内容经过运算得到一串哈希值# hash值的特单1传入的内容一样则得到的结果一样2无论传多大内容得到的hash值长度一样3不能反向破解14 subprocess模块 import subprocess sh-3.2# ls /Users/egon/Desktop |grep txt$mysql.txttt.txt事物.txt ## 查看 /Users/jieli/Desktop 下的文件列表 res1subprocess.Popen(ls /Users/jieli/Desktop,shellTrue,stdoutsubprocess.PIPEstderrsubprocess.PIPE) # shell True 意思是调一个终端 stdout 是正确结果的输出管道 stderr 是接受错误结果的输出管道 # res1 是对象 print(res2.stdout.read()) # 打印正确的结果得到的格式是字节解码用的是系统的编码格式,mac为utf-8 print(res1.stderr.read()) # 打印错误的结果得到的是字节格式解码用的是系统的编码格式windows为gbkressubprocess.Popen(grep txt$,shellTrue,stdinres1.stdout,stdoutsubprocess.PIPE) print(res.stdout.read().decode(utf-8))#等同于上面,但是上面的优势在于,一个数据流可以和另外一个数据流交互,可以通过爬虫得到结果然后交给grep res1subprocess.Popen(ls /Users/jieli/Desktop |grep txt$,shellTrue,stdoutsubprocess.PIPE) print(res1.stdout.read().decode(utf-8))#windows下: # dir | findstr test* # dir | findstr txt$import subprocess res1subprocess.Popen(rdir C:\Users\Administrator\PycharmProjects\test\函数备课,shellTrue,stdoutsubprocess.PIPE) ressubprocess.Popen(findstr test*,shellTrue,stdinres1.stdout,stdoutsubprocess.PIPE)print(res.stdout.read().decode(gbk)) #subprocess使用当前系统默认编码得到结果为bytes类型在windows下需要用gbk解码15日志模块logging 14.1 日志级别 import loggingCRITICAL 50 #FATAL CRITICAL ERROR 40 WARNING 30 #WARN WARNING INFO 20 DEBUG 10 NOTSET 0 #不设置14.2 默认级别为warning默认打印到终端 import logginglogging.debug(调试debug) logging.info(消息info) logging.warning(警告warn) ## WARNING:root:警告warn logging.error(错误error) ## ERROR:root:错误error logging.critical(严重critical) ## CRITICAL:root:严重critical WARNING:root:警告warn ERROR:root:错误error CRITICAL:root:严重critical14.3 为logging模块指定全局配置针对所有logger有效控制打印到文件中 可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为可用参数有filename用指定的文件名创建FiledHandler后边会具体讲解handler的概念这样日志会被存储在指定的文件中。filemode文件打开方式在指定了filename时使用这个参数默认值为“a”还可指定为“w”。format指定handler使用的日志显示格式。datefmt指定日期时间格式。level设置rootlogger后边会讲解具体概念的日志级别stream用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件默认为sys.stderr。若同时列出了 filename和stream两个参数则stream参数会被忽略。## 例如 logging.basicConfig(format %(asctime)s - %(name)s - %(levelname)s - %(module)s # 就这样自定义格式 ) format参数中可能用到的格式化串 %(name)s # Logger的名字 %(levelno)s # 数字形式的日志级别 %(levelname)s # 文本形式的日志级别 %(pathname)s # 调用日志输出函数的模块的完整路径名可能没有 %(filename)s # 调用日志输出函数的模块的文件名 %(module)s # 调用日志输出函数的模块名 %(funcName)s # 调用日志输出函数的函数名 %(lineno)d # 调用日志输出函数的语句所在的代码行 %(created)f # 当前时间用UNIX标准的表示时间的浮 点数表示 %(relativeCreated)d # 输出日志信息时的自Logger创建以 来的毫秒数 %(asctime)s # 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 %(thread)d # 线程ID。可能没有 %(threadName)s # 线程名。可能没有 %(process)d # 进程ID。可能没有 %(message)s # 用户输出的消息14.4 使用例子 #使用import logging logging.basicConfig(## 写到文件里的编码格式以系统编码格式为准Windows为gbkfilenameaccess.log, ## 日志输出的位置format%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s, ## 一个日志输出的格式datefmt%Y-%m-%d %H:%M:%S %p, ## 输出里的时间格式level10 ## 日志错误级别 )logging.debug(调试debug) logging.info(消息info) logging.warning(警告warn) logging.error(错误error) logging.critical(严重critical)#结果 access.log内容: 2017-07-28 20:32:17 PM - root - DEBUG -test: 调试debug 2017-07-28 20:32:17 PM - root - INFO -test: 消息info 2017-07-28 20:32:17 PM - root - WARNING -test: 警告warn 2017-07-28 20:32:17 PM - root - ERROR -test: 错误error 2017-07-28 20:32:17 PM - root - CRITICAL -test: 严重critical14.5 logging模块的FormatterHandlerLoggerFilter对象 #logger产生日志的对象 #Filter过滤日志的对象 #Handler接收日志然后控制打印到不同的地方FileHandler用来打印到文件中StreamHandler用来打印到终端 #Formatter对象可以定制不同的日志格式对象然后绑定给不同的Handler对象使用以此来控制不同的Handler的日志格式 critical50 error 40 warning 30 info 20 debug 10 import logging#1、logger对象负责产生日志然后交给Filter过滤然后交给不同的Handler输出 loggerlogging.getLogger(__file__)#2、Filter对象不常用略#3、Handler对象接收logger传来的日志然后控制输出 h1logging.FileHandler(t1.log) #打印到文件 h2logging.FileHandler(t2.log) #打印到文件 h3logging.StreamHandler() #打印到终端#4、Formatter对象日志格式 formmater1logging.Formatter(%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s,datefmt%Y-%m-%d %H:%M:%S %p, )formmater2logging.Formatter(%(asctime)s : %(message)s,datefmt%Y-%m-%d %H:%M:%S %p, )formmater3logging.Formatter(%(name)s %(message)s,)#5、为Handler对象绑定格式 h1.setFormatter(formmater1) h2.setFormatter(formmater2) h3.setFormatter(formmater3)#6、将Handler添加给logger并设置日志级别 logger.addHandler(h1) logger.addHandler(h2) logger.addHandler(h3) logger.setLevel(10)#7、测试 logger.debug(debug) logger.info(info) logger.warning(warning) logger.error(error) logger.critical(critical)14.6 Logger与Handler的级别 ### logger是第一级过滤然后才能到handler我们可以给logger和handler同时设置level#验证 import loggingformlogging.Formatter(%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s,datefmt%Y-%m-%d %H:%M:%S %p, )chlogging.StreamHandler()ch.setFormatter(form) # ch.setLevel(10) ch.setLevel(20)l1logging.getLogger(root) # l1.setLevel(20) l1.setLevel(10) l1.addHandler(ch)l1.debug(l1 debug)14.7 Logger的继承了解 import loggingformatterlogging.Formatter(%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s,datefmt%Y-%m-%d %H:%M:%S %p,)chlogging.StreamHandler() ch.setFormatter(formatter)logger1logging.getLogger(root) logger2logging.getLogger(root.child1) logger3logging.getLogger(root.child1.child2)logger1.addHandler(ch) logger2.addHandler(ch) logger3.addHandler(ch) logger1.setLevel(10) logger2.setLevel(10) logger3.setLevel(10)logger1.debug(log1 debug) logger2.debug(log2 debug) logger3.debug(log3 debug)2017-07-28 22:22:05 PM - root - DEBUG -test: log1 debug 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 2017-07-28 22:22:05 PM - root.child1 - DEBUG -test: log2 debug 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug 2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test: log3 debug14.8 应用 14.8.1 logging配置 logging配置 import os import logging.config# 定义三种日志输出格式 开始standard_format [%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d] \[%(levelname)s][%(message)s] #其中name为getlogger指定的名字simple_format [%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)sid_simple_format [%(levelname)s][%(asctime)s] %(message)s# 定义日志输出格式 结束logfile_dir os.path.dirname(os.path.abspath(__file__)) # log文件的目录logfile_name all2.log # log文件名# 如果不存在定义的日志目录就创建一个 if not os.path.isdir(logfile_dir):os.mkdir(logfile_dir)# log文件的全路径 logfile_path os.path.join(logfile_dir, logfile_name)# log配置字典 LOGGING_DIC {version: 1,disable_existing_loggers: False,formatters: {standard: {format: standard_format},simple: {format: simple_format},},filters: {},handlers: {#打印到终端的日志console: {level: DEBUG,class: logging.StreamHandler, # 打印到屏幕formatter: simple},#打印到文件的日志,收集info及以上的日志default: {level: DEBUG,class: logging.handlers.RotatingFileHandler, # 保存到文件formatter: standard,filename: logfile_path, # 日志文件maxBytes: 1024*1024*5, # 日志大小 5MbackupCount: 5,encoding: utf-8, # 日志文件的编码再也不用担心中文log乱码了},},loggers: {#logging.getLogger(__name__)拿到的logger配置: {handlers: [default, console], # 这里把上面定义的两个handler都加上即log数据既写入文件又打印到屏幕level: DEBUG,propagate: True, # 向上更高level的logger传递},}, }def load_my_logging_cfg():logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置logger logging.getLogger(__name__) # 生成一个log实例logger.info(It works!) # 记录该文件的运行状态if __name__ __main__:load_my_logging_cfg()14.8.2 使用 MyLogging Test import time import logging import my_logging # 导入自定义的logging配置logger logging.getLogger(__name__) # 生成logger实例def demo():logger.debug(start range... time:{}.format(time.time()))logger.info(中文测试开始。。。)for i in range(10):logger.debug(i:{}.format(i))time.sleep(0.2)else:logger.debug(over range... time:{}.format(time.time()))logger.info(中文测试结束。。。)if __name__ __main__:my_logging.load_my_logging_cfg() # 在你程序文件的入口加载自定义logging配置demo()14.8.3 注意注意注意 MyLogging Test import time import logging import my_logging # 导入自定义的logging配置logger logging.getLogger(__name__) # 生成logger实例def demo():logger.debug(start range... time:{}.format(time.time()))logger.info(中文测试开始。。。)for i in range(10):logger.debug(i:{}.format(i))time.sleep(0.2)else:logger.debug(over range... time:{}.format(time.time()))logger.info(中文测试结束。。。)if __name__ __main__:my_logging.load_my_logging_cfg() # 在你程序文件的入口加载自定义logging配置demo()14.8.4 另外一个django的配置瞄一眼就可以跟上面的一样 #logging_config.py LOGGING {version: 1,disable_existing_loggers: False,formatters: {standard: {format: [%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d][%(levelname)s][%(message)s]},simple: {format: [%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s},collect: {format: %(message)s}},filters: {require_debug_true: {(): django.utils.log.RequireDebugTrue,},},handlers: {#打印到终端的日志console: {level: DEBUG,filters: [require_debug_true],class: logging.StreamHandler,formatter: simple},#打印到文件的日志,收集info及以上的日志default: {level: INFO,class: logging.handlers.RotatingFileHandler, # 保存到文件自动切filename: os.path.join(BASE_LOG_DIR, xxx_info.log), # 日志文件maxBytes: 1024 * 1024 * 5, # 日志大小 5MbackupCount: 3,formatter: standard,encoding: utf-8,},#打印到文件的日志:收集错误及以上的日志error: {level: ERROR,class: logging.handlers.RotatingFileHandler, # 保存到文件自动切filename: os.path.join(BASE_LOG_DIR, xxx_err.log), # 日志文件maxBytes: 1024 * 1024 * 5, # 日志大小 5MbackupCount: 5,formatter: standard,encoding: utf-8,},#打印到文件的日志collect: {level: INFO,class: logging.handlers.RotatingFileHandler, # 保存到文件自动切filename: os.path.join(BASE_LOG_DIR, xxx_collect.log),maxBytes: 1024 * 1024 * 5, # 日志大小 5MbackupCount: 5,formatter: collect,encoding: utf-8}},loggers: {#logging.getLogger(__name__)拿到的logger配置: {handlers: [default, console, error],level: DEBUG,propagate: True,},#logging.getLogger(collect)拿到的logger配置collect: {handlers: [console, collect],level: INFO,}}, }# ----------- # 用法:拿到俩个loggerlogger logging.getLogger(__name__) #线上正常的日志 collect_logger logging.getLogger(collect) #领导说,需要为领导们单独定制领导们看的日志14.9 直奔主题常规使用 14.9.1 日志级别与配置 import logging # 在 # 一日志配置 logging.basicConfig(# 1、日志输出位置1、终端 2、文件# filenameaccess.log, # 不指定默认打印到终端# 2、日志格式format%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s,# 3、时间格式datefmt%Y-%m-%d %H:%M:%S %p,# 4、日志级别# critical 50# error 40# warning 30# info 20# debug 10level30, )# 二输出日志 logging.debug(调试debug) logging.info(消息info) logging.warning(警告warn) logging.error(错误error) logging.critical(严重critical) # 注意下面的root是默认的日志名字 WARNING:root:警告warn ERROR:root:错误error CRITICAL:root:严重critical14.9.2 日志配置字典setting.py logging配置 在 setting.py中定义 import os# 1、定义三种日志输出格式日志中可能用到的格式化串如下 # %(name)s Logger的名字 # %(levelno)s 数字形式的日志级别 # %(levelname)s 文本形式的日志级别 # %(pathname)s 调用日志输出函数的模块的完整路径名可能没有 # %(filename)s 调用日志输出函数的模块的文件名 # %(module)s 调用日志输出函数的模块名 # %(funcName)s 调用日志输出函数的函数名 # %(lineno)d 调用日志输出函数的语句所在的代码行 # %(created)f 当前时间用UNIX标准的表示时间的浮 点数表示 # %(relativeCreated)d 输出日志信息时的自Logger创建以 来的毫秒数 # %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 # %(thread)d 线程ID。可能没有 # %(threadName)s 线程名。可能没有 # %(process)d 进程ID。可能没有 # %(message)s用户输出的消息# 2、强调其中的%(name)s为getlogger时指定的名字 ## 这些是预先定义好的自定义格式 standard_format [%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d] \[%(levelname)s][%(message)s]simple_format [%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)stest_format %(asctime)s] %(message)s# 3、日志配置字典 LOGGING_DIC {version: 1,disable_existing_loggers: False,formatters: {# 自己自定义的日志格式可以自己改standard: {# 自己定义的自定义格式format: standard_format},simple: {format: simple_format},test: {format: test_format},},filters: {},## 日志的接受者不同的handle可以使日志输出到不同位置handlers: {#打印到终端的日志console: {level: DEBUG,class: logging.StreamHandler, # 打印到屏幕## 指定输出格式formatter: simple},#打印到文件的日志,收集info及以上的日志default: {level: DEBUG,class: logging.handlers.RotatingFileHandler, # 保存到文件,日志轮转formatter: standard,# 可以定制日志文件路径# BASE_DIR os.path.dirname(os.path.abspath(__file__)) # log文件的目录# LOG_PATH os.path.join(BASE_DIR,a1.log)filename: a1.log, # 日志文件maxBytes: 1024*1024*5, # 日志大小 5MbackupCount: 5,encoding: utf-8, # 日志文件的编码再也不用担心中文log乱码了},## 测试用的日志格式other: {level: DEBUG,class: logging.FileHandler, # 保存到文件formatter: test,filename: a2.log,##拿到项目的跟文件夹 os.path.dirname(os.path.dirname(__file__))encoding: utf-8,},},# 负责产生日志产生的日志传递给handler负责处理loggers: {#logging.getLogger(__name__)拿到的logger配置kkk: {# kkk 产生的日志传给谁handlers: [default, console], # 这里把上面定义的两个handler都加上即log数据既写入文件又打印到屏幕level: DEBUG, # loggers(第一层日志级别关限制)---handlers(第二层日志级别关卡限制)propagate: False, # 默认为True向上更高level的logger传递通常设置为False即可否则会一份日志向上层层# 传递},bbb: {# kkk 产生的日志传给谁handlers: [console], # 这里把上面定义的两个handler都加上即log数据既写入文件又打印到屏幕level: DEBUG, # loggers(第一层日志级别关限制)---handlers(第二层日志级别关卡限制)propagate: False, # 默认为True向上更高level的logger传递通常设置为False即可否则会一份日志向上层层# 传递},专门的采集: {handlers: [other,],level: DEBUG,propagate: False,},}, }14.9.3 使用 import settings# !!!强调!!! # 1、logging是一个包需要使用其下的config、getLogger可以如下导入 # 可能不能正常使用 # import logging.config # import logging.getLogger # 2、也可以使用如下导入 # from logging import config,getLogger from logging import config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config. from logging import getLogger # 用于获取配置文件里的日志生产者# 3、加载配置 # 把配置好的配置字典扔进去 logging.config.dictConfig(settings.LOGGING_DIC)logger1 getLogger(kkk) ## kkk 是可以同时向终端和文件里输出日志的 logger2 getLogger(bbb) ### bbb 只向终端里输出日志# 4、输出日志 logger1logging.getLogger(用户交易) logger1.info(egon儿子alex转账3亿冥币)# logger2logging.getLogger(专门的采集) # 名字传入的必须是专门的采集与LOGGING_DIC中的配置唯一对应 # logger2.debug(专门采集的日志)14.9.4 日志轮换 ## class: logging.handlers.RotatingFileHandler, # 保存到文件,日志轮转## maxBytes: 1024*1024*5, # 日志大小 5M## backupCount: 5, 最多保运几份#打印到文件的日志,收集info及以上的日志default: {level: DEBUG,class: logging.handlers.RotatingFileHandler, # 保存到文件,日志轮转formatter: standard,# 可以定制日志文件路径# BASE_DIR os.path.dirname(os.path.abspath(__file__)) # log文件的目录# LOG_PATH os.path.join(BASE_DIR,a1.log)filename: a1.log, # 日志文件maxBytes: 1024*1024*5, # 日志大小 5MbackupCount: 5,encoding: utf-8, # 日志文件的编码再也不用担心中文log乱码了},15struct模块 ## 该模块可以把一个类型如数字转成固定长度的bytes import struct bytes struct.pack(i,1000) ## 拿到长度固定的四个字节 num struct.unpack(i,bytes)[0] ## 结果是元祖元祖里拿到数字拿到数字四常用API模块 1字符串 1.1 字符串查找方法 startswith() #以指定字符串开头Endswith() # 以指定字符串结尾find() # 返回字符串第一次出现的位置Rfind() # 返回最后一次出现的位置Count() # 返回某个字符总共出现的次数Isallnum() # 判断所有字符是不是全是数字或者字母 2.2 去除首位信息 Strip() # 去除字符串首位指定信息 默认去除首位空格Lstrip() # 去除左边的指定信息Rtrip() # 去除右边的指定信息 3.3 大小写转换 Capitalize() # 产生新的字符串首字母大写Title() # 每个单词首字母大写Upper() # 所有字母转换成大写Lower() # 所有字母转换成小写Swapcase() # 所有字母大小写转换4.4 格式排版 # 1. Center() ljust() rjust() 用于实现排版# 默认用空格填充# 2. 接受两个参数第一个参数是要实现的长度第二个字符是要填充的字符s ainis.center(10,*) # 用*左右填充让s达到10的长度# 格式化我是{0},我喜欢数字{1:*^8}.format(艾尼,666)# 后面是依次是 填充的字符 对齐方式(^ 左中右) 格式化长度# 如1:*^20 用*号居中对齐长度为 20 个字符# 数字格式化 5.5 数字格式化 数字格式输出描述3.1415926{ :.2f }3.14保留小数点后两位3.1415926{ :.2f }3.14带符号的保留小数点后两位2.71828{ :.0f }3不带小数5{ :02d }5数字补零填充左边宽度为2)5{ :x4d }5xxx数字补x填充右边宽度为4)10{ :x4d }10xx数字补x填充右边宽度为4)1000000{ :, }1000000以逗号分割的数字形式0.25{ :.2% }25.00%百分比格式 6.6 其他方法 Isalnum() # 是否全为数字或字母Isalpha() # 是不是都是字母或汉字组成Isdigit() # 是不是都是由数字组成Isspace() # 检测是否为空白字符Isupper() # 检测是否为大写字母Islower() # 检测是否为小写字母2列表 方法要点描述list.append(x)增加元素将元素x增加到列表list尾部list.extend(aList)增加元素将列表aList素有元素加到列表list尾部list.insert(index,x)增加元素将列表list指定index处插入元素xlist.remove(x)shan删除元素删除列表中首次出现的指定元素xlist.pop(index)删除元素删除index处的元素并返回默认删除最后一个元素并返回list.clear()删除所有元素删除原数不会删除列表对象list.index(x)访问元素返回第一个x的索引若不存在则抛出异常list.count(x)计数返回元素x在列表中出现的次数len(list)返回列表长度返回类表中总元素的个数 方法要点描述list.reverse()翻转列表所有元素原地翻转list.sort()排序所有元素原地排序list.copy()浅拷贝返回列表对象的浅拷贝 3字典 # update(),把第二个字典加到第一个字典里面 a.update(b) # 把字典b加到a里面# 可以用 del 删除键值对# Del a[‘name’] del a[‘sex’]# 可以用 clear()方法删除所有键值对 # Pop()方法可以删除键值对并将值返回 a.pop(name)# Popitem()方法:随机删除键值对并将其返回# 序列解包 a.values() a.items()4Python常用内置函数 4.1 round() 函数 round()是一个处理数值的内置函数它返回浮点数x的四舍五入值 4.2 all() 和 any() all()和any()用于判断可迭代对象中的元素是否为True。它们返回布尔值True或False numbers [1, 2, 3, 4, 5] if all(num 0 for num in numbers):print(All numbers are positive) else:print(There are some non-positive numbers)if any(num 4 for num in numbers):print(At least one number is greater than 4) else:print(No number is greater than 4) 4.3 lambda函数 lambda x: x 5 这个Lambda函数可以像下面这样使用 add_five lambda x: x 5 result add_five(10) print(result) # 输出 15 4.4 sorted()函数 sorted()是一个内置函数它用于对可迭代对象进行排序。 sorted()函数接受一个可迭代对象作为参数并返回一个新的已排序的列表。 sorted(iterable, keyNone, reverseFalse) # iterable: 需要排序的可迭代对象例如列表、元组、集合、字典等。 #key可选参数: 用于指定排序的关键字。key是一个函数它将作用于iterable中的每个元素并返回一个用于排序的关键字。默认为None表示按照元素的大小进行排序。 # reverse可选参数: 用于指定排序的顺序。如果设置为True则按照逆序排序。默认为False表示按照正序排序。 numbers [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] sorted_numbers sorted(numbers) print(sorted_numbers) # 输出结果为 [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]words [apple, banana, cherry, date] sorted_words sorted(words, keylen) print(sorted_words) # 输出结果为 [date, apple, banana, cherry]numbers [(1, 2), (3, 4), (2, 1), (4, 3)] sorted_numbers sorted(numbers, keylambda x: x[1]) print(sorted_numbers) # 输出结果为 [(2, 1), (1, 2), (4, 3), (3, 4)] # 在上面的示例中第一个示例对一个整数列表进行排序第二个示例对一个字符串列表按照字符串长度进行排序第三个示例对一个元组列表按照元组中第二个元素进行排序其中使用了lambda表达式作为key参数来指定排序方式。 4.5 map()函数 map(函数名可迭代对象) map函数是一种高阶函数它接受一个函数和一个可迭代对象作为参数返回一个新的可迭代对象 map得到的是一个迭代器 # 其中每个元素都是将原可迭代对象中的元素应用给定函数后的结果。 # 可以简单理解为对可迭代对象中的每个元素都执行同一个操作返回一个新的结果集合。 # 需要注意的是map函数返回的是一个迭代器对象因此如果要使用它的结果需要将它转换为一个列表list()、元组tuple()或集合set()和其他可迭代对象。map函数的一些应用 1.用来批量接收变量 n,m map(int,input().split())2.对可迭代对象进行批量处理返回列表map m map(.join,[[a,b,c],[d,e,f]]) print(m) - [abc,def]3.配合lambda函数达到自己想要的效果 numbers [1, 2, 3, 4, 5] doubled_numbers map(lambda x: x * 2, numbers) print(list(doubled_numbers)) - [2, 4, 6, 8, 10] 4.5 filter()函数 filter() 函数是 Python 内置函数之一它用于过滤序列中的元素返回一个满足条件的新序列。 filter() 函数的语法如下 my_list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] result filter(lambda x: x % 2 0, my_list) print(list(result)) # 输出 [2, 4, 6, 8, 10] 在这个例子中lambda x: x % 2 0 是一个 lambda 函数用于判断一个数是否为偶数。filter() 函数将这个 lambda 函数作为参数对列表 my_list 进行过滤最后返回一个新列表其中包含 my_list 中所有的偶数。 4.6 ASCII码的函数 ord() # 接收字符转换ASCII码 chr() # 接收ASCII码转换字符4.7 转进制函数 # 其它进制通用转10进制 int(x,y) # x是你要转的数而y是这个数是由什么进制表示的 # 当y为0时就按x的前缀来看如 0bx 二进制,0b 0o 0x,分别是二八十六# 10进制转其他进制 hex() # 转16 oct() # 转8# 有一个函数很适合10进制转其他各种进制 divmod(x,y) #其作用是同时返回两个数的商和余数。 # 所以要这样接收它的值 a,b divmod(x,y) 4.8 列表 Python中的list是一个非常重要的数据类型可以用来存储多个值包括数字、字符串、对象等等。 以下是一些常见的list函数及其示例append() - 将一个元素添加到list的末尾 fruits [apple, banana, cherry] fruits.append(orange) print(fruits) # [apple, banana, cherry, orange]extend() - 将一个list的所有元素添加到另一个list的末尾 fruits [apple, banana, cherry] more_fruits [orange, mango, grape] fruits.extend(more_fruits) print(fruits) # [apple, banana, cherry, orange, mango, grape]insert() - 在指定的位置插入一个元素 fruits [apple, banana, cherry] fruits.insert(1, orange) print(fruits) # [apple, orange, banana, cherry]remove() - 删除指定的元素 fruits [apple, banana, cherry] fruits.remove(banana) print(fruits) # [apple, cherry]pop() - 删除指定位置的元素默认为最后一个元素并返回该元素的值 fruits [apple, banana, cherry] last_fruit fruits.pop() print(last_fruit) # cherry print(fruits) # [apple, banana]index() - 返回指定元素在list中的索引位置 fruits [apple, banana, cherry] banana_index fruits.index(banana) print(banana_index) # 1count() - 返回指定元素在list中出现的次数 fruits [apple, banana, cherry, banana, banana] banana_count fruits.count(banana) print(banana_count) # 3sort() - 将list中的元素进行排序 fruits [apple, banana, cherry] fruits.sort() print(fruits) # [apple, banana, cherry]reverse() - 将list中的元素翻转 fruits [apple, banana, cherry] fruits.reverse() print(fruits) # [cherry, banana, apple]len() - 返回list中元素的数量 fruits [apple, banana, cherry] num_fruits len(fruits) print(num_fruits) # 3copy() - 返回一个list的副本 fruits [apple, banana, cherry] fruits_copy fruits.copy() print(fruits_copy) # [apple, banana, cherry]clear() - 删除list中的所有元素 fruits [apple, banana, cherry] fruits.clear() print(fruits) # []max() - 返回list中最大的元素 numbers [5, 10, 3, 8, 15] max_num max(numbers) print(max_num) # 15min() - 返回list中最小的元素 numbers [5, 10, 3, 8, 15] min_num min(numbers) print(min_num) # 3sum() - 返回list中所有元素的和仅适用于数字类型的list numbers [5, 10, 3, 8, 15] sum_nums sum(numbers) print(sum_nums) # 41any() - 如果list中至少有一个元素为True则返回True bool_list [False, True, False] has_true any(bool_list) print(has_true) # Trueall() - 如果list中的所有元素都为True则返回True bool_list [True, True, True] all_true all(bool_list) print(all_true) # Trueenumerate() - 返回一个枚举对象其中包含list中每个元素的索引和值 fruits [apple, banana, cherry] for index, fruit in enumerate(fruits):print(index, fruit) # 0 apple # 1 banana # 2 cherrymap() - 对list中的每个元素应用函数并返回结果的list numbers [1, 2, 3, 4] squares list(map(lambda x: x ** 2, numbers)) print(squares) # [1, 4, 9, 16]filter() - 返回list中符合条件的元素的子集 numbers [1, 2, 3, 4, 5, 6] even_nums list(filter(lambda x: x % 2 0, numbers)) print(even_nums) # [2, 4, 6]reduce() - 对list中的元素应用函数将其归约为单个值 from functools import reduce numbers [1, 2, 3, 4] sum_nums reduce(lambda x, y: x y, numbers) print(sum_nums) # 10zip() - 将多个list的元素配对返回一个元组的list fruits [apple, banana, cherry] colors [red, yellow, red] fruit_colors list(zip(fruits, colors)) print(fruit_colors) # [(apple, red), (banana, yellow), (cherry, red)]sorted() - 返回一个新的已排序的list numbers [3, 2, 1, 5, 4] sorted_nums sorted(numbers) print(sorted_nums) # [1, 2, 3, 4, 5]join() - 将list中的字符串连接成一个字符串 fruits [apple, banana, cherry] fruit_string , .join(fruits) print(fruit_string) # apple, banana, cherryslice() - 返回一个list的子集根据索引的起始和结束位置 fruits [apple, banana, cherry, orange, grape] subset fruits[1:4] print(subset) # [banana, cherry, orange]希望这些函数能够帮助你更好地使用Python的list类型。 4.9 元祖 Python元组是不可变序列它不支持在原地修改元素。因此Python元组的函数相对较少。 以下是Python元组的所有函数 count count方法返回元组中指定元素的数量。 my_tuple (apple, banana, apple, orange, banana, apple) count my_tuple.count(apple) print(count) # 输出3index index方法返回元组中指定元素第一次出现的索引。 my_tuple (apple, banana, apple, orange, banana, apple) index my_tuple.index(orange) print(index) # 输出3len len方法返回元组中元素的数量。 my_tuple (apple, banana, orange) length len(my_tuple) print(length) # 输出3tuple tuple函数用于将一个可迭代对象转换为元组。 my_list [1, 2, 3] my_tuple tuple(my_list) print(my_tuple) # 输出(1, 2, 3)zip zip函数将多个可迭代对象的对应元素打包成元组返回一个包含这些元组的迭代器。 fruits (apple, banana, orange) quantities (5, 2, 3) prices (1.2, 1.5, 0.8) # 将三个元组打包成一个迭代器 inventory zip(fruits, quantities, prices) # 遍历迭代器中的元素 for item in inventory:print(item) # 输出 # (apple, 5, 1.2) # (banana, 2, 1.5) # (orange, 3, 0.8)sorted sorted函数返回一个按指定顺序排序后的可迭代对象可以接收一个关键字参数key来指定排序的关键字。 my_tuple (3, 2, 1) sorted_tuple sorted(my_tuple) print(sorted_tuple) # 输出[1, 2, 3] # 按绝对值大小排序 my_tuple (-3, 2, -1) sorted_tuple sorted(my_tuple, keyabs) print(sorted_tuple) # 输出[-1, 2, -3]reversed reversed函数返回一个迭代器包含按相反顺序排列的可迭代对象中的元素。 my_tuple (apple, banana, orange) reversed_tuple reversed(my_tuple) for item in reversed_tuple:print(item) # 输出 # orange # banana # apple继续 max max函数返回可迭代对象中最大的元素可以接收一个关键字参数key来指定比较的关键字。 my_tuple (3, 2, 1) max_element max(my_tuple) print(max_element) # 输出3 # 按绝对值大小比较 my_tuple (-3, 2, -1) max_element max(my_tuple, keyabs) print(max_element) # 输出-3min min函数返回可迭代对象中最小的元素可以接收一个关键字参数key来指定比较的关键字。 my_tuple (3, 2, 1) min_element min(my_tuple) print(min_element) # 输出1 # 按绝对值大小比较 my_tuple (-3, 2, -1) min_element min(my_tuple, keyabs) print(min_element) # 输出-1sum sum函数返回可迭代对象中所有元素的和可以接收一个可选参数start指定求和的起始值。 my_tuple (3, 2, 1) sum_value sum(my_tuple) print(sum_value) # 输出6 # 指定求和的起始值为5 my_tuple (3, 2, 1) sum_value sum(my_tuple, 5) print(sum_value) # 输出11all all函数返回可迭代对象中所有元素都为真值即不为False、0、None等时返回True否则返回False。 my_tuple (1, 2, 3) result all(my_tuple) print(result) # 输出True my_tuple (1, 2, 0) result all(my_tuple) print(result) # 输出Falseany any函数返回可迭代对象中至少有一个元素为真值即不为False、0、None等时返回True否则返回False。 my_tuple (0, False, None) result any(my_tuple) print(result) # 输出False my_tuple (0, False, 1) result any(my_tuple) print(result) # 输出True 4.10 字典 Python字典dictionary是一个无序的键值对集合。Python中有许多内置函数可以操作字典。 以下是一些常用的函数及其示例创建字典 # 创建一个空字典 my_dict {}# 创建一个非空字典 my_dict {apple: 1, banana: 2, orange: 3}访问字典 # 获取字典中指定键对应的值 value my_dict[apple] print(value) # 输出1# 使用get()方法获取字典中指定键对应的值 value my_dict.get(banana) print(value) # 输出2# 获取字典中所有键的列表 keys list(my_dict.keys()) print(keys) # 输出[apple, banana, orange]# 获取字典中所有值的列表 values list(my_dict.values()) print(values) # 输出[1, 2, 3]修改字典 # 修改字典中指定键对应的值 my_dict[apple] 4 print(my_dict) # 输出{apple: 4, banana: 2, orange: 3}# 使用update()方法修改字典中的值 my_dict.update({apple: 5, orange: 6}) print(my_dict) # 输出{apple: 5, banana: 2, orange: 6}删除字典 # 删除字典中指定键值对 del my_dict[apple] print(my_dict) # 输出{banana: 2, orange: 6}# 删除字典中所有键值对 my_dict.clear() print(my_dict) # 输出{}其他函数 # 获取字典中键值对的数量 num_items len(my_dict) print(num_items) # 输出0# 检查字典中是否存在指定键 if apple in my_dict:print(Yes) # 输出No# 复制字典 new_dict my_dict.copy() print(new_dict) # 输出{}遍历字典 # 遍历字典中所有键值对 for key, value in my_dict.items():print(key, value)# 遍历字典中所有键 for key in my_dict.keys():print(key)# 遍历字典中所有值 for value in my_dict.values():print(value)设置默认值 # 使用setdefault()方法设置默认值 my_dict.setdefault(apple, 0) print(my_dict) # 输出{banana: 2, orange: 6, apple: 0}合并字典 # 使用update()方法合并字典 dict1 {apple: 1, banana: 2} dict2 {orange: 3, pear: 4} dict1.update(dict2) print(dict1) # 输出{apple: 1, banana: 2, orange: 3, pear: 4}# 使用**运算符合并字典 dict1 {apple: 1, banana: 2} dict2 {orange: 3, pear: 4} dict3 {**dict1, **dict2} print(dict3) # 输出{apple: 1, banana: 2, orange: 3, pear: 4}字典推导式 # 创建字典推导式 my_dict {i: i*2 for i in range(5)} print(my_dict) # 输出{0: 0, 1: 2, 2: 4, 3: 6, 4: 8}反转字典 # 反转字典中的键值对 my_dict {apple: 1, banana: 2, orange: 3} reversed_dict {value: key for key, value in my_dict.items()} print(reversed_dict) # 输出{1: apple, 2: banana, 3: orange}排序字典 # 按键排序 my_dict {apple: 1, banana: 2, orange: 3} sorted_dict {key: my_dict[key] for key in sorted(my_dict)} print(sorted_dict) # 输出{apple: 1, banana: 2, orange: 3}# 按值排序 my_dict {apple: 1, banana: 2, orange: 3} sorted_dict {key: value for key, value in sorted(my_dict.items(), keylambda item: item[1])} print(sorted_dict) # 输出{apple: 1, banana: 2, orange: 3}过滤字典 # 过滤字典中满足条件的键值对 my_dict {apple: 1, banana: 2, orange: 3} filtered_dict {key: value for key, value in my_dict.items() if value 1} print(filtered_dict) # 输出{banana: 2, orange: 3}计数器 # 使用collections模块中的Counter类创建计数器 from collections import Counter my_list [apple, banana, apple, orange, banana, apple] my_counter Counter(my_list) print(my_counter) # 输出Counter({apple: 3, banana: 2, orange: 1})# 获取计数器中指定元素的数量 count my_counter[apple] print(count) # 输出3# 获取计数器中出现次数最多的元素和出现次数 most_common my_counter.most_common(1) print(most_common) # 输出[(apple, 3)] 4.11 集合 以下是Python set对象支持的一些常用方法add(): 将一个元素添加到set中如果元素已经存在什么都不会发生。 fruits {apple, banana, orange} fruits.add(kiwi) print(fruits) # {orange, banana, kiwi, apple}clear(): 移除set中的所有元素。 fruits {apple, banana, orange} fruits.clear() print(fruits) # set()copy(): 返回set的一个副本。 fruits {apple, banana, orange} fruits_copy fruits.copy() print(fruits_copy) # {orange, banana, apple}difference(): 返回一个包含set和另一个set或iterable中不同元素的新set。也可以直接减 eg:fruits - more_fruits fruits {apple, banana, orange} more_fruits {banana, kiwi, pineapple} diff_fruits fruits.difference(more_fruits) print(diff_fruits) # {orange, apple}discard(): 从set中移除一个元素如果元素不存在什么都不会发生。 fruits {apple, banana, orange} fruits.discard(banana) print(fruits) # {orange, apple}intersection(): 返回一个包含set和另一个set或iterable中共同元素的新set。也可以直接交 eg:fruits more_fruits fruits {apple, banana, orange} more_fruits {banana, kiwi, pineapple} common_fruits fruits.intersection(more_fruits) print(common_fruits) # {banana}isdisjoint(): 如果set和另一个set或iterable没有共同元素返回True否则返回False。也可以直接交然后判断 eg:return fruits more_fruits set() fruits {apple, banana, orange} more_fruits {kiwi, pineapple} print(fruits.isdisjoint(more_fruits)) # Trueissubset(): 如果set是另一个set的子集返回True否则返回False。 也可以直接交然后判断是不是等于自身 eg:return fruits more_fruits fruits fruits {apple, banana, orange} more_fruits {banana, orange, kiwi, pineapple} print(fruits.issubset(more_fruits)) # Falseissuperset(): 如果set是另一个set的超集返回True否则返回False。 fruits {apple, banana, orange} more_fruits {banana, orange} print(fruits.issuperset(more_fruits)) # Truepop(): 移除并返回set中的一个元素如果set为空抛出KeyError异常。 fruits {apple, banana, orange} print(fruits.pop()) # orange print(fruits) # {apple, banana}remove(): 从set中移除一个元素如果元素不存在抛出KeyError异常。 fruits {apple, banana, orange} fruits.remove(banana) print(fruits) # {orange, apple}symmetric_difference(): 返回一个包含set和另一个set或iterable中不重复元素的新setsymmetric_difference_update(): 将set和另一个set或iterable中不重复的元素更新到set中。 fruits {apple, banana, orange} more_fruits {banana, kiwi, pineapple} fruits.symmetric_difference_update(more_fruits) print(fruits) # {orange, kiwi, pineapple, apple}union(): 返回一个包含set和另一个set或iterable中所有元素的新set。 不可以除了 union() 方法我们还可以使用 | 运算符来实现两个 set 的并集 fruits {apple, banana, orange} more_fruits {banana, kiwi, pineapple} all_fruits fruits.union(more_fruits) print(all_fruits) # {kiwi, apple, pineapple, orange, banana}update(): 将set和另一个set或iterable中所有元素更新到set中。 fruits {apple, banana, orange} more_fruits {banana, kiwi, pineapple} fruits.update(more_fruits) print(fruits) # {kiwi, apple, pineapple, orange, banana}difference_update(): 将set和另一个set或iterable中不同的元素更新到set中。 fruits {apple, banana, orange} more_fruits {banana, kiwi, pineapple} fruits.difference_update(more_fruits) print(fruits) # {orange, apple}intersection_update(): 将set和另一个set或iterable中共同的元素更新到set中。 fruits {apple, banana, orange} more_fruits {banana, kiwi, pineapple} fruits.intersection_update(more_fruits) print(fruits) # {banana} 4.12 字符串处理函数 大小写处理 s,s1 aaaBBBccc, 123456 s.upper() # 将字符串全部大写 AAABBBCCC s.lower() # 将字符串全部小写 aaabbbccc s.swapcase() # 将s大小写反转 AAAbbbCCC字符判断 isdigit() , isnumeric # 判断字符串中是否全是数字字符 print(list(map(lambda x:x.isdigit(),[Z,Z2]))) # [False, True] isdigit是否为数字字符包括Unicode数字单字节数字双字节全角数字不包括汉字数字罗马数字、小数 isnumeric是否所有字符均为数值字符包括Unicode数字、双字节全角数字、罗马数字、汉字数字不包括小数。s.isalpha() # 判断字符串中是否全为字母 s.isalnum() # 判断字符串中是否全为字母或者数字 4.13 callable() ## 判断一个对象能不能调用 def func():passclass Foo:pass print(callable(Foo)) ## true print(callable(func)) ## true4.14 dir()----查看属性 class Foo:pass obj Foo()print(dir(obj)) ## 查看obj的属性[__class__, __delattr__, __dict__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __gt__, __hash__, __init__, __init_subclass__, __le__, __lt__, __module__, __ne__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__, __weakref__]4.15 enumerate() ## 既能拿到索引又能拿到值 lis [a,b,c,d,f]for i,v in enumerate(lis):print(i,v) # 0 a # 1 b # 2 c # 3 d # 4 f 4.16 eval() ## 执行字符串里的表达式 res eval(1 2)res eval({name:aini,age:22}) print(res) ## {name:aini,age:22} ## 拿到的就是字典类型4.17 frozenset() s frozenset({1,2,3,4,5,6}) ## 得到不可变集合4.18 hash() ## 传入不可变类型得到一个hash值 res hash(aini) print(res) ## -39472239622209066494.19 help() ## 查看文档注释4.20 isinstance() ## 判断一个对象是不是一个类的实例class Foo:passobj Foo()## 判断obj是不是Foo的实例化 isinstance(obj,Foo)## 判断列表字典都可以用 isinstance([],list) isinstance({{name:aini,age:22}},dict)五request网络请求 1request模块 1-1response的常用属性 1response.text #响应体 str类型response.encoding #从HTTP header中猜测的响应内容的编码方式 2respones.content #响应体 bytes类型 3response.status_code #响应状态码, 4response.request.headers #响应对应的请求头 5response.headers 响应头, 6response.cookies #响应的cookie经过了set-cookie动作 7response.url #获取访问的url, 8response.json() #获取json数据 得到内容为字典 (如果接口响应体的格式是json格式时) 9response.ok# 如果status_code小于等于200response.ok返回True。# 如果status_code大于200response.ok返回False。# 先安装 reqeuests import requests # 给定抓取的网址的url url http://www.baidu.com # 发起get请求 response requests.get(url)# 看一下响应的状态码 print(response.status_code) # 看一下请求的url print(response.url, response.url) # 获取编码 print(response.encoding) # 设定编码 # response.encoding GBK # response.encoding UTF-8 # response.encoding response.apparent_encoding# 看一下返回的数据 以字符串形式返回的一般情况下会乱码 需要给定编码 print(response.text)# 获取bytes print( response.content) print(response.content.decode()) # 使用默认解码方式 print(response.content.decode(UTF-8)) # 使用默认解码方式 print(response.content.decode(GBK)) # 使用默认解码方式# 获取响应头 print(response.headers)# 获取响应对应的请求头 print(response.request.headers)print(response.ok)# 获取JSON数据 print(response.json())1-2 response.text 和response.content的区别 ## response.text# 类型str # 解码类型 requests模块自动根据HTTP 头部对响应的编码作出有根据的推测推测的文本编码 # 如何修改编码方式response.encodinggbk/UTF-8## response.content## 类型bytes ## 解码类型 没有指定 ## 如何修改编码方式response.content.deocde(utf8)获取网页源码的通用方式 response.content.decode() response.content.decode(UTF-8) response.text## 以上三种方法从前往后尝试能够100%的解决所有网页解码的问题 ## 所以更推荐使用response.content.deocde()的方式获取响应的html页面1-3下载图片实例 import requests# 图片的URL url https://ww4.sinaimg.cn/mw690/0076vsZ6ly1hiw5krf9wdj31401hcb2a.jpg # 发起请求 response requests.get(url) # 图片使用wb with open(dlrb.jpg, wb) as f:f.write(response.content)1-4添加请求头 import requestsurl http://www.baidu.com## 添加请求头 headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 } # 携带请求头 response requests.get(url, headersheaders) # print(response.content.decode()) print(response.request.headers)1-5get传参数 1-5-1 第一种方式 import requests## url ## get参数在URL里以查询字符串形式传递 url http://www.zishazx.com/product?page1size_id0volum_id0price_id2category_id1001prize_id0pug_id25#views# 设置请求头 headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 }# 发起get请求 response requests.get(url, headersheaders)# 获取返回数据 data response.content.decode() print(data) # 写入 with open(zsh.html, w, encodingUTF-8) as f:f.write(data)1-5-2 第二种方式 import requestsurl http://www.zishazx.com/product # 设置请求头 headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 } # 鞋带的参数 get传参 params {page: 1,size_id: 0,volum_id: 0,price_id: 2,category_id: 1001,prize_id: 0,pug_id: 25 }# 发起get请求 携带了 get传参 携带了headers请求头 response requests.get(url, headersheaders, paramsparams) # 获取返回数据 data response.content.decode() print(response.url) # print(data) # 写入 with open(zsh.html, w, encodingUTF-8) as f:f.write(data)1-6 实战案例 1-6-1 获取图片案例 import requests from lxml import etreeurl https://app.mi.com/subject/115150 headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 }response requests.get(url, headersheaders) data response.content.decode()tree etree.HTML(data) li_list tree.xpath(//ul[classapplist]/li) for li in li_list:# 获取图片地址img_src li.xpath(./a/img/data-src)[0]# 获取名称name li.xpath(./h5/a/text())[0]# 获取简介decr li.xpath(./p/a/text())[0]print(img_src, name, decr)1-6-2 xpath紫砂之星抓取单页数据 import requests from lxml import etree# 要抓取的url url http://www.zishazx.com/product # 给请求头 ua headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 } # 发起get请求 res requests.get(url, headersheaders) # 获取响应的页面内容 data res.content.decode() # 实例化匹配对象 tree etree.HTML(data) # print(data) # 获取到了所有的li li_list tree.xpath(//ul[classlist clearfix]/li) for li in li_list:# 获取到图片的src地址img li.xpath(./p[classimg]/a/img/src)[0]name li.xpath(./p[classname]/text())[0]p_no li.xpath(./p[classp_no]/text())[0]print(img, name, p_no)1-6-3 bs4紫砂之星抓取单页数据 import requests from bs4 import BeautifulSoup# 要抓取的url url http://www.zishazx.com/product # 给请求头 ua headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 } # 发起get请求 res requests.get(url, headersheaders) # 获取响应的页面内容 data res.content.decode() # 实例化匹配对象 soup BeautifulSoup(data, lxml) # print(data) # 获取到了所有的li # li_list tree.xpath(//ul[classlist clearfix]/li) li_list soup.find(ul, class_list clearfix).findAll(li) for li in li_list:# 获取到图片的src地址# img li.xpath(./p[classimg]/a/img/src)[0]img li.find(p, class_img).a.img[src]# name li.xpath(./p[classname]/text())[0]name li.find(p, class_name).string# p_no li.xpath(./p[classp_no]/text())[0]p_no li.find(p, class_p_no).stringprint(img, name, p_no)1-6-4 xpath小说阅读网 from lxml import etree import requestsurl https://www.readnovel.com/category # 给定请求头 headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 } # 发起请求 res requests.get(url, headersheaders) data res.content.decode() # print(data) # 实例化tree对象 tree etree.HTML(data) # 获取所有图书的li li_list tree.xpath(//div[classright-book-list]/ul/li) for li in li_list:# 获取封面img li.xpath(./div[classbook-img]/a/img/src)[0]# 获取标题title li.xpath(./div[classbook-info]/h3/a/text())[0]# 获取简介intro li.xpath(.//p[classintro]/text())[0]print(img, title, intro)1-6-5 bs4小说阅读网 from bs4 import BeautifulSoup import requestsurl https://www.readnovel.com/category # 给定请求头 headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 } # 发起请求 res requests.get(url, headersheaders) data res.content.decode() # print(data) # 实例化tree对象 soup BeautifulSoup(data, lxml) # 获取所有图书的li # li_list tree.xpath(//div[classright-book-list]/ul/li) li_list soup.find(div, class_right-book-list).ul.findAll(li) for li in li_list:# 获取封面# img li.xpath(./div[classbook-img]/a/img/src)[0]img li.find(div, class_book-img).a.img[src]# 获取标题# title li.xpath(./div[classbook-info]/h3/a/text())[0]title li.find(div, class_book-info).h3.a.string# 获取简介# intro li.xpath(.//p[classintro]/text())[0]intro li.find(p, class_intro).stringprint(img, title, intro)1-6-6 xpath抓取优美图库 import os import random import timefrom lxml import etree import requestsurl http://www.umeituku.com/bizhitupian/ headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 }res requests.get(url, headersheaders) data res.content.decode() tree etree.HTML(data) # 获取所有二级标签页的url地址 a_list tree.xpath(//div[classTypeList]/ul/li/a/href) # 创建图片目录 存储当前的图片 path img if not os.path.exists(path):os.mkdir(path) for url in a_list:# 开始访问二级标签页内容res requests.get(url, headersheaders)data res.content.decode()tree etree.HTML(data)try:# 找二级标签页当前大图的src地址和图片名称src tree.xpath(//p[aligncenter]/a/img/src)[0]alt tree.xpath(//p[aligncenter]/a/img/alt)[0]print(src, alt, 图片下载中)# 图片存入本地with open(os.path.join(path, alt.jpg), wb) as f:f.write(requests.get(src, headersheaders).content)print(src, alt, 图片下载完成......)# 给个时间自省except Exception as e:print(f在抓取网址{url}的过程中出现了问题 问题为, e)time.sleep(random.randint(1, 4)) print(OVER 下载结束)1-6-7 抓取冶金信息 from lxml import etree import requestsurl http://www.metalinfo.cn/mi.html headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 }pageSize: 20 current: 2 resourceType: r_news facetFilter: {} order: desc sort: sort_timeres requests.get(url, headersheaders) data res.content.decode() tree etree.HTML(data) li_list tree.xpath(//ul[idsearchLists]/li) print(li_list) for li in li_list:list_title .join(li.xpath(//div[classlist-title ]//text()))list_intro li.xpath(//div[classlist-intro]/text())[0]list_keys .join(li.xpath(//div[classlist-keys]/text()))print(list_title, list_intro, list_keys) 1-6-8 异步请求 from lxml import etree import requestsurl http://www.metalinfo.cn/json/search/list headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 } # 传递post数据 data {pageSize: 200,current: 1,resourceType: r_news,facetFilter: {},order: desc,sort: sort_time, } # 发起post请求 res requests.post(url, headersheaders, datadata) # 获取json数据 json_data res.json()[result][records] i 0 for j in json_data:# 获取标题title j[title]# 获取简介r_abstract j[r_abstract]print(title)print(r_abstract)i 1 print(i)1-6-9 中信证券抓取单页 import requests from lxml import etreeurl http://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index.html headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, }res requests.get(url, headersheaders) html res.content.decode() tree etree.HTML(html) li_list tree.xpath(//ul[classlist-con]/li) # print(li_list) for li in li_list:con li.xpath(./span/text())th1 con[0]th2 con[1]th3 con[2]th4 con[3]th5 con[4]print(th1, th2, th3, th4, th5)2反扒措施 2-1 代理的使用 # 用到的库 import requests # 写入获取到的ip地址到proxy# 一个ip地址 proxy {http:http://221.178.232.130:8080 }res requests.get(url, proxiesproxy) print(res.content.decode())### ----------------------------------------------------------------------------# 多个ip地址 proxy [{http:http://221.178.232.130:8080},{http:http://221.178.232.130:8080} ]import random proxy random.choice(proxy) # 随机获取ipres requests.get(url, proxiesproxy) print(res.content.decode())2-2 处理cookie 2-2-1 带cookie的请求 import requestsurl https://xueqiu.com/statuses/hot/listV2.json?since_id-1max_id554225size15 headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36,Referer: https://xueqiu.com/,## 携带cookie信息Cookie:cookiesu121697804017738; device_id2cb32776fe1f32adba3aefc52173bcdc; xq_a_tokene2f0876e8fd368a0be2b6d38a49ed2dd5eec7557; xqate2f0876e8fd368a0be2b6d38a49ed2dd5eec7557; xq_r_token2a5b753b2db675b4ac36c938d20120660651116d; xq_id_tokeneyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1aWQiOi0xLCJpc3MiOiJ1YyIsImV4cCI6MTcwMDY5OTg3NSwiY3RtIjoxNjk4MjM4NzI4MTU4LCJjaWQiOiJkOWQwbjRBWnVwIn0.RtY0JREVs0R4s9sgP2RsybzTrLY7UD5dDElnpf16r7-F02lOLkU7mdgAm0HjvKvbcAYYeRyP6Ke6rdy3WfbFI-RlJwzxIo5wZ4ScGzy0Vj3VYKqsh7-Wx8MnzyRjVcJPtVUfBlN_Plj5nmxnQPykmZwKSRjKT02YBy2XH4OHNaN0sG1Rst37mAj2f42lTogbHdfZBsRUkweP-UezUkEyvSncUYIe9IAMZmHf7d5AQ94BK5h3nhSqy01KyyTf2aonnwWG7rNrOeuo7F28S50Wz-1JBKtbQYhRbOEZL2FVpizmpC_h98pYl3RtDBVvbiUEJPxx1-bRN6J78h3bduYu0w; u121697804017738; Hm_lvt_1db88642e346389874251b5a1eded6e31697804019,1698238782; }# 再发请求。拿数据 res requests.get(url, headersheaders) print(res.json())2-2-2, coocie的字典形式 import requests# 携带cookie登录雪球网 抓取完善个人资料页面 headers {User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36,Referer: https://xueqiu.com/u/1990923459,Host: xueqiu.com, } url https://xueqiu.com/users/connectnew?redirect/setting/usercookie_dict {u: 1990923459,bid: 1f110dfd43538f4b8362dfcd21ffbb64_l27g4lfl,xq_is_login: 1,xq_r_token: 5dcbe83944f0b75325f91246061d4a2a01999367 } res requests.get(url, headersheaders, cookiescookie_dict) with open(雪球网.html, w) as f:f.write(res.content.decode(UTF-8))print(res.content.decode(UTF-8))2-2-3 获取服务端返回的cookie import requestsurl https://xueqiu.com/ headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, } res requests.get(url, headersheaders) # 获取cookie cookies res.cookies print(cookies) # 获取字典格式的cookie print(dict(cookies))2-2-4 携带首页服务器响应的cookie import requests # 就是为了获取cookie index_url https://xueqiu.com/ headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36,Referer: https://xueqiu.com/, } res requests.get(index_url, headersheaders) # 获取cookie cookies dict(res.cookies)url https://xueqiu.com/statuses/hot/listV2.json?since_id-1max_id554225size15 # 携带cookie进行请求 res requests.get(url, headersheaders, cookiescookies) print(res.json())2-2-5 使用session处理cookie import requests # 就是为了获取cookie headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36,Referer: https://xueqiu.com/, } # 使用这个session对象进行维护 session requests.Session() # session requests.session() # 请求首页 获取返回的cookie index_url https://xueqiu.com/ session.get(index_url, headersheaders)# 获取数据 url https://xueqiu.com/statuses/hot/listV2.json?since_id-1max_id554225size15 # 携带cookie进行请求 res session.get(url, headersheaders) print(res.json())2-2-6 模拟登录 6-1 手动处理cookie import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, } # 登录的url地址 login_url https://passport.17k.com/ck/user/login data {loginName: 17346570232,password: xlg17346570232, } # 发起登录请求 res requests.post(login_url, headersheaders, datadata) cookies dict(res.cookies) # 获取登录后的cookie# 获取登录后的数据 url https://user.17k.com/ck/user/myInfo/96139098?bindInfo1appKey2406394919 res requests.get(url, headersheaders, cookiescookies) print(res.content.decode())6-2 自动维护cookie import requestsheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, } # 登录的url地址 login_url https://passport.17k.com/ck/user/login data {loginName: 17346570232,password: xlg17346570232, } # 发起登录请求 session requests.Session() session.post(login_url, headersheaders, datadata)# 获取登录后的数据 url https://user.17k.com/ck/user/myInfo/96139098?bindInfo1appKey2406394919 res session.get(url, headersheaders) print(res.content.decode())2-3 案例 2-3-1 处理验证码 1-1 下载验证码 ## 首先找到发放验证码的URL地址获取验证码保存到本地import requests # 验证码地址 url https://so.gushiwen.cn/RandCode.ashx res requests.get(url)with open(yzm.jpg, wb) as f:f.write(res.content)1-2 识别验证码 ## 用验证码识别模块识别验证码# 终端用pip安装ddddoce包 pip install ddddocr# ddddocr可能会出现的问题 # 1 在运行过程中 报错最底部出现dll的问题 安装一下c环境 # 2 运行顶部会出现PIL的问题 # 可能没安装pillow模块 pip install pillow # 安装了(版本高了 卸载原有pillow 安装9.5.0的pillow模块) # pip uninstall pillow # pip install pillow9.5.0 import ddddocr ocr ddddocr.DdddOcr() with open(yzm.jpg, rb) as f:data f.read() result ocr.classification(data) print(result)1-3 登录 import requestsurl https://so.gushiwen.cn/user/login.aspx?fromhttp%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36,Referer: https://so.gushiwen.cn/user/login.aspx?fromhttp://so.gushiwen.cn/user/collect.aspx, } email 793390457qq.com, pwd xlg17346570232, data {__VIEWSTATE: AaJHgmeyf8Le6GErv1HkNyY9sDsTvgOx5w95HI82SkYSEWCpd9gSo2mvsYno9ZIc1D/tjgrPiujAhdRcKtnUjN5RdyvONf3MAk83da/5zRoc2WtYcqhyh1iEk9hVU6e7jmM8I07Z3dNPLNcAouMrW4mUaGk,__VIEWSTATEGENERATOR: C93BE1AE,from: http://so.gushiwen.cn/user/collect.aspx,email: email,pwd: pwd,code: k04c, denglu: 登录, } res requests.post(url, headersheaders, datadata) # print(res.content.decode()) with open(gsw.html, w, encodingUTF-8) as f:f.write(res.content.decode())1-4 上面三步整合 import requests import ddddocrurl https://so.gushiwen.cn/user/login.aspx?fromhttp%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36,Referer: https://so.gushiwen.cn/user/login.aspx?fromhttp://so.gushiwen.cn/user/collect.aspx, }# 验证码处理 img_url https://so.gushiwen.cn/RandCode.ashx res requests.get(img_url) img res.content with open(yzm.jpg, wb) as f:f.write(img) ocr ddddocr.DdddOcr() result ocr.classification(img)email 793390457qq.com, pwd xlg17346570232, print(result) data {__VIEWSTATE: AaJHgmeyf8Le6GErv1HkNyY9sDsTvgOx5w95HI82SkYSEWCpd9gSo2mvsYno9ZIc1D/tjgrPiujAhdRcKtnUjN5RdyvONf3MAk83da/5zRoc2WtYcqhyh1iEk9hVU6e7jmM8I07Z3dNPLNcAouMrW4mUaGk,__VIEWSTATEGENERATOR: C93BE1AE,from: http://so.gushiwen.cn/user/collect.aspx,email: email,pwd: pwd,code: result,denglu: 登录, } res requests.post(url, headersheaders, datadata) # print(res.content.decode()) with open(gsw.html, w, encodingUTF-8) as f:f.write(res.content.decode())但是还是提示验证码不对 问题出现在哪里 1-5 最终版本 需要添加cookie数据 import requests import ddddocr session requests.Session() url https://so.gushiwen.cn/user/login.aspx?fromhttp%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36,Referer: https://so.gushiwen.cn/user/login.aspx?fromhttp://so.gushiwen.cn/user/collect.aspx, } # 验证码处理 img_url https://so.gushiwen.cn/RandCode.ashx res session.get(img_url) img res.content with open(yzm.jpg, wb) as f:f.write(img) ocr ddddocr.DdddOcr() result ocr.classification(img)email 793390457qq.com, pwd xlg17346570232, print(result) data {__VIEWSTATE: AaJHgmeyf8Le6GErv1HkNyY9sDsTvgOx5w95HI82SkYSEWCpd9gSo2mvsYno9ZIc1D/tjgrPiujAhdRcKtnUjN5RdyvONf3MAk83da/5zRoc2WtYcqhyh1iEk9hVU6e7jmM8I07Z3dNPLNcAouMrW4mUaGk,__VIEWSTATEGENERATOR: C93BE1AE,from: http://so.gushiwen.cn/user/collect.aspx,email: email,pwd: pwd,code: result,denglu: 登录, } res session.post(url, headersheaders, datadata) # print(res.content.decode()) with open(gsw.html, w, encodingUTF-8) as f:f.write(res.content.decode())1-6 打码平台使用 import base64 import json import requests def base64_api(uname, pwd, img, typeid):with open(img, rb) as f:base64_data base64.b64encode(f.read())b64 base64_data.decode()data {username: uname, password: pwd, typeid: typeid, image: b64}result json.loads(requests.post(http://api.ttshitu.com/predict, jsondata).text)if result[success]:return result[data][result]else:#注意返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别return result[message]return if __name__ __main__:img_path ./code.pngresult base64_api(unamexxxxx, pwdxxxxx, imgimg_path, typeid3)print(result)import base64 import json import requests # 一、图片文字类型(默认 3 数英混合) # 1 : 纯数字 # 1001纯数字2 # 2 : 纯英文 # 1002纯英文2 # 3 : 数英混合 # 1003数英混合2 # 4 : 闪动GIF # 7 : 无感学习(独家) # 11 : 计算题 # 1005: 快速计算题 # 16 : 汉字 # 32 : 通用文字识别(证件、单据) # 66: 问答题 # 49 :recaptcha图片识别 # 二、图片旋转角度类型 # 29 : 旋转类型 # # 三、图片坐标点选类型 # 19 : 1个坐标 # 20 : 3个坐标 # 21 : 3 ~ 5个坐标 # 22 : 5 ~ 8个坐标 # 27 : 1 ~ 4个坐标 # 48 : 轨迹类型 # # 四、缺口识别 # 18 : 缺口识别需要2张图 一张目标图一张缺口图 # 33 : 单缺口识别返回X轴坐标 只需要1张图 # 五、拼图识别 # 53拼图识别 def base64_api(uname, pwd, img, typeid):with open(img, rb) as f:base64_data base64.b64encode(f.read())b64 base64_data.decode()data {username: uname, password: pwd, typeid: typeid, image: b64}result json.loads(requests.post(http://api.ttshitu.com/predict, jsondata).text)if result[success]:return result[data][result]else:#注意返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别return result[message]return if __name__ __main__:img_path C:/Users/Administrator/Desktop/file.jpgresult base64_api(uname你的账号, pwd你的密码, imgimg_path, typeid3)print(result)3抓取多页数据 3-1 xpath紫砂之星抓取多页数据 import random import timeimport requests from lxml import etreefor i in range(1, 11):url fhttp://www.zishazx.com/product?page{i}volum_start0volum_end0volum_id0price_start0price_end0category_id0pug_id0size_id0price_id0prize_id0searchsflag#viewsprint(f正在抓取第{i}页数据》)# 给请求头 uaheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36}# 发起get请求res requests.get(url, headersheaders)# 获取响应的页面内容data res.content.decode()# 实例化匹配对象tree etree.HTML(data)# print(data)# 获取到了所有的lili_list tree.xpath(//ul[classlist clearfix]/li)for li in li_list:# 获取到图片的src地址img li.xpath(./p[classimg]/a/img/src)[0]name li.xpath(./p[classname]/text())[0]p_no li.xpath(./p[classp_no]/text())[0]print(img, name, p_no)time.sleep(random.randint(1,4)) 3-2 抓取多页数据案例 http://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index.html 1 http://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index_1.html 2 http://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index_4.html 5 import requests import re from lxml import etreeurl http://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index.html headers {User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, }res requests.get(url, headersheaders) html res.content.decode() # print(html) page re.search(var countPage (?Ppage\d)//共多少页, html).group(page) for i in range(int(page)1):url fhttp://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index_{i}.htmlif not i:url fhttp://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index.htmlprint(url)3-3 登录处理 import requests index_url https://v3pro.houjiemeishi.com/PC/index.html headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, } session requests.Session() session.get(index_url, headersheaders)# 登录的url地址 login_url https://v3pro.houjiemeishi.com//index.php?store_id1store_type6 # 登录携带的表单数据 data {module: app_pc,action: login,m: login,phone: luckyboy,password: bHVja3lib3k,imgCode: flms,language: , } headers[Referer] https://v3pro.houjiemeishi.com/PC/pages/login/login.html res session.post(login_url, datadata, headersheaders) data res.json() print(登录后返回的, data) access_id data[data][access_id] # 抓取个人资料 own https://v3pro.houjiemeishi.com//index.php?store_id1store_type6 data {module: app_pc,action: user,m: personal_resources,access_id: access_id,language: , } headers[Referer] https://v3pro.houjiemeishi.com/PC/index.html?modulemyactionmymmyamyinfor res session.post(login_url, datadata, headersheaders) print(获取个人资料的, res.json()4requests处理证书错误 import requestsurl https://www.12306.cn/mormhweb/ response requests.get(url)5、超时参数的使用 response requests.get(url,timeout3)6请求参数类型 1. Query String Parameters# 最终是要被添加在url上面的.# 此时, 你可以有两个选择.1. 把参数直接怼在url上面url https://movie.douban.com/j/chart/top_list?type13interval_id100%3A90actionstart0limit20requests.get(url)2. 把参数弄出来. 弄成字典. 然后通过params传递给服务器url https://movie.douban.com/j/chart/top_listparams {type: 13interval_id: 100:90action:start: 0limit: 20}requests.get(url, paramsparams)3. 还可以混合搭配.url https://movie.douban.com/j/chart/top_list?type13params {interval_id: 100:90action:start: 0limit: 20}requests.get(url, paramsparams)# 上述三种方案. 最终在服务器是一样的..原因是, 请求是要遵守http协议的 # 在http协议中. get请求的所有参数都要怼在url上面2. Form Data# 首先Form Data一定是post请求# 它的参数. 需要处理成字典. 然后再requests模块里.url xxxxxdata {数据}requests.post(url, datadata)3. Request Payload 表示的就是挂载.# 挂载的数据类型不一定是json. 最多的是json...# 在请求头里. 会有一个content-type属性. 来描述该挂载内容的格式# 我们处理的时候. 一般是按照浏览器上面的提示. 来组装参数以及请求头url xxxxxdata {字典}解决方案:1. 直接用json参数传递requests.post(url, jsondata)# 把你传递的字典. 处理成json然后发送给服务器# 隐藏的逻辑:# 自动在请求头里帮你添加content-type: json....# 上述逻辑是自动的2. 手动把字典处理成json. 然后再请求头里增加content-type把处理好的json用data传递出去s json.dumps(data, separators(,, :)) # json字符串requests.post(url, datas, headers{Content-Type: application/json})# 上述逻辑是自己手动来...4. 三种参数可以混搭....# Query String 和 Form Data# Query String 和 Requests payload# 用上面的三种方案. 混合处理即可.4. 请求头.User-Agent: 表示的是你的网络设备...Referer: 防盗链.# a页面 发请求到b页面. 在b页面的请求头上面就会有referer, 是a页面的地址.Cookie:# 客户端和服务器的会话状态.# 应该如何处理cookie1. 服务器在返回的http数据包的时候. 在响应头上会有Set-Cookie# Set-Cookie: xxxxxxxxxx# 告诉浏览器. 把该信息保存下来.以后使用我的网站的时候. 带着该cookie信息# 保持cookie状态: session#session表示会话. 你再session中保存的请求头信息. cookie信息# 可以重复使用...# 可以帮我们保持住cookie的状态.# 它只能帮你保持住, 响应头回来的cookie信息.2. 在js中可以动态的修改cookie# 有些网站不是通过响应头加载的cookie..... 这时候session就不行了....该信息是js动态加载的# 此时. 我们只能想办法手工去维护cookie的改变策略. 还是要用session....# 综上. 我们发请求的时候. 一定要用session 六selenium 1下载配置 ## 安装 pip install selenium## 它与其他库不同的地方是他要启动你电脑上的浏览器, 这就需要一个驱动程序来辅助. ## 这里推荐用chrome浏览器## chrome驱动地址:http://chromedriver.storage.googleapis.com/index.html https://googlechromelabs.github.io/chrome-for-testing/#stable## 先查看自己谷歌浏览器的版本我的是120.0.6099.255然后打开这个驱动地址 https://googlechromelabs.github.io/chrome-for-testing/#stable 选stable 稳定版 然后在网页上搜索我们的版本只要前三个部分对应上就行也就是120.0.6099 如下图就这样我们找到了我们想要的版本 把URL地址复制下载去浏览器下载驱动 下完以后解压发现里面是个exe文件往后浏览器更新了驱动也需要重新下载对应版本的 然后关键的来了. 把你下载的浏览器驱动放在python解释器所在的文件夹 Windwos: py -0p 查看Python路径 Mac: open 路径 到此为止配置就结束了 2selenium导入使用 from selenium.webdriver import Chrome # 导入谷歌浏览器的类# 创建浏览器对象 web Chrome() # 如果你的浏览器驱动放在了解释器文件夹web.get(http://www.baidu.com) # 输入网址2、selenium的基本使用 2.1 加载网页 selenium通过控制浏览器所以对应的获取的数据都是elements中的内容 from selenium import webdriver from selenium.webdriver.common.by import Bydriver webdriver.Chrome() # 访问百度 driver.get(http://www.baidu.com/) # 截图 driver.save_screenshot(baidu.png)2.2 定位和操作 # 搜索关键字 杜卡迪 driver.find_element(By.ID, kw).send_keys(杜卡迪) # 点击id为su的搜索按钮 driver.find_element(By.ID, su).click()3.3 查看请求信息 driver.page_source # 获取页面内容 driver.get_cookies() driver.current_url3.4 退出 driver.close() # 退出当前页面 driver.quit() # 退出浏览器3.5 小结 1. selenium的导包:from selenium import webdriver2. selenium创建driver对象:driver webdriver.Chrome()3. selenium请求数据:driver.get(http://www.baidu.com/)4. selenium查看数据: driver.page_source5. 关闭浏览器: driver.quit()6. 根据id定位元素: driver.find_element_by_id(kw)/driver.find_element(By.ID, kw)7. 操作点击事件: click()8. 给输入框赋值:send_keys()9获取cookiedriver.get_cookies()10刷新页面driver.refresh()11执行js代码driver.execute_script(fwindow.scrollBy(0, {step_length}))3-6 小案例 3-6-1 简单案例 找到搜索框输入内容找到搜索按钮进行点击 import timefrom selenium.webdriver import Chrome # 导入谷歌浏览器的类# 创建浏览器对象 from selenium.webdriver.common.by import Byweb Chrome() # 如果你的浏览器驱动放在了解释器文件夹web.get(https://www.gushiwen.cn/) # 输入网址# 查找搜索框 txtKey web.find_element(By.ID,txtKey)txtKey.send_keys(唐诗)# 找到点击按钮 search web.find_element(By.XPATH,//*[idsearch]/form/input[3]) search.click() print(search) time.sleep(5) web.quit()3-6-2 解决登录问题 2-1 基本代码 import timefrom selenium.webdriver import Chrome from selenium.webdriver.common.by import Bydriver Chrome() # 访问的网址 driver.get(https://www.gushiwen.cn/)1 点击我的 到登录页面 2 获取账号节点 输入值 3 获取密码节点 输入值 4 获取验证码节点 输入值 5 点击登录# 点我的 driver.find_element(By.XPATH, /html/body/div[1]/div[1]/div/div[2]/div/a[6]).click()# 获取账号节点 email driver.find_element(By.ID, email) email.send_keys(793390457qq.com) # 获取密码节点 password driver.find_element(By.ID, pwd) password.send_keys(xlg17346570232) # 获取验证码节点 yzm driver.find_element(By.ID, code) yzm.send_keys(1234) time.sleep(5)# 点击登录 driver.find_element(By.ID, denglu).click()time.sleep(5)2-2 打码平台 import base64 import json import requests import timefrom selenium.webdriver import Chrome from selenium.webdriver.common.by import Bydef base64_api(uname, pwd, img, typeid):with open(img, rb) as f:base64_data base64.b64encode(f.read())b64 base64_data.decode()data {username: uname, password: pwd, typeid: typeid, image: b64}result json.loads(requests.post(http://api.ttshitu.com/predict, jsondata).text)if result[success]:return result[data][result]else:#注意返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别return result[message]return if __name__ __main__:driver Chrome()# 访问的网址driver.get(https://www.gushiwen.cn/)1 点击我的 到登录页面2 获取账号节点 输入值3 获取密码节点 输入值4 获取验证码节点 输入值5 点击登录# 点我的driver.find_element(By.XPATH, /html/body/div[1]/div[1]/div/div[2]/div/a[6]).click()# 获取账号节点email driver.find_element(By.ID, email)email.send_keys(793390457qq.com)# 获取密码节点password driver.find_element(By.ID, pwd)password.send_keys(xlg17346570232)# 验证码图片的节点img_path yzm.jpg# screenshot截图并保存保存driver.find_element(By.ID, imgCode).screenshot(img_path)# 识别验证码result base64_api(unameluckyboyxlg, pwd17346570232, imgimg_path, typeid3)print(result)# 获取验证码节点yzm driver.find_element(By.ID, code)yzm.send_keys(result) # 输入识别后的值time.sleep(8)# 点击登录driver.find_element(By.ID, denglu).click()time.sleep(50) 2-3 保存登录后的cookie import base64 import json import requests import timefrom selenium.webdriver import Chrome from selenium.webdriver.common.by import Bydef base64_api(uname, pwd, img, typeid):with open(img, rb) as f:base64_data base64.b64encode(f.read())b64 base64_data.decode()data {username: uname, password: pwd, typeid: typeid, image: b64}result json.loads(requests.post(http://api.ttshitu.com/predict, jsondata).text)if result[success]:return result[data][result]else:#注意返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别return result[message]return if __name__ __main__:driver Chrome()# 访问的网址driver.get(https://www.gushiwen.cn/)1 点击我的 到登录页面2 获取账号节点 输入值3 获取密码节点 输入值4 获取验证码节点 输入值5 点击登录# 点我的driver.find_element(By.XPATH, /html/body/div[1]/div[1]/div/div[2]/div/a[6]).click()# 获取账号节点email driver.find_element(By.ID, email)email.send_keys(793390457qq.com)# 获取密码节点password driver.find_element(By.ID, pwd)password.send_keys(xlg17346570232)# 验证码图片的节点img_path yzm.jpg# screenshot截图并保存保存driver.find_element(By.ID, imgCode).screenshot(img_path)# 识别验证码result base64_api(unameluckyboyxlg, pwd17346570232, imgimg_path, typeid3)print(result)# 获取验证码节点yzm driver.find_element(By.ID, code)yzm.send_keys(result) # 输入识别后的值time.sleep(8)# 点击登录driver.find_element(By.ID, denglu).click()time.sleep(4)# 获取cookie保存到本地cookies driver.get_cookies()print(cookies)with open(cookies.txt, w, encodingUTF-8) as f:f.write(json.dumps(cookies)) 2-4 携带cookie进行访问 import time from selenium.webdriver.common.by import By from selenium.webdriver import Chrome import jsondriver Chrome() # 访问登录 driver.get(https://so.gushiwen.cn/user/login.aspx?fromhttp://so.gushiwen.cn/user/collect.aspx) # 本地cookie加载 with open(cookies.txt, r, encodingUTF-8) as f:cookies json.loads(f.read())# cookie加载到selenium中 for cookie in cookies:driver.add_cookie(cookie)# 刷新一下 driver.refresh()driver.get(https://so.gushiwen.cn/user/collect.aspx)time.sleep(10)3-6-3 抓取网易 import time from selenium.webdriver import Chrome from selenium.webdriver.common.by import Bydef window_scroll(driver, stop_length, step_length):向下滚动方法封装:param driver: selenium对象:param stop_length: 滚动终止值:param step_length: 每次滚动步长:return:while True:# 终止不滚的条件if stop_length - step_length 0:driver.execute_script(fwindow.scrollBy(0, {stop_length}))break# 执行js代码 向下滚动driver.execute_script(fwindow.scrollBy(0, {step_length}))stop_length - step_lengthtime.sleep(1) # 1秒滚一下# driver.execute_script(window.scrollBy(0, 30000)) if __name__ __main__:driver Chrome()driver.get(https://news.163.com/)stop_length 30000 # 终止值step_length 2000 # 每次滚动的值# 循环5次点击加载更多for i in range(1, 6):window_scroll(driver, stop_length, step_length)# 点击加载更多more driver.find_element(By.XPATH, //*[idindex2016_wrap]/div[3]/div[2]/div[3]/div[2]/div[5]/div/a[3]/div[1]/span)# more.click() # 点击driver.execute_script(arguments[0].click(), more)print(f第{i}次 点击加载更多)time.sleep(5)# 获取页面所有源代码page driver.page_sourceprint(page)3、selenium的定位操作 1元素定位的两种写法 直接调用型 el driver.find_element_by_xxx(value)# xxx是定位方式后面我们会讲value为该方式对应的值使用By类型(需要导入By) 建议使用这种方式 # 直接掉用的方式会在底层翻译成这种方式 from selenium.webdriver.common.by import By driver.find_element(By.xxx,value)2元素定位的两种方式: 精确定位一个元素,返回结果为一个element对象,定位不到则报错 driver.find_element(By.xx, value) # 建议使用 driver.find_element_by_xxx(value)定位一组元素,返回结果为element对象列表,定位不到返回空列表 driver.find_elements(By.xx, value) # 建议使用 driver.find_elements_by_xxx(value)3元素定位的八种方法: 以下方法在element之后添加s就变成能够获取一组元素的方法 By.ID 使用id值定位 el driver.find_element(By.ID, ) el driver.find_element_by_id() By.XPATH 使用xpath定位 el driver.find_element(By.XPATH, ) el driver.find_element_by_xpath() By.TAG_NAME. 使用标签名定位 el driver.find_element(By.TAG_NAME, ) el driver.find_element_by_tag_name() By.LINK_TEXT使用超链接文本定位 el driver.find_element(By.LINK_TEXT, ) el driver.find_element_by_link_text() By.PARTIAL_LINK_TEXT 使用部分超链接文本定位 el driver.find_element(By.PARTIAL_LINK_TEXT , ) el driver.find_element_by_partial_link_text()By.NAME 使用name属性值定位 el driver.find_element(By.NAME, ) el driver.find_element_by_name()By.CLASS_NAME 使用class属性值定位 el driver.find_element(By.CLASS_NAME, ) el driver.find_element_by_class_name()By.CSS_SELECTOR 使用css选择器定位 el driver.find_element(By.CSS_SELECTOR, ) el driver.find_element_by_css_selector()注意 find_element与find_elements区别 1. 只查找一个元素的时候:可以使用find_element(),find_elements()find_element()会返回一个WebElement节点对象,但是没找到会报错,而find_elements()不会,之后返回一个空列表 2. 查找多个元素的时候:只能用find_elements(),返回一个列表,列表里的元素全是WebElement节点对象 3. 找到都是节点(标签) 4. 如果想要获取相关内容(只对find_element()有效,列表对象没有这个属性) 使用 .text 5. 如果想要获取相关属性的值(如href对应的链接等,只对find_element()有效,列表对象没有这个属性):使用 .get_attribute(href) ​ 4、元素的操作 find_element_by_xxx方法仅仅能够获取元素对象接下来就可以对元素执行以下操作 从定位到的元素中提取数据的方法 4.1 从定位到的元素中获取数据 el.get_attribute(key) # 获取key属性名对应的属性值 el.text # 获取开闭标签之间的文本内容4.2 对定位到的元素的操作 el.click() # 对元素执行点击操作el.submit() # 对元素执行提交操作el.clear() # 清空可输入元素中的数据el.send_keys(data) # 向可输入元素输入数据5小结 ## 1. 根据xpath定位元素:driver.find_elements(By.XPATH,//*[ids]/h1/a)## 2. 根据class定位元素:driver.find_elements(By.CLASS_NAME, box)## 3. 根据link_text定位元素:driver.find_elements(By.LINK_TEXT, 下载豆瓣 App)## 4. 根据tag_name定位元素:driver.find_elements(By.TAG_NAME, h1)## 5. 获取元素文本内容:element.text## 6. 获取元素标签属性: element.get_attribute(href)## 7. 向输入框输入数据: element.send_keys(data)4、无头浏览器 我们已经基本了解了selenium的基本使用了. 但是呢, 不知各位有没有发现, 每次打开浏览器的时间都比较长. 这就比较耗时了. 我们写的是爬虫程序. 目的是数据. 并不是想看网页. 那能不能让浏览器在后台跑呢? 答案是可以的 from selenium.webdriver import Chrome from selenium.webdriver.chrome.options import Optionsopt Options() opt.add_argument(--headless) opt.add_argument(--disable-gpu) opt.add_argument(--window-size4000,1600) # 设置窗口大小web Chrome(optionsopt)from selenium.webdriver import Chrome from selenium.webdriver.chrome.options import Optionsopt Options() opt.add_argument(--headless) opt.add_argument(--disable-gpu)web Chrome(optionsopt) web.get(https://www.baidu.com) print(web.title)5、selenium 处理cookie 通过driver.get_cookies()能够获取所有的cookie 获取cookie dictCookies driver.get_cookies()设置cookie driver.add_cookie(dictCookies)删除cookie #删除一条cookie driver.delete_cookie(CookieName) # 删除所有的cookie driver.delete_all_cookies()6其他知识 6.1 当你触发了某个事件之后页面出现了弹窗提示处理这个提示或者获取提示信息方法如下 alert driver.switch_to_alert()6.2 页面前进和后退 driver.forward() # 前进 driver.back() # 后退 driver.refresh() # 刷新 driver.close() # 关闭当前窗口6.3 设置浏览器最大窗口 driver.maximize_window() #最大化浏览器窗口七数据库操作 1MySQL 1.1 基础知识 # DB数据库他保存了一系列有组织的数据 # DBMS数据库管理系统 # SQL结构化查询语言用来与数据库进行沟通1.1.1 MySQL服务的登录和退出 # 1通过 Windows 自带的客户端# 登录MySQL -h 主机名 -p 端口号 -u 用户名 -p 密码-p 和密码之间不能有空格# 退出exit1.1.2 查看数据库的版本号 ## 1Windows 客户端进入 MySQL,写 SQL 命令 select version(); ## 2Windows 客户端写 MySQL --version*结尾没有分号1.1.3 MySQL 语法规范 ## 1. 不区分大小写建议关键字大写表名列名小写 ## 2. 每条命令最好分号结尾 ## 3. 每条命令根据需要进行缩进换行 ## 4. 注释1,单行注释# 注释内容2,单行注释-- 注释内容-- 后面必须有空格3,多行注释/* 注释内容 */1.1.4 SQL语言 ## 1. DQL数据查询语言select ## 2. DML数据操作语言 增删改 ## 3. DDL数据定义语言 ## 4. TCL事务控制语言1.2 DQL 基础查询语言 1.2.1 进阶1DQL基础查询 1-1 代码格式化 ## F12 可以对代码进行格式化1-2 简单查询 # 查询单个字段 select last_name from employees;# 查询表中的多个字段 select last_name , salary,email from employees;# 查询表中的所有字段 select * from employees;# 查询常量表达式 select 100; select aini; select 100*98; select version();1-3 起别名 ## as 关键字## 方式一select 98 * 100 as 运算结果select last_name as 姓, first_name as 名 from employees;## 方式二 select last_name 姓,first_name 名 from employees;## 注意特殊字符如#,关键字 建议加上双引号;select salaty as out put from employess;1-4 去重 # 去重 distinct## 查询员工表中涉及到的所有部门编号 select distinct department_id from employees;1-5 的作用 ## 两个操作数是数值则做加法运算 ## 其中一个为字符串时试图将其转换为数值转换成功继续做数值的加法运算如果转换失败则将此字符串转换为 0如果其中一方为 null则结果已经为 nullselect aini 20 # 20 select 50 30 # 80 select a b # 01-6 concat函数 ## Null 与任何字段任何数据拼接结果都是 nullselect concat(a,b,c) as 字符连接; select concat(last_name,first_name) as 姓名 from employees;1-7 IFNULL 函数 ## 1IFNULL(x,y) x 为判断的值y 为返回的值 意思就是假如 x 是 null select ifnull(commission_puc,0) as 奖金率,commission-puc from employees;## null 的地方会返回函数里面设置的值不是null 的地方会返回本身的值1.2.2 进阶2条件查询 2-1 条件查询分类 # 按条件表达式进行筛选 ! # 按逻辑表达式进行筛选 || ! and not or# 模糊查询like , between and , in , null2-2 条件表达式查询 # 查询工资12000的员工信息select * from employees where salaty 12000;# 查询部门编号不等于90号的员工名和部门编号select last_anme ,department_id from employees where department_id 90;2-3 按逻辑表达式筛选 # 查询员工工资在10000 到 20000 之间的员工名工资奖金select last_name,salary commistion_put from employees where salary 10000 and salary 20000;# 查询部门编号不是在90 到 110 之间的或者工资高于15000的员工信息select * from employees where department_id 90 or department_id 110 or salary 15000;select * from employees where not (department_id 90 and department_id 110) or salary 15000;2-4 模糊查询 4.1 通配符 # %表示任意多个字符也包含零个字符 # _表示任意单个字符4-2 like # 查询员工名中包含字符a的员工信息select * from employees where last_name like %a%;# 查询员工名中第三个字符为e的第五个字符为a的员工名select last_name from employees where last_name like __e_a%# 查询员工名中第二字符为下划线的员工名select last_name from employees where last_name like _\_%; # 需要对下划线进项转义# 自定义转义符号select last_name from employees where last_name like _$_% escape $;select last_name from employees where last_name like _z_% escape z;4-3 between and # 包含临界值临界值不能颠倒# 查询员工编号在100到120之间的员工信息select * from employees where employee_id between 100 and 120;4-4 in ## 判断值是否等于in列表中的某一项 ## 不支持括号里使用通配符 ## in 列表的值类型必须统一或兼容# 查询员工的工种编号是IT_PROG,AD_VP,AD_PRES 中的一个工种名和工种编号select last_name ,job_id from employees where job_id in (IT_PROG,AD_VP,AD_PRES)4-5 is null ## 不能用来判断字段值是否为空## 查询没有奖金的员工和奖金率select last_name,commistion_pct from employees where commisstion_pct is null## 不能判断字段值是否为Null所以使用is null## 查询有奖金的员工和奖金率select last_name,commistion_pct from employees where commission-pct is not null4-6 安全等于 #案例1查询没有奖金的员工名和奖金率 SELECTlast_name,commission_pct FROMemployees WHEREcommission_pct NULL; #案例2查询工资为12000的员工信息 SELECTlast_name,salary FROMemployeesWHERE salary 12000;4-7 Isnull函数 ## 功能判断一个字段值是否为 null ## Isnull字段名就一个参数值为 null 返回 1值不是为空则返回 0# IS NULL:仅仅可以判断NULL值可读性较高建议使用 ## :既可以判断NULL值又可以判断普通的数值可读性较低1.2.3 进阶3排序 /* 特点 1、asc代表的是升序可以省略 desc代表的是降序 2、order by子句可以支持 单个字段、别名、表达式、函数、多个字段 3、order by子句在查询语句的最后面除了limit子句 */#1、按单个字段排序 SELECT * FROM employees ORDER BY salary DESC;#2、添加筛选条件再排序 #案例查询部门编号90的员工信息并按员工编号降序 SELECT * FROM employees WHERE department_id90 ORDER BY employee_id DESC;#3、按表达式排序 #案例查询员工信息 按年薪降序 SELECT *,salary*12*(1IFNULL(commission_pct,0)) FROM employees ORDER BY salary*12*(1IFNULL(commission_pct,0)) DESC;#4、按别名排序 #案例查询员工信息 按年薪升序 SELECT *,salary*12*(1IFNULL(commission_pct,0)) 年薪 FROM employees ORDER BY 年薪 ASC;#5、按函数排序 #案例查询员工名并且按名字的长度降序SELECT LENGTH(last_name),last_name FROM employees ORDER BY LENGTH(last_name) DESC;#6、按多个字段排序 #案例查询员工信息要求先按工资降序再按employee_id升序 SELECT * FROM employees ORDER BY salary DESC,employee_id ASC; ## Order by 语句一般放在最后1.2.4 进阶4常见函数介绍 4-1 分类 ## 分类## 单行函数## Concat() ; length() ; ifnull() ; isnull() 等## 分组函数## 功能做统计使用统计函数##单行函数## 1. 字符函数## 2. 数学函数## 3. 日期函数## 4. 其他函数## 5. 流程控制函数4-2 字符函数 2-1 length(str) ## 注一个汉字占三个字节SELECT LENGTH(john); SELECT LENGTH(张三丰hahaha);SHOW VARIABLES LIKE %char%2-2 concat SELECT CONCAT(last_name,_,first_name) 姓名 FROM employees;2-3 upper,lower SELECT UPPER(john); SELECT LOWER(joHn); #示例将姓变大写名变小写然后拼接 SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名 FROM employees;2-4 substr,substring # 注意索引从1开始 #截取从指定索引处后面所有字符 SELECT SUBSTR(李莫愁爱上了陆展元,7) out_put;#截取从指定索引处指定字符长度的字符 SELECT SUBSTR(李莫愁爱上了陆展元,1,3) out_put;#案例姓名中首字符大写其他字符小写然后用_拼接显示出来SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),_,LOWER(SUBSTR(last_name,2))) out_put FROM employees;## 可以放三个参数第一个为字段或要截取的字符串第二个是开始位置的索引第三个是长度2-5 instr ## Instr 返回一个小字符串在大字符串里面的第一次出现的起始索引找不到就返回 0 SELECT INSTR(杨不殷六侠悔爱上了殷六侠,殷八侠) AS out_put;2-6 trim # 只去掉前后的空格或者前后的某个指定字符 SELECT LENGTH(TRIM( 张翠山 )) AS out_put;SELECT TRIM(aa FROM aaaaaaaaa张aaaaaaaaaaaa翠山aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) AS out_put;2-7 lpad ## lpad 在左边填充指定字符到指定长度指定长度指的是总长度 SELECT LPAD(殷素素,2,*) AS out_put;2-8 rpad ## 8rpad 右填充跟lpad同理 SELECT RPAD(殷素素,12,ab) AS out_put;2-9 replace ## replace 替换 可以把所有被替换的内容都替换掉 ## 三个参数(字符串,’被替换的内容’,’替换的新内容’) SELECT REPLACE(周芷若周芷若周芷若周芷若张无忌爱上了周芷若,周芷若,赵敏) AS out_put;4-3 数学函数 3-1 round ## 一个参数直接四舍五入到整数第二个参数可以设置保留的小数位数 SELECT ROUND(1.567,2); SELECT ROUND(-1.55);3-2 floor SELECT FLOOR(-9.99);3-3 ceil SELECT CEIL(-1.02);3-4 truncate截断 SELECT TRUNCATE(1.69999,1); ## 结果是 1.63-5 mod SELECT MOD(10,-3); SELECT 10%3;4-3 日期函数 3-1 now #now 返回当前系统日期时间 SELECT NOW();3-2 curdate #curdate 返回当前系统日期不包含时间 SELECT CURDATE();3-3 curtime #curtime 返回当前时间不包含日期 SELECT CURTIME();3-4 获取指定部分 #可以获取指定的部分年、月、日、小时、分钟、秒 SELECT YEAR(NOW()) 年; SELECT YEAR(1998-1-1) 年;SELECT YEAR(hiredate) 年 FROM employees;SELECT MONTH(NOW()) 月; SELECT MONTHNAME(NOW()) 月;#str_to_date 将字符通过指定的格式转换成日期 SELECT STR_TO_DATE(1998-3-2,%Y-%c-%d) AS out_put;#查询入职日期为1992--4-3的员工信息 SELECT * FROM employees WHERE hiredate 1992-4-3;SELECT * FROM employees WHERE hiredate STR_TO_DATE(4-3 1992,%c-%d %Y);#date_format 将日期转换成字符 SELECT DATE_FORMAT(NOW(),%y年%m月%d日) AS out_put;#查询有奖金的员工名和入职日期(xx月/xx日 xx年) SELECT last_name,DATE_FORMAT(hiredate,%m月/%d日 %y年) 入职日期 FROM employees WHERE commission_pct IS NOT NULL; 4-4 其他函数 SELECT VERSION(); SELECT DATABASE(); SELECT USER();4-5 流程控制函数 5-1 if函数 #1.if函数 if else 的效果SELECT IF(105,大,小);SELECT last_name,commission_pct,IF(commission_pct IS NULL,没奖金呵呵,有奖金嘻嘻) 备注 FROM employees;5-2 case函数的使用 /* case 要判断的字段或表达式 when 常量1 then 要显示的值1或语句1; when 常量2 then 要显示的值2或语句2; ... else 要显示的值n或语句n; end *//*案例查询员工的工资要求部门号30显示的工资为1.1倍 部门号40显示的工资为1.2倍 部门号50显示的工资为1.3倍 其他部门显示的工资为原工资*/SELECT salary 原始工资,department_id, CASE department_id WHEN 30 THEN salary*1.1 WHEN 40 THEN salary*1.2 WHEN 50 THEN salary*1.3 ELSE salary END AS 新工资 FROM employees;#3.case 函数的使用二类似于 多重if /* case when 条件1 then 要显示的值1或语句1 when 条件2 then 要显示的值2或语句2 。。。 else 要显示的值n或语句n end */#案例查询员工的工资的情况 /* 如果工资20000,显示A级别 如果工资15000,显示B级别 如果工资10000显示C级别 否则显示D级别 */SELECT salary, CASE WHEN salary20000 THEN A WHEN salary15000 THEN B WHEN salary10000 THEN C ELSE D END AS 工资级别 FROM employees;4-6 分组函数 /* 功能用作统计使用又称为聚合函数或统计函数或组函数 分类 sum 求和、avg 平均值、max 最大值 、min 最小值 、count 计算个数特点 1、sum、avg一般用于处理数值型max、min、count可以处理任何类型 2、以上分组函数都忽略null值 3、可以和distinct搭配实现去重的运算 4、count函数的单独介绍 一般使用count(*)用作统计行数 5、和分组函数一同查询的字段要求是group by后的字段 */6-1 简单的使用 SELECT SUM(salary) FROM employees; SELECT AVG(salary) FROM employees; SELECT MIN(salary) FROM employees; SELECT MAX(salary) FROM employees; SELECT COUNT(salary) FROM employees;SELECT SUM(salary) 和,AVG(salary) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数 FROM employees;SELECT SUM(salary) 和,ROUND(AVG(salary),2) 平均,MAX(salary) 最高,MIN(salary) 低,COUNT(salary) 个数 FROM employees; 6-2 参数支持那些类型 SELECT SUM(last_name) ,AVG(last_name) FROM employees; SELECT SUM(hiredate) ,AVG(hiredate) FROM employees;SELECT MAX(last_name),MIN(last_name) FROM employees;SELECT MAX(hiredate),MIN(hiredate) FROM employees;SELECT COUNT(commission_pct) FROM employees; SELECT COUNT(last_name) FROM employees;6-3 能否忽略null SELECT SUM(commission_pct), AVG(commission_pct), SUM(commission_pct)/35, SUM(commission_pct)/107 FROM employees;SELECT MAX(commission_pct) ,MIN(commission_pct) FROM employees;SELECT COUNT(commission_pct) FROM employees; SELECT commission_pct FROM employees;6-3 和distinct搭配 SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;6-5 count函数的详细介绍 SELECT COUNT(salary) FROM employees;SELECT COUNT(*) FROM employees;SELECT COUNT(1) FROM employees;效率 ## MYISAM存储引擎下 COUNT(*)的效率高 ## INNODB 存储引擎下COUNT(*)和COUNT(1)的效率差不多比COUNT(字段)要高一些6-6 和分组函数一同查询的字段有限制 SELECT AVG(salary),employee_id FROM employees;6-7 datediff函数 ## 返回两个日期相差的天数 select datediff(2017-10-1,2017-05-18); select datediff(max(hiredate),min(hiredate)) from employees;1.2.5 进阶5分组查询 /* 语法 select 查询列表 from 表 【where 筛选条件】 group by 分组的字段 【order by 排序的字段】;特点 1、和分组函数一同查询的字段必须是group by后出现的字段 2、筛选分为两类分组前筛选和分组后筛选针对的表 位置 连接的关键字 分组前筛选 原始表 group by前 where分组后筛选 group by后的结果集 group by后 having问题1分组函数做筛选能不能放在where后面 答不能问题2where——group by——having一般来讲能用分组前筛选的尽量使用分组前筛选提高效率3、分组可以按单个字段也可以按多个字段 4、可以搭配着排序使用 */5-1 简单的分组 #案例1查询每个工种的员工平均工资 SELECT AVG(salary),job_id FROM employees GROUP BY job_id;#案例2查询每个位置的部门个数 SELECT COUNT(*),location_id FROM departments GROUP BY location_id;5-2 分组前筛选 #案例1查询邮箱中包含a字符的 每个部门的最高工资 SELECT MAX(salary),department_id FROM employees WHERE email LIKE %a% GROUP BY department_id;#案例2查询有奖金的每个领导手下员工的平均工资 SELECT AVG(salary),manager_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY manager_id;5-3 分组后筛选 #案例查询哪个部门的员工个数5 # ①查询每个部门的员工个数 SELECT COUNT(*),department_id FROM employees GROUP BY department_id; #② 筛选刚才①结果 SELECT COUNT(*),department_id FROM employees GROUP BY department_id HAVING COUNT(*)5;#案例2每个工种有奖金的员工的最高工资12000的工种编号和最高工资 SELECT job_id,MAX(salary) FROM employees WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING MAX(salary)12000;#案例3领导编号102的每个领导手下的最低工资大于5000的领导编号和最低工资manager_id102SELECT manager_id,MIN(salary) FROM employees GROUP BY manager_id HAVING MIN(salary)5000;5-4 添加排序 #案例每个工种有奖金的员工的最高工资6000的工种编号和最高工资,按最高工资升序SELECT job_id,MAX(salary) m FROM employees WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING m6000 ORDER BY m ; 5-5 按多个字段分组 #案例查询每个工种每个部门的最低工资,并按最低工资降序SELECT MIN(salary),job_id,department_id FROM employees GROUP BY department_id,job_id ORDER BY MIN(salary) DESC;1.2.6 进阶6连接查询 /* 含义又称多表查询当查询的字段来自于多个表时就会用到连接查询笛卡尔乘积现象表1 有m行表2有n行结果m*n行发生原因没有有效的连接条件 如何避免添加有效的连接条件分类按年代分类sql92标准:仅仅支持内连接sql99标准【推荐】支持内连接外连接左外和右外交叉连接按功能分类内连接等值连接非等值连接自连接外连接左外连接右外连接全外连接交叉连接 */6-1 sql92标准 1-1 等值连接 /* ① 多表等值连接的结果为多表的交集部分 ② n表连接至少需要n-1个连接条件 ③ 多表的顺序没有要求 ④ 一般需要为表起别名 ⑤ 可以搭配前面介绍的所有子句使用比如排序、分组、筛选*/#案例1查询女神名和对应的男神名 SELECT name,boyName FROM boys,beauty WHERE beauty.boyfriend_id boys.id;#案例2查询员工名和对应的部门名 SELECT last_name,department_name FROM employees,departments WHERE employees.department_iddepartments.department_id;1-2 给表起别名 /* ①提高语句的简洁度 ②区分多个重名的字段 注意如果为表起了别名则查询的字段就不能使用原来的表名去限定两个表的顺序可以改变 */ #查询员工名、工种号、工种名SELECT e.last_name,e.job_id,j.job_title FROM employees e,jobs j WHERE e.job_idj.job_id;1-3 两个表顺序调换 #查询员工名、工种号、工种名SELECT e.last_name,e.job_id,j.job_title FROM jobs j,employees e WHERE e.job_idj.job_id;1-4 可以加筛选 #案例查询有奖金的员工名、部门名 SELECT last_name,department_name,commission_pct FROM employees e,departments d WHERE e.department_idd.department_id AND e.commission_pct IS NOT NULL;#案例2查询城市名中第二个字符为o的部门名和城市名 SELECT department_name,city FROM departments d,locations l WHERE d.location_id l.location_id AND city LIKE _o%;1-5 可以加分组 #案例1查询每个城市的部门个数 SELECT COUNT(*) 个数,city FROM departments d,locations l WHERE d.location_idl.location_id GROUP BY city;#案例2查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资 SELECT department_name,d.manager_id,MIN(salary) FROM departments d,employees e WHERE d.department_ide.department_id AND commission_pct IS NOT NULL GROUP BY department_name,d.manager_id;1-6 可以加排序 #案例查询每个工种的工种名和员工的个数并且按员工个数降序 SELECT job_title,COUNT(*) FROM employees e,jobs j WHERE e.job_idj.job_id GROUP BY job_title ORDER BY COUNT(*) DESC; 1-7 三表连接 #案例查询员工名、部门名和所在的城市 SELECT last_name,department_name,city FROM employees e,departments d,locations l WHERE e.department_idd.department_id AND d.location_idl.location_id AND city LIKE s% ORDER BY department_name DESC; 1-8 非等值连接 #案例1查询员工的工资和工资级别SELECT salary,grade_level FROM employees e,job_grades g WHERE salary BETWEEN g.lowest_sal AND g.highest_sal AND g.grade_levelA;/* select salary,employee_id from employees; select * from job_grades; CREATE TABLE job_grades (grade_level VARCHAR(3),lowest_sal int,highest_sal int);INSERT INTO job_grades VALUES (A, 1000, 2999);INSERT INTO job_grades VALUES (B, 3000, 5999);INSERT INTO job_grades VALUES(C, 6000, 9999);INSERT INTO job_grades VALUES(D, 10000, 14999);INSERT INTO job_grades VALUES(E, 15000, 24999);INSERT INTO job_grades VALUES(F, 25000, 40000);*/1-9 自连接 #案例查询 员工名和上级的名称 SELECT e.employee_id,e.last_name,m.employee_id,m.last_name FROM employees e,employees m WHERE e.manager_idm.employee_id;## 自连接就是把一张表用两次来查询数据1-10 案例讲解 ## 单行函数#1. 显示系统时间(注日期时间)SELECT NOW();#2. 查询员工号姓名工资以及工资提高百分之20%后的结果new salarySELECT employee_id,last_name,salary,salary*1.2 new salaryFROM employees;#3. 将员工的姓名按首字母排序并写出姓名的长度lengthSELECT LENGTH(last_name) 长度,SUBSTR(last_name,1,1) 首字符,last_nameFROM employeesORDER BY 首字符;#4. 做一个查询产生下面的结果last_name earns salary monthly but wants salary*3Dream SalaryKing earns 24000 monthly but wants 72000SELECT CONCAT(last_name, earns ,salary, monthly but wants ,salary*3) AS Dream SalaryFROM employeesWHERE salary24000;#5. 使用case-when按照下面的条件job gradeAD_PRES AST_MAN BIT_PROG CSA_REP DST_CLERK E产生下面的结果Last_name Job_id Gradeking AD_PRES ASELECT last_name,job_id AS job,CASE job_idWHEN AD_PRES THEN A WHEN ST_MAN THEN B WHEN IT_PROG THEN C WHEN SA_PRE THEN DWHEN ST_CLERK THEN EEND AS GradeFROM employeesWHERE job_id AD_PRES;#分组查询#1.查询各job_id的员工工资的最大值最小值平均值总和并按job_id升序SELECT MAX(salary),MIN(salary),AVG(salary),SUM(salary),job_idFROM employeesGROUP BY job_idORDER BY job_id;#2.查询员工最高工资和最低工资的差距DIFFERENCESELECT MAX(salary)-MIN(salary) DIFFRENCEFROM employees;#3.查询各个管理者手下员工的最低工资其中最低工资不能低于6000没有管理者的员工不计算在内SELECT MIN(salary),manager_idFROM employeesWHERE manager_id IS NOT NULLGROUP BY manager_idHAVING MIN(salary)6000;#4.查询所有部门的编号员工数量和工资平均值,并按平均工资降序SELECT department_id,COUNT(*),AVG(salary) aFROM employeesGROUP BY department_idORDER BY a DESC;#5.选择具有各个job_id的员工人数SELECT COUNT(*) 个数,job_idFROM employeesGROUP BY job_id;## 排序查询#1.查询员工的姓名和部门号和年薪按年薪降序 按姓名升序SELECT last_name,department_id,salary*12*(1IFNULL(commission_pct,0)) 年薪FROM employeesORDER BY 年薪 DESC,last_name ASC;#2.选择工资不在8000到17000的员工的姓名和工资按工资降序SELECT last_name,salaryFROM employeesWHERE salary NOT BETWEEN 8000 AND 17000ORDER BY salary DESC;#3.查询邮箱中包含e的员工信息并先按邮箱的字节数降序再按部门号升序SELECT *,LENGTH(email)FROM employeesWHERE email LIKE %e%ORDER BY LENGTH(email) DESC,department_id ASC;# 分组函数#1.查询公司员工工资的最大值最小值平均值总和SELECT MAX(salary) 最大值,MIN(salary) 最小值,AVG(salary) 平均值,SUM(salary) 和FROM employees;#2.查询员工表中的最大入职时间和最小入职时间的相差天数 DIFFRENCESELECT MAX(hiredate) 最大,MIN(hiredate) 最小,(MAX(hiredate)-MIN(hiredate))/1000/3600/24 DIFFRENCEFROM employees;SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) DIFFRENCEFROM employees;SELECT DATEDIFF(1995-2-7,1995-2-6);#3.查询部门编号为90的员工个数SELECT COUNT(*) FROM employees WHERE department_id 90;6-2 sql99语法 /* 语法select 查询列表from 表1 别名 【连接类型】join 表2 别名 on 连接条件【where 筛选条件】【group by 分组】【having 筛选条件】【order by 排序列表】分类 内连接★inner 外连接左外(★):left 【outer】右外(★)right 【outer】全外full【outer】 交叉连接cross */ 2-1 内连接 /* 语法 select 查询列表 from 表1 别名 inner join 表2 别名 on 连接条件;分类 等值 非等值 自连接特点 ①添加排序、分组、筛选 ②inner可以省略 ③ 筛选条件放在where后面连接条件放在on后面提高分离性便于阅读 ④inner join连接和sql92语法中的等值连接效果是一样的都是查询多表的交集 */2-2 等值连接 #案例1.查询员工名、部门名 SELECT last_name,department_name FROM departments dJOIN employees e ON e.department_id d.department_id;#案例2.查询名字中包含e的员工名和工种名添加筛选SELECT last_name,job_titleFROM employees eINNER JOIN jobs jON e.job_id j.job_idWHERE e.last_name LIKE %e%;#3. 查询部门个数3的城市名和部门个数添加分组筛选#①查询每个城市的部门个数#②在①结果上筛选满足条件的SELECT city,COUNT(*) 部门个数FROM departments dINNER JOIN locations lON d.location_idl.location_idGROUP BY cityHAVING COUNT(*)3;#案例4.查询哪个部门的员工个数3的部门名和员工个数并按个数降序添加排序#①查询每个部门的员工个数SELECT COUNT(*),department_nameFROM employees eINNER JOIN departments dON e.department_idd.department_idGROUP BY department_name#② 在①结果上筛选员工个数3的记录并排序SELECT COUNT(*) 个数,department_nameFROM employees eINNER JOIN departments dON e.department_idd.department_idGROUP BY department_nameHAVING COUNT(*)3ORDER BY COUNT(*) DESC;#5.查询员工名、部门名、工种名并按部门名降序添加三表连接 SELECT last_name,department_name,job_title FROM employees e INNER JOIN departments d ON e.department_idd.department_id INNER JOIN jobs j ON e.job_id j.job_id ORDER BY department_name DESC; 2-3 非等值连接 #查询员工的工资级别 SELECT salary,grade_level FROM employees eJOIN job_grades gON e.salary BETWEEN g.lowest_sal AND g.highest_sal;#查询工资级别的个数20的个数并且按工资级别降序SELECT COUNT(*),grade_level FROM employees eJOIN job_grades gON e.salary BETWEEN g.lowest_sal AND g.highest_salGROUP BY grade_levelHAVING COUNT(*)20ORDER BY grade_level DESC;2-4 自连接 #查询员工的名字、上级的名字SELECT e.last_name,m.last_nameFROM employees eJOIN employees mON e.manager_id m.employee_id;#查询姓名中包含字符k的员工的名字、上级的名字SELECT e.last_name,m.last_nameFROM employees eJOIN employees mON e.manager_id m.employee_idWHERE e.last_name LIKE %k%;2-5 外连接 /*应用场景用于查询一个表中有另一个表没有的记录特点1、外连接的查询结果为主表中的所有记录如果从表中有和它匹配的则显示匹配的值如果从表中没有和它匹配的则显示null外连接查询结果内连接结果主表中有而从表没有的记录2、左外连接left join左边的是主表右外连接right join右边的是主表3、左外和右外交换两个表的顺序可以实现同样的效果 4、全外连接内连接的结果表1中有但表2没有的表2中有但表1没有的*/#引入查询男朋友 不在男神表的的女神名SELECT * FROM beauty;SELECT * FROM boys;2-6 左外连接 SELECT b.*,bo.*FROM boys boLEFT OUTER JOIN beauty bON b.boyfriend_id bo.idWHERE b.id IS NULL;#案例1查询哪个部门没有员工#左外SELECT d.*,e.employee_idFROM departments dLEFT OUTER JOIN employees eON d.department_id e.department_idWHERE e.employee_id IS NULL;2-7 右外连接 SELECT d.*,e.employee_idFROM employees eRIGHT OUTER JOIN departments dON d.department_id e.department_idWHERE e.employee_id IS NULL;2-8 全连接 USE girls;SELECT b.*,bo.*FROM beauty bFULL OUTER JOIN boys boON b.boyfriend_id bo.id;2-9 交叉连接 SELECT b.*,bo.*FROM beauty bCROSS JOIN boys bo;2-10 sql92和slq99pk #sql92和 sql99pk/*功能sql99支持的较多可读性sql99实现连接条件和筛选条件的分离可读性较高*/2-11 案例练习 ## 连接查询 #1.显示所有员工的姓名部门号和部门名称。 USE myemployees;SELECT last_name,d.department_id,department_name FROM employees e,departments d WHERE e.department_id d.department_id;#2.查询90号部门员工的job_id和90号部门的location_id SELECT job_id,location_id FROM employees e,departments d WHERE e.department_idd.department_id AND e.department_id90;#3. 选择所有有奖金的员工的 last_name , department_name , location_id , citySELECT last_name , department_name , l.location_id , city FROM employees e,departments d,locations l WHERE e.department_id d.department_id AND d.location_idl.location_id AND e.commission_pct IS NOT NULL; #4.选择city在Toronto工作的员工的 last_name , job_id , department_id , department_name SELECT last_name , job_id , d.department_id , department_name FROM employees e,departments d ,locations l WHERE e.department_id d.department_id AND d.location_idl.location_id AND city Toronto;#5.查询每个工种、每个部门的部门名、工种名和最低工资 SELECT department_name,job_title,MIN(salary) 最低工资 FROM employees e,departments d,jobs j WHERE e.department_idd.department_id AND e.job_idj.job_id GROUP BY department_name,job_title;#6.查询每个国家下的部门个数大于2的国家编号 SELECT country_id,COUNT(*) 部门个数 FROM departments d,locations l WHERE d.location_idl.location_id GROUP BY country_id HAVING 部门个数2;#7、选择指定员工的姓名员工号以及他的管理者的姓名和员工号结果类似于下面的格式 employees Emp# manager Mgr# kochhar 101 king 100SELECT e.last_name employees,e.employee_id Emp#,m.last_name manager,m.employee_id Mgr# FROM employees e,employees m WHERE e.manager_id m.employee_id AND e.last_namekochhar;## 外连接#一、查询编号3的女神的男朋友信息如果有则列出详细如果没有用null填充 SELECT b.id,b.name,bo.* FROM beauty b LEFT OUTER JOIN boys bo ON b.boyfriend_id bo.id WHERE b.id3;#二、查询哪个城市没有部门 SELECT city FROM departments d RIGHT OUTER JOIN locations l ON d.location_idl.location_id WHERE d.department_id IS NULL;#三、查询部门名为SAL或IT的员工信息 SELECT e.*,d.department_name,d.department_id FROM departments d LEFT JOIN employees e ON d.department_id e.department_id WHERE d.department_name IN(SAL,IT);SELECT * FROM departments WHERE department_name IN(SAL,IT);## 子查询 #1. 查询和Zlotkey相同部门的员工姓名和工资#①查询Zlotkey的部门SELECT department_idFROM employeesWHERE last_name Zlotkey#②查询部门号①的姓名和工资SELECT last_name,salaryFROM employeesWHERE department_id (SELECT department_idFROM employeesWHERE last_name Zlotkey)#2.查询工资比公司平均工资高的员工的员工号姓名和工资。#①查询平均工资SELECT AVG(salary)FROM employees#②查询工资①的员工号姓名和工资。SELECT last_name,employee_id,salaryFROM employeesWHERE salary(SELECT AVG(salary)FROM employees);#3.查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资#①查询各部门的平均工资SELECT AVG(salary),department_idFROM employeesGROUP BY department_id#②连接①结果集和employees表进行筛选SELECT employee_id,last_name,salary,e.department_idFROM employees eINNER JOIN (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id) ag_depON e.department_id ag_dep.department_idWHERE salaryag_dep.ag ;#4. 查询和姓名中包含字母u的员工在相同部门的员工的员工号和姓名#①查询姓名中包含字母u的员工的部门SELECT DISTINCT department_idFROM employeesWHERE last_name LIKE %u%#②查询部门号①中的任意一个的员工号和姓名SELECT last_name,employee_idFROM employeesWHERE department_id IN(SELECT DISTINCT department_idFROM employeesWHERE last_name LIKE %u%);#5. 查询在部门的location_id为1700的部门工作的员工的员工号#①查询location_id为1700的部门SELECT DISTINCT department_idFROM departments WHERE location_id 1700#②查询部门号①中的任意一个的员工号SELECT employee_idFROM employeesWHERE department_id ANY(SELECT DISTINCT department_idFROM departments WHERE location_id 1700); #6.查询管理者是King的员工姓名和工资#①查询姓名为king的员工编号SELECT employee_idFROM employeesWHERE last_name K_ing#②查询哪个员工的manager_id ①SELECT last_name,salaryFROM employeesWHERE manager_id IN(SELECT employee_idFROM employeesWHERE last_name K_ing);#7.查询工资最高的员工的姓名要求first_name和last_name显示为一列列名为 姓.名#①查询最高工资SELECT MAX(salary)FROM employees#②查询工资①的姓.名SELECT CONCAT(first_name,last_name) 姓.名FROM employeesWHERE salary(SELECT MAX(salary)FROM employees); 1.2.7 进阶7子查询 /* 含义 出现在其他语句中的select语句称为子查询或内查询 外部的查询语句称为主查询或外查询分类 按子查询出现的位置select后面仅仅支持标量子查询from后面支持表子查询where或having后面★标量子查询单行 √列子查询 多行 √行子查询exists后面相关子查询表子查询 按结果集的行列数不同标量子查询结果集只有一行一列列子查询结果集只有一列多行行子查询结果集有一行多列表子查询结果集一般为多行多列 */7-1 where或having后面 /* 1、标量子查询单行子查询 2、列子查询多行子查询 3、行子查询多列多行 特点 ①子查询放在小括号内 ②子查询一般放在条件的右侧 ③标量子查询一般搭配着单行操作符使用列子查询一般搭配着多行操作符使用 in、any/some、all ④子查询的执行优先于主查询执行主查询的条件用到了子查询的结果*/1-1 标量子查询 #案例1谁的工资比 Abel 高?#①查询Abel的工资SELECT salaryFROM employeesWHERE last_name Abel#②查询员工的信息满足 salary①结果SELECT *FROM employeesWHERE salary(SELECT salaryFROM employeesWHERE last_name Abel);#案例2返回job_id与141号员工相同salary比143号员工多的员工 姓名job_id 和工资#①查询141号员工的job_idSELECT job_idFROM employeesWHERE employee_id 141#②查询143号员工的salarySELECT salaryFROM employeesWHERE employee_id 143#③查询员工的姓名job_id 和工资要求job_id①并且salary②SELECT last_name,job_id,salaryFROM employeesWHERE job_id (SELECT job_idFROM employeesWHERE employee_id 141) AND salary(SELECT salaryFROM employeesWHERE employee_id 143);#案例3返回公司工资最少的员工的last_name,job_id和salary#①查询公司的 最低工资SELECT MIN(salary)FROM employees#②查询last_name,job_id和salary要求salary①SELECT last_name,job_id,salaryFROM employeesWHERE salary(SELECT MIN(salary)FROM employees);#案例4查询最低工资大于50号部门最低工资的部门id和其最低工资#①查询50号部门的最低工资SELECT MIN(salary)FROM employeesWHERE department_id 50#②查询每个部门的最低工资SELECT MIN(salary),department_idFROM employeesGROUP BY department_id#③ 在②基础上筛选满足min(salary)①SELECT MIN(salary),department_idFROM employeesGROUP BY department_idHAVING MIN(salary)(SELECT MIN(salary)FROM employeesWHERE department_id 50);#非法使用标量子查询SELECT MIN(salary),department_idFROM employeesGROUP BY department_idHAVING MIN(salary)(SELECT salaryFROM employeesWHERE department_id 250);1-2 列子查询 #案例1返回location_id是1400或1700的部门中的所有员工姓名#①查询location_id是1400或1700的部门编号SELECT DISTINCT department_idFROM departmentsWHERE location_id IN(1400,1700)#②查询员工姓名要求部门号是①列表中的某一个SELECT last_nameFROM employeesWHERE department_id ALL(SELECT DISTINCT department_idFROM departmentsWHERE location_id IN(1400,1700));#案例2返回其它工种中比job_id为‘IT_PROG’工种任一工资低的员工的员工号、姓名、job_id 以及salary#①查询job_id为‘IT_PROG’部门任一工资SELECT DISTINCT salaryFROM employeesWHERE job_id IT_PROG#②查询员工号、姓名、job_id 以及salarysalary(①)的任意一个SELECT last_name,employee_id,job_id,salaryFROM employeesWHERE salaryANY(SELECT DISTINCT salaryFROM employeesWHERE job_id IT_PROG) AND job_idIT_PROG;#或SELECT last_name,employee_id,job_id,salaryFROM employeesWHERE salary(SELECT MAX(salary)FROM employeesWHERE job_id IT_PROG) AND job_idIT_PROG;#案例3返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工 的员工号、姓名、job_id 以及salarySELECT last_name,employee_id,job_id,salaryFROM employeesWHERE salaryALL(SELECT DISTINCT salaryFROM employeesWHERE job_id IT_PROG) AND job_idIT_PROG;#或SELECT last_name,employee_id,job_id,salaryFROM employeesWHERE salary(SELECT MIN( salary)FROM employeesWHERE job_id IT_PROG) AND job_idIT_PROG; 1-3 行子查询 ##行子查询结果集一行多列或多行多列#案例查询员工编号最小并且工资最高的员工信息 SELECT * FROM employees WHERE (employee_id,salary)(SELECT MIN(employee_id),MAX(salary)FROM employees );#①查询最小的员工编号SELECT MIN(employee_id)FROM employees#②查询最高工资SELECT MAX(salary)FROM employees#③查询员工信息SELECT *FROM employeesWHERE employee_id(SELECT MIN(employee_id)FROM employees)AND salary(SELECT MAX(salary)FROM employees);7-2 select后面 /* 仅仅支持标量子查询 */#案例查询每个部门的员工个数 SELECT d.*,(SELECT COUNT(*)FROM employees eWHERE e.department_id d.department_id) 个数FROM departments d;#案例2查询员工号102的部门名 SELECT (SELECT department_name,e.department_idFROM departments dINNER JOIN employees eON d.department_ide.department_idWHERE e.employee_id102 ) 部门名; 7-3 from后面 /* 将子查询结果充当一张表要求必须起别名 */#案例查询每个部门的平均工资的工资等级 #①查询每个部门的平均工资 SELECT AVG(salary),department_id FROM employees GROUP BY department_id SELECT * FROM job_grades;#②连接①的结果集和job_grades表筛选条件平均工资 between lowest_sal and highest_salSELECT ag_dep.*,g.grade_level FROM (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id ) ag_dep INNER JOIN job_grades g ON ag_dep.ag BETWEEN lowest_sal AND highest_sal; 7-4 exists后面 #四、exists后面相关子查询/* 语法 exists(完整的查询语句) 结果 1或0 */SELECT EXISTS(SELECT employee_id FROM employees WHERE salary300000);#案例1查询有员工的部门名 #in SELECT department_name FROM departments d WHERE d.department_id IN(SELECT department_idFROM employees )#exists SELECT department_name FROM departments d WHERE EXISTS(SELECT *FROM employees eWHERE d.department_ide.department_id );#案例2查询没有女朋友的男神信息 #in SELECT bo.* FROM boys bo WHERE bo.id NOT IN(SELECT boyfriend_idFROM beauty )#exists SELECT bo.* FROM boys bo WHERE NOT EXISTS(SELECT boyfriend_idFROM beauty bWHERE bo.idb.boyfriend_id ); 1.2.8 进阶8分页查询 /* 应用场景当要显示的数据一页显示不全需要分页提交sql请求 语法select 查询列表from 表【join type join 表2on 连接条件where 筛选条件group by 分组字段having 分组后的筛选order by 排序的字段】limit 【offset,】size;offset要显示条目的起始索引起始索引从0开始size 要显示的条目个数 特点①limit语句放在查询语句的最后②公式要显示的页数 page每页的条目数sizeselect 查询列表from 表limit (page-1)*size,size;size10page 1 02 103 20*/ #案例1查询前五条员工信息 SELECT * FROM employees LIMIT 0,5; SELECT * FROM employees LIMIT 5;#案例2查询第11条——第25条 SELECT * FROM employees LIMIT 10,15;#案例3有奖金的员工信息并且工资较高的前10名显示出来 SELECT * FROMemployees WHERE commission_pct IS NOT NULL ORDER BY salary DESC LIMIT 10 ; 1.2.9 进阶9联合查询 /* union 联合 合并将多条查询语句的结果合并成一个结果 语法 查询语句1 union 查询语句2 union ...应用场景 要查询的结果来自于多个表且多个表没有直接的连接关系但查询的信息一致时 特点★ 1、要求多条查询语句的查询列数是一致的 2、要求多条查询语句的查询的每一列的类型和顺序最好一致 3、union关键字默认去重如果使用union all 可以包含重复项 */#引入的案例查询部门编号90或邮箱包含a的员工信息 SELECT * FROM employees WHERE email LIKE %a% OR department_id90;; SELECT * FROM employees WHERE email LIKE %a% UNION SELECT * FROM employees WHERE department_id90;#案例查询中国用户中男性的信息以及外国用户中年男性的用户信息 SELECT id,cname FROM t_ca WHERE csex男 UNION ALL SELECT t_id,tname FROM t_ua WHERE tGendermale;1.2.10 子查询经典案例 # 1. 查询工资最低的员工信息: last_name, salary#①查询最低的工资 SELECT MIN(salary) FROM employees#②查询last_name,salary要求salary① SELECT last_name,salary FROM employees WHERE salary(SELECT MIN(salary)FROM employees );# 2. 查询平均工资最低的部门信息#方式一 #①各部门的平均工资 SELECT AVG(salary),department_id FROM employees GROUP BY department_id #②查询①结果上的最低平均工资 SELECT MIN(ag) FROM (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id ) ag_dep#③查询哪个部门的平均工资②SELECT AVG(salary),department_id FROM employees GROUP BY department_id HAVING AVG(salary)(SELECT MIN(ag)FROM (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id) ag_dep);#④查询部门信息SELECT d.* FROM departments d WHERE d.department_id(SELECT department_idFROM employeesGROUP BY department_idHAVING AVG(salary)(SELECT MIN(ag)FROM (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id) ag_dep));#方式二 #①各部门的平均工资 SELECT AVG(salary),department_id FROM employees GROUP BY department_id#②求出最低平均工资的部门编号 SELECT department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) LIMIT 1;#③查询部门信息 SELECT * FROM departments WHERE department_id(SELECT department_idFROM employeesGROUP BY department_idORDER BY AVG(salary) LIMIT 1 );# 3. 查询平均工资最低的部门信息和该部门的平均工资 #①各部门的平均工资 SELECT AVG(salary),department_id FROM employees GROUP BY department_id #②求出最低平均工资的部门编号 SELECT AVG(salary),department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) LIMIT 1; #③查询部门信息 SELECT d.*,ag FROM departments d JOIN (SELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_idORDER BY AVG(salary) LIMIT 1) ag_dep ON d.department_idag_dep.department_id;# 4. 查询平均工资最高的 job 信息 #①查询最高的job的平均工资 SELECT AVG(salary),job_id FROM employees GROUP BY job_id ORDER BY AVG(salary) DESC LIMIT 1#②查询job信息 SELECT * FROM jobs WHERE job_id(SELECT job_idFROM employeesGROUP BY job_idORDER BY AVG(salary) DESCLIMIT 1); # 5. 查询平均工资高于公司平均工资的部门有哪些?#①查询平均工资 SELECT AVG(salary) FROM employees#②查询每个部门的平均工资 SELECT AVG(salary),department_id FROM employees GROUP BY department_id#③筛选②结果集满足平均工资①SELECT AVG(salary),department_id FROM employees GROUP BY department_id HAVING AVG(salary)(SELECT AVG(salary)FROM employees);# 6. 查询出公司中所有 manager 的详细信息. #①查询所有manager的员工编号 SELECT DISTINCT manager_id FROM employees#②查询详细信息满足employee_id① SELECT * FROM employees WHERE employee_id ANY(SELECT DISTINCT manager_idFROM employees);# 7. 各个部门中 最高工资中最低的那个部门的 最低工资是多少#①查询各部门的最高工资中最低的部门编号 SELECT department_id FROM employees GROUP BY department_id ORDER BY MAX(salary) LIMIT 1#②查询①结果的那个部门的最低工资SELECT MIN(salary) ,department_id FROM employees WHERE department_id(SELECT department_idFROM employeesGROUP BY department_idORDER BY MAX(salary)LIMIT 1); # 8. 查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary #①查询平均工资最高的部门编号 SELECT department_id FROMemployees GROUP BY department_id ORDER BY AVG(salary) DESC LIMIT 1 #②将employees和departments连接查询筛选条件是①SELECT last_name, d.department_id, email, salary FROMemployees e INNER JOIN departments d ON d.manager_id e.employee_id WHERE d.department_id (SELECT department_id FROMemployees GROUP BY department_id ORDER BY AVG(salary) DESC LIMIT 1) ; 1.3 DD 数据定义语言 #DDL /*数据定义语言库和表的管理一、库的管理创建、修改、删除二、表的管理创建、修改、删除创建 create修改 alter删除 drop */1.3.1 库的管理 1-1 库的创建 /* 语法 create database [if not exists]库名; */#案例创建库Books CREATE DATABASE IF NOT EXISTS books ;1-2 库的修改 RENAME DATABASE books TO 新库名;#更改库的字符集 ALTER DATABASE books CHARACTER SET gbk;1-3 库的删除 DROP DATABASE IF EXISTS books;1.3.2 表的管理 2-1 表的创建 /*语法create table 表名(列名 列的类型【(长度) 约束】,列名 列的类型【(长度) 约束】,列名 列的类型【(长度) 约束】,...列名 列的类型【(长度) 约束】) */ #案例创建表Book CREATE TABLE book(id INT,#编号bName VARCHAR(20),#图书名price DOUBLE,#价格authorId INT,#作者编号publishDate DATETIME#出版日期 );DESC book;#案例创建表author CREATE TABLE IF NOT EXISTS author(id INT,au_name VARCHAR(20),nation VARCHAR(10) ) DESC author; 2-2 表的修改 /* 语法 alter table 表名 add|drop|modify|change column 列名 【列类型 约束】; */2-1 修改列名 #①修改列名 ALTER TABLE book CHANGE COLUMN publishdate pubDate DATETIME;2-2 修改列的类型或约束 #②修改列的类型或约束 ALTER TABLE book MODIFY COLUMN pubdate TIMESTAMP;2-3 添加新列 #③添加新列 ALTER TABLE author ADD COLUMN annual DOUBLE; 2-4 删除列 #④删除列 ALTER TABLE book_author DROP COLUMN annual;2-5 修改表名 #⑤修改表名 ALTER TABLE author RENAME TO book_author;2-3 表的删除 DROP TABLE IF EXISTS book_author;SHOW TABLES;#通用的写法 DROP DATABASE IF EXISTS 旧库名; CREATE DATABASE 新库名;DROP TABLE IF EXISTS 旧表名; CREATE TABLE 表名();2-4 表的复制 INSERT INTO author VALUES (1,村上春树,日本), (2,莫言,中国), (3,冯唐,中国), (4,金庸,中国);SELECT * FROM Author; SELECT * FROM copy2;4-1 仅仅复制表结构 CREATE TABLE copy LIKE author;4-2 复制表的结构数据 CREATE TABLE copy2 SELECT * FROM author;4-3 只复制部分数据 CREATE TABLE copy3 SELECT id,au_name FROM author WHERE nation中国;4-4 仅仅复制某些字段 CREATE TABLE copy4 SELECT id,au_name FROM author WHERE 0; 1.3.3 常见的数据类型 其他1binary 和 varbinary 用于保存较短的二进制2Enum 用于保存枚举3Set 用于保存集合 日期型1date (4 字节) 1000-01-01 ~ 9999-12-312datetime (8 字节)1000-01-01 00:00:00 ~ 9999-12-31 23:59:593timestamp (4 字节) 1970~2038 年的某个时刻受时区的影响4time 只有时间5year 只有年份 1901 ~ 2155*/3-1 整形 /* 1Tinyint1 字节有符号 -128~127无符号 0~2552Smallint2 字节有符号 -32768~32767无符号 0~655353Mediumint3 字节有符号 -8388608~8388607无符号 0~16772154IntInteger4 字节有符号 -2147483648~2147483647无符号 0~42949672955Bigint 8 字节 反正非常非常大特点 ① 如果不设置无符号还是有符号默认是有符号如果想设置无符号需要添加unsigned关键字 ② 如果插入的数值超出了整型的范围,会报out of range异常并且插入临界值 ③ 如果不设置长度会有默认的长度 长度代表了显示的最大宽度如果不够会用0在左边填充但必须搭配zerofill使用 */1-1 设置无符号和有符号 DROP TABLE IF EXISTS tab_int; CREATE TABLE tab_int(t1 INT(7) ZEROFILL,t2 INT(7) ZEROFILL );DESC tab_int;INSERT INTO tab_int VALUES(-123456); INSERT INTO tab_int VALUES(-123456,-123456); INSERT INTO tab_int VALUES(2147483648,4294967296); INSERT INTO tab_int VALUES(123,123);SELECT * FROM tab_int;3-2 小数 /* 浮点型1float(m,d) 4 字节2Double 8 字节定点类型1Dec(m,d) m2 字节2Decimal(m,d)dec,decimal 两者一样。Dec 是简写 特点:1m 是总的位数d 是小数点后面保留的位数2如果超过范围插入的也是临界值3M,d 都能省略4如果 decimal 的话 m 默认是 10d 默认是 05如果是 float 和 double 随着插入的数值的精度来确定精度6定点型精确度较高如果要求插入的数值要求较高如货币运算则可以选择定点型原则选择的类型越简单越好 */CREATE TABLE tab_char(c1 ENUM(a,b,c));INSERT INTO tab_char VALUES(a); INSERT INTO tab_char VALUES(b); INSERT INTO tab_char VALUES(c); INSERT INTO tab_char VALUES(m); INSERT INTO tab_char VALUES(A);SELECT * FROM tab_set;CREATE TABLE tab_set(s1 SET(a,b,c,d) ); INSERT INTO tab_set VALUES(a); INSERT INTO tab_set VALUES(A,B); INSERT INTO tab_set VALUES(a,c,d); 2-1 测试M和D DROP TABLE tab_float; CREATE TABLE tab_float(f1 FLOAT,f2 DOUBLE,f3 DECIMAL ); SELECT * FROM tab_float; DESC tab_float;INSERT INTO tab_float VALUES(123.4523,123.4523,123.4523); INSERT INTO tab_float VALUES(123.456,123.456,123.456); INSERT INTO tab_float VALUES(123.4,123.4,123.4); INSERT INTO tab_float VALUES(1523.4,1523.4,1523.4);#原则 /* 所选择的类型越简单越好能保存数值的类型越小越好 */3-3 字符型 /* 字符型1.Char(m) m 是字符数2.Varcahr(m)3.Text4.Blob(较大的二进制)Char()是固定长度的字符varcahr(m)是固定长度的字符 *//* 较短的文本 char varchar其他 binary和varbinary用于保存较短的二进制 enum用于保存枚举 set用于保存集合较长的文本 text blob(较大的二进制) 特点写法 M的意思 特点 空间的耗费 效率 char char(M) 最大的字符数可以省略默认为1 固定长度的字符 比较耗费 高varchar varchar(M) 最大的字符数不可以省略 可变长度的字符 比较节省 低 */CREATE TABLE tab_char(c1 ENUM(a,b,c) );INSERT INTO tab_char VALUES(a); INSERT INTO tab_char VALUES(b); INSERT INTO tab_char VALUES(c); INSERT INTO tab_char VALUES(m); INSERT INTO tab_char VALUES(A);SELECT * FROM tab_set;CREATE TABLE tab_set(s1 SET(a,b,c,d) );INSERT INTO tab_set VALUES(a); INSERT INTO tab_set VALUES(A,B); INSERT INTO tab_set VALUES(a,c,d);3-4 日期型 /* 分类date只保存日期time 只保存时间year只保存年datetime保存日期时间timestamp保存日期时间特点字节 范围 时区等的影响 datetime 8 1000——9999 不受 timestamp 4 1970-2038 受*/CREATE TABLE tab_date(t1 DATETIME,t2 TIMESTAMP); INSERT INTO tab_date VALUES(NOW(),NOW());SELECT * FROM tab_date;SHOW VARIABLES LIKE time_zone;SET time_zone9:00; 1.3.4 库和表的管理练习 #1. 创建表dept1NAME NULL? TYPEid INT(7)NAME VARCHAR(25)USE test;CREATE TABLE dept1(id INT(7),NAME VARCHAR(25));#2. 将表departments中的数据插入新表dept2中CREATE TABLE dept2SELECT department_id,department_nameFROM myemployees.departments;#3. 创建表emp5NAME NULL? TYPEid INT(7)First_name VARCHAR (25)Last_name VARCHAR(25)Dept_id INT(7)CREATE TABLE emp5(id INT(7),first_name VARCHAR(25),last_name VARCHAR(25),dept_id INT(7));#4. 将列Last_name的长度增加到50ALTER TABLE emp5 MODIFY COLUMN last_name VARCHAR(50);#5. 根据表employees创建employees2CREATE TABLE employees2 LIKE myemployees.employees;#6. 删除表emp5DROP TABLE IF EXISTS emp5;#7. 将表employees2重命名为emp5ALTER TABLE employees2 RENAME TO emp5;#8.在表dept和emp5中添加新列test_column并检查所作的操作ALTER TABLE emp5 ADD COLUMN test_column INT;#9.直接删除表emp5中的列 dept_idDESC emp5;ALTER TABLE emp5 DROP COLUMN test_column;1.3.5 常见的约束 5-1 分类 /* 1. 非空约束 not null 2. 默认约束 default 3. 主键约束 primary key 保证字段值得唯一性非空 4. 为以约束 unique 保证字段值得唯一性可以为空 5. 检查约束 check 在 MySQL 中不支持但不报错 6. 外键约束foreign key 用于限制两个表的关系用于保证该字段的值必须来自主表的关联列的值在从表添加外键约束用于引用主表中某列的值*/5-2 约束添加的分类 ## 1列级约束6 大约束都支持但外键约束没有效果 ## 2表级约束除了非空默认值约束其余的都支持5-3 添加约束的时机、 ## 1.创建表时 ## 2.修改表时5-4 主键和唯一性对比 /* 主键和唯一的大对比保证唯一性 是否允许为空 一个表中可以有多少个 是否允许组合 主键 √ × 至多有1个 √但不推荐 唯一 √ √ 可以有多个 √但不推荐外键1、要求在从表设置外键关系2、从表的外键列的类型和主表的关联列的类型要求一致或兼容名称无要求3、主表的关联列必须是一个key一般是主键或唯一4、插入数据时先插入主表再插入从表删除数据时先删除从表再删除主表 */5-5 添加表时添加约束 5-1 添加列级约束 #1.添加列级约束 /* 语法直接在字段名和类型后面追加 约束类型即可。只支持默认、非空、主键、唯一 */USE students; DROP TABLE stuinfo; CREATE TABLE stuinfo(id INT PRIMARY KEY,#主键stuName VARCHAR(20) NOT NULL UNIQUE,#非空gender CHAR(1) CHECK(gender男 OR gender 女),#检查seat INT UNIQUE,#唯一age INT DEFAULT 18,#默认约束majorId INT REFERENCES major(id)#外键 );CREATE TABLE major(id INT PRIMARY KEY,majorName VARCHAR(20) );#查看stuinfo中的所有索引包括主键、外键、唯一 SHOW INDEX FROM stuinfo;5-2 添加表级约束 /*语法在各个字段的最下面【constraint 约束名】 约束类型(字段名) */DROP TABLE IF EXISTS stuinfo; CREATE TABLE stuinfo(id INT,stuname VARCHAR(20),gender CHAR(1),seat INT,age INT,majorid INT,CONSTRAINT pk PRIMARY KEY(id),#主键CONSTRAINT uq UNIQUE(seat),#唯一键CONSTRAINT ck CHECK(gender 男 OR gender 女),#检查CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)#外键 );SHOW INDEX FROM stuinfo;#通用的写法★ CREATE TABLE IF NOT EXISTS stuinfo(id INT PRIMARY KEY,stuname VARCHAR(20),sex CHAR(1),age INT DEFAULT 18,seat INT UNIQUE,majorid INT,CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id) ); 5-6 修改表时添加约束 6-1 添加列级约束 alter table 表名 modify column 字段名 字段类型 新约束;6-2 添加表级约束 alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】;DROP TABLE IF EXISTS stuinfo; CREATE TABLE stuinfo(id INT,stuname VARCHAR(20),gender CHAR(1),seat INT,age INT,majorid INT ) DESC stuinfo; 6-3 添加非空约束 #1.添加非空约束 ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;6-4 添加默认约束 #2.添加默认约束 ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;6-5 添加主键 #①列级约束ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;#②表级约束ALTER TABLE stuinfo ADD PRIMARY KEY(id);6-6 添加唯一 #①列级约束ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;#②表级约束ALTER TABLE stuinfo ADD UNIQUE(seat);6-7 添加外键 ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id); 5-6 修改表时删除约束 6-1 删除非空约束 ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL;6-2 删除默认约束 ALTER TABLE stuinfo MODIFY COLUMN age INT ;6-3 删除主键 ALTER TABLE stuinfo DROP PRIMARY KEY;6-4 删除唯一 ALTER TABLE stuinfo DROP INDEX seat;6-5 删除外键 ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;1.3.6 标识列 /* 又称为自增长列 含义可以不用手动的插入值系统提供默认的序列值特点 1、标识列必须和主键搭配吗不一定但要求是一个key 2、一个表可以有几个标识列至多一个 3、标识列的类型只能是数值型 4、标识列可以通过 SET auto_increment_increment3;设置步长 可以通过 手动插入值设置起始值 */ 6-1 创建表时创建标识列 DROP TABLE IF EXISTS tab_identity; CREATE TABLE tab_identity(id INT ,NAME FLOAT UNIQUE AUTO_INCREMENT,seat INT );TRUNCATE TABLE tab_identity;INSERT INTO tab_identity(id,NAME) VALUES(NULL,john); INSERT INTO tab_identity(NAME) VALUES(lucy); SELECT * FROM tab_identity;SHOW VARIABLES LIKE %auto_increment%;SET auto_increment_increment3;1.3.7 常见约束 案例讲解 #1.向表emp2的id列中添加PRIMARY KEY约束my_emp_id_pkALTER TABLE emp2 MODIFY COLUMN id INT PRIMARY KEY; ALTER TABLE emp2 ADD CONSTRAINT my_emp_id_pk PRIMARY KEY(id);#2. 向表dept2的id列中添加PRIMARY KEY约束my_dept_id_pk#3. 向表emp2中添加列dept_id并在其中定义FOREIGN KEY约束与之相关联的列是dept2表中的id列。 ALTER TABLE emp2 ADD COLUMN dept_id INT; ALTER TABLE emp2 ADD CONSTRAINT fk_emp2_dept2 FOREIGN KEY(dept_id) REFERENCES dept2(id);位置 支持的约束类型 是否可以起约束名 列级约束 列的后面 语法都支持但外键没有效果 不可以 表级约束 所有列的下面 默认和非空不支持其他支持 可以主键没有效果1.4 DML 数据操纵语言 /*数据操作语言插入insert修改update删除delete */1.4.1 插入 1-1 经典插入 * 语法 insert into 表名(列名,...) values(值1,...);*/ SELECT * FROM beauty; #1.插入的值的类型要与列的类型一致或兼容 INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id) VALUES(13,唐艺昕,女,1990-4-23,1898888888,NULL,2);#2.不可以为null的列必须插入值。可以为null的列如何插入值 #方式一 INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id) VALUES(13,唐艺昕,女,1990-4-23,1898888888,NULL,2);#方式二 INSERT INTO beauty(id,NAME,sex,phone) VALUES(15,娜扎,女,1388888888);#3.列的顺序是否可以调换 INSERT INTO beauty(NAME,sex,id,phone) VALUES(蒋欣,女,16,110);#4.列数和值的个数必须一致 INSERT INTO beauty(NAME,sex,id,phone) VALUES(关晓彤,女,17,110);#5.可以省略列名默认所有列而且列的顺序和表中列的顺序一致 INSERT INTO beauty VALUES(18,张飞,男,NULL,119,NULL,NULL); 1-2 插入方式2 /*语法 insert into 表名 set 列名值,列名值,... */INSERT INTO beauty SET id19,NAME刘涛,phone999; 1-3 两种方式比较 #1、方式一支持插入多行,方式二不支持INSERT INTO beauty VALUES(23,唐艺昕1,女,1990-4-23,1898888888,NULL,2) ,(24,唐艺昕2,女,1990-4-23,1898888888,NULL,2) ,(25,唐艺昕3,女,1990-4-23,1898888888,NULL,2);#2、方式一支持子查询方式二不支持 INSERT INTO beauty(id,NAME,phone) SELECT 26,宋茜,11809866;INSERT INTO beauty(id,NAME,phone) SELECT id,boyname,1234567 FROM boys WHERE id3;1.4.2 修改 /*1.修改单表的记录★语法update 表名set 列新值,列新值,...where 筛选条件;2.修改多表的记录【补充】语法sql92语法update 表1 别名,表2 别名set 列值,...where 连接条件and 筛选条件;sql99语法update 表1 别名inner|left|right join 表2 别名on 连接条件set 列值,...where 筛选条件;*/2-1 修改单表记录 #案例1修改beauty表中姓唐的女神的电话为13899888899UPDATE beauty SET phone 13899888899 WHERE NAME LIKE 唐%;#案例2修改boys表中id好为2的名称为张飞魅力值 10 UPDATE boys SET boyname张飞,usercp10 WHERE id2;2-2 修改多表记录 #案例 1修改张无忌的女朋友的手机号为114 UPDATE boys bo INNER JOIN beauty b ON bo.idb.boyfriend_id SET b.phone119,bo.userCP1000 WHERE bo.boyName张无忌;#案例2修改没有男朋友的女神的男朋友编号都为2号 UPDATE boys bo RIGHT JOIN beauty b ON bo.idb.boyfriend_id SET b.boyfriend_id2 WHERE bo.id IS NULL;SELECT * FROM boys;1.4.3 删除语句 /*方式一delete 语法1、单表的删除【★】delete from 表名 where 筛选条件2、多表的删除【补充】 sql92语法delete 表1的别名,表2的别名from 表1 别名,表2 别名where 连接条件and 筛选条件;sql99语法delete 表1的别名,表2的别名from 表1 别名inner|left|right join 表2 别名 on 连接条件where 筛选条件;方式二truncate 语法truncate table 表名;*/ 3-1 delete 1-1 单表删除 #案例删除手机号以9结尾的女神信息 DELETE FROM beauty WHERE phone LIKE %9; SELECT * FROM beauty; 1-2 多表删除 #案例删除张无忌的女朋友的信息 DELETE b FROM beauty b INNER JOIN boys bo ON b.boyfriend_id bo.id WHERE bo.boyName张无忌;#案例删除黄晓明的信息以及他女朋友的信息 DELETE b,bo FROM beauty b INNER JOIN boys bo ON b.boyfriend_idbo.id WHERE bo.boyName黄晓明;3-2 truncate语句 #案例将魅力值100的男神信息删除 TRUNCATE TABLE boys 3-3 delete pk truncate /*1.delete 可以加where 条件truncate不能加2.truncate删除效率高一丢丢 3.假如要删除的表中有自增长列 如果用delete删除后再插入数据自增长列的值从断点开始而truncate删除后再插入数据自增长列的值从1开始。 4.truncate删除没有返回值delete删除有返回值5.truncate删除不能回滚delete删除可以回滚. */SELECT * FROM boys;DELETE FROM boys; TRUNCATE TABLE boys; INSERT INTO boys (boyname,usercp) VALUES(张飞,100),(刘备,100),(关云长,100);1.4.4 案例讲解 #1. 运行以下脚本创建表my_employeesUSE myemployees; CREATE TABLE my_employees(Id INT(10),First_name VARCHAR(10),Last_name VARCHAR(10),Userid VARCHAR(10),Salary DOUBLE(10,2) ); CREATE TABLE users(id INT,userid VARCHAR(10),department_id INT); #2. 显示表my_employees的结构DESC my_employees;#3. 向my_employees表中插入下列数据ID FIRST_NAME LAST_NAME USERID SALARY1 patel Ralph Rpatel 8952 Dancs Betty Bdancs 8603 Biri Ben Bbiri 11004 Newman Chad Cnewman 7505 Ropeburn Audrey Aropebur 1550#方式一INSERT INTO my_employeesVALUES(1,patel,Ralph,Rpatel,895),(2,Dancs,Betty,Bdancs,860),(3,Biri,Ben,Bbiri,1100),(4,Newman,Chad,Cnewman,750),(5,Ropeburn,Audrey,Aropebur,1550);DELETE FROM my_employees;#方式二INSERT INTO my_employeesSELECT 1,patel,Ralph,Rpatel,895 UNIONSELECT 2,Dancs,Betty,Bdancs,860 UNIONSELECT 3,Biri,Ben,Bbiri,1100 UNIONSELECT 4,Newman,Chad,Cnewman,750 UNIONSELECT 5,Ropeburn,Audrey,Aropebur,1550;#4. 向users表中插入数据1 Rpatel 102 Bdancs 103 Bbiri 204 Cnewman 305 Aropebur 40INSERT INTO usersVALUES(1,Rpatel,10),(2,Bdancs,10),(3,Bbiri,20);#5.将3号员工的last_name修改为“drelxer”UPDATE my_employees SET last_namedrelxer WHERE id 3;#6.将所有工资少于900的员工的工资修改为1000UPDATE my_employees SET salary1000 WHERE salary900;#7.将userid 为Bbiri的user表和my_employees表的记录全部删除DELETE u,eFROM users uJOIN my_employees e ON u.useride.UseridWHERE u.useridBbiri;#8.删除所有数据DELETE FROM my_employees;DELETE FROM users;#9.检查所作的修正SELECT * FROM my_employees;SELECT * FROM users;#10.清空表my_employeesTRUNCATE TABLE my_employees; 1.5 TCL 事务控制语言 1.5.1 事务的属性 1. 原子性 ## 事务是一个不可分割的工作单位事务中的操作要么都发生要么都不发生 2. 一致性 ## 事务必须使数据库从一个形状状态变换到另外一个一致性状态 3. 隔离性 ## 一个事务不能被其他事务干扰事务之间是隔离的互不干扰 4. 持久性 ## 事务一旦被提交它对数据库中数据的改变就是永久性的1.5.2 事务的创建 ## 隐式事务事务没有明显的开启和结束标记比如 insertupdatedelete 语句 ## 显示事务具有明显的开启和结束标志。先设置自动提交功能为禁用SET autocommit 0;## 步骤一开启事务1Set autocommit 0;2Start transaction;(可选的可以不写)## 步骤二编写事务中的 SQL 语句3语句 1;selectinsertupdatedelete4语句 2## 步骤三结束事务提交事务或回滚事务commit or rollback1.5.3 演示事务的使用步骤 #开启事务SET autocommit0;START TRANSACTION;#编写一组事务的语句UPDATE account SET balance 1000 WHERE username张无忌;UPDATE account SET balance 1000 WHERE username赵敏;#结束事务ROLLBACK;#commit; 1.5.4 隔离机制 ## 对于同时运行的多个事务当这些事务访问数据库中的相同数据时如果没有采取必要的隔离机制就会导致各种并发问题## 脏读对于两个事务 T1T2T1 读取了已经被 T2 更新但还没被提交的字段之后若 T2 回滚T1 读取的内容就是临时无效的## 不可重复读对于两个事务 T1T2T1 读取了一个字段然后 T2 更新了该字段之后T1 再次读取该字段值就不一样了## 幻读对于两个事务 T1T2T1 从一个表中读取了一个字段然后 T2 在该表中插入了一些新的行之后如果 T1 再次读取同一个表就会多出几行1.5.5 四种隔离级别 ## MySQL 支持 4 种事务隔离级别。MySQL 默认的事务隔离级别为REPEATABLE READ1.5.6 注意 ## 15.7.2 之前 使用 show variables like tx_isoation 或者 select tx_isolation; ## 2 5.7.2 之 后 使 用 show variables like transaction_isoation 或 者 select transaction_isoation;Savepoint:节点名设置保存点 SET autocommit0; START TRANSACTION; DELETE FROM account WHERE id25; SAVEPOINT a;#设置保存点 DELETE FROM account WHERE id28; ROLLBACK TO a;#回滚到保存点SELECT * FROM account;1.5.7 演示事务对于delete和truncate的处理的区别 SET autocommit0; START TRANSACTION;DELETE FROM account; ROLLBACK; 1.5.8 视图 /* 含义虚拟表和普通表一样使用 mysql5.1版本出现的新特性是通过表动态生成的数据比如舞蹈班和普通班级的对比创建语法的关键字 是否实际占用物理空间 使用视图 create view 只是保存了sql逻辑 增删改查只是一般不能增删改表 create table 保存了数据 增删改查 */8-1 视图创建 /* 语法 create view 视图名 as 查询语句;*/ USE myemployees;#1.查询姓名中包含a字符的员工名、部门名和工种信息 #①创建 CREATE VIEW myv1 ASSELECT last_name,department_name,job_title FROM employees e JOIN departments d ON e.department_id d.department_id JOIN jobs j ON j.job_id e.job_id;#②使用 SELECT * FROM myv1 WHERE last_name LIKE %a%;#2.查询各部门的平均工资级别#①创建视图查看每个部门的平均工资CREATE VIEW myv2ASSELECT AVG(salary) ag,department_idFROM employeesGROUP BY department_id;#②使用SELECT myv2.ag,g.grade_levelFROM myv2JOIN job_grades gON myv2.ag BETWEEN g.lowest_sal AND g.highest_sal;#3.查询平均工资最低的部门信息 SELECT * FROM myv2 ORDER BY ag LIMIT 1;#4.查询平均工资最低的部门名和工资 CREATE VIEW myv3 AS SELECT * FROM myv2 ORDER BY ag LIMIT 1;SELECT d.*,m.ag FROM myv3 m JOIN departments d ON m.department_idd.department_id; 8-2 视图的修改 2-1 方式1 #方式一 /* create or replace view 视图名 as 查询语句; */ SELECT * FROM myv3 CREATE OR REPLACE VIEW myv3 AS SELECT AVG(salary),job_id FROM employees GROUP BY job_id;2-2 方式2 /* 语法 alter view 视图名 as 查询语句; */ ALTER VIEW myv3 AS SELECT * FROM employees;8-3 视图的删除 /* 语法drop view 视图名,视图名,...; */DROP VIEW emp_v1,emp_v2,myv3;8-4 查看视图 DESC myv3;SHOW CREATE VIEW myv3;8-5 视图的更新 CREATE OR REPLACE VIEW myv1 AS SELECT last_name,email,salary*12*(1IFNULL(commission_pct,0)) annual salary FROM employees;CREATE OR REPLACE VIEW myv1 AS SELECT last_name,email FROM employees;SELECT * FROM myv1; SELECT * FROM employees;5-1 插入 INSERT INTO myv1 VALUES(张飞,zfqq.com);5-2 修改 UPDATE myv1 SET last_name 张无忌 WHERE last_name张飞;5-3 删除 DELETE FROM myv1 WHERE last_name 张无忌;5-4 注意 #具备以下特点的视图不允许更新 #①包含以下关键字的sql语句分组函数、distinct、group by、having、union或者union allCREATE OR REPLACE VIEW myv1 AS SELECT MAX(salary) m,department_id FROM employees GROUP BY department_id;SELECT * FROM myv1;#更新 UPDATE myv1 SET m9000 WHERE department_id10;#②常量视图 CREATE OR REPLACE VIEW myv2 AS SELECT john NAME;SELECT * FROM myv2;#更新 UPDATE myv2 SET NAMElucy;#③Select中包含子查询 CREATE OR REPLACE VIEW myv3 ASSELECT department_id,(SELECT MAX(salary) FROM employees) 最高工资 FROM departments;#更新 SELECT * FROM myv3; UPDATE myv3 SET 最高工资100000;#④join CREATE OR REPLACE VIEW myv4 ASSELECT last_name,department_name FROM employees e JOIN departments d ON e.department_id d.department_id;#更新SELECT * FROM myv4; UPDATE myv4 SET last_name 张飞 WHERE last_nameWhalen; INSERT INTO myv4 VALUES(陈真,xxxx);#⑤from一个不能更新的视图 CREATE OR REPLACE VIEW myv5 ASSELECT * FROM myv3;#更新 SELECT * FROM myv5;UPDATE myv5 SET 最高工资10000 WHERE department_id60;#⑥where子句的子查询引用了from子句中的表 CREATE OR REPLACE VIEW myv6 ASSELECT last_name,email,salary FROM employees WHERE employee_id IN(SELECT manager_idFROM employeesWHERE manager_id IS NOT NULL );#更新 SELECT * FROM myv6; UPDATE myv6 SET salary10000 WHERE last_name k_ing;1.5.9 视图案例讲解 #一、创建视图emp_v1,要求查询电话号码以‘011’开头的员工姓名和工资、邮箱 CREATE OR REPLACE VIEW emp_v1 AS SELECT last_name,salary,email FROM employees WHERE phone_number LIKE 011%;#二、创建视图emp_v2要求查询部门的最高工资高于12000的部门信息 CREATE OR REPLACE VIEW emp_v2 AS SELECT MAX(salary) mx_dep,department_id FROM employees GROUP BY department_id HAVING MAX(salary)12000;SELECT d.*,m.mx_dep FROM departments d JOIN emp_v2 m ON m.department_id d.department_id;1.5.10 变量 10-1 系统变量 ## 系统变量变量由系统提供不是用户定义属于服务器层面## 1查看所有的系统变量 SHOW VARIABLES;## 2查看满足条件的部分系统变量SHOW VARIABLES LIKE %char%;## 3查看指定的某个系统的变量值SELECT character_set_client;global.变量名 session.变量名 变量名## 4为系统变量名赋值1set 变量名 值global.变量名||session.变量名2Set global.变量名 值 (session.变量名)## 如果是全局级别加 global如果是会话级别加 session 关键字1-1 全局变量 ## 全局变量 SHOW GLOBAL VARIABLES;(1) 查看部分全局变量SHOW GLOBAL VARIABLES LIKE %char%(2) 查看指定的全局变量的值SELECT global.autocommit;(3) 为某个指定的全局变量赋值 SET global.autocommit0;## 作用域服务器每次启动将为所有的全局变量赋初始值针对于所有的会话连接有效但不能跨重启1-2 会话变量 SHOW SESSION VARIABLES; ## 作用域仅仅针对于当前的会话连接有效(1) 查看部分会话变量SHOW SESSION VARIABLES LIKE %char%(2) 查看指定的全局变量的值SELECT SESSION.autocommit;(3) 为某个指定的全局变量赋值 SET SESSION.变量名值;10-2 自定义变量 ## 自定义变量: 用户自定义的变量不是系统提供的2-1 用户变量 ## 作用域仅仅针对于当前的会话连接有效可以应用在任何地方1 声明并初始化## 1SET 用户变量名:值(为了不跟等号起冲突);## 2SET 用户变量名值## 3SELECT 用户变量名:值2 更新用户变量的值跟声明初始化一样## (1) SET 用户变量名:值(为了不跟等号起冲突);## (2) SET 用户变量名值## (3) SELECT 用户变量名:值## (4) SELECT 字段 INTO 变量名 FROM 表查询出来的值必须是一个值才能赋给这个变量3 查看用户变量的值## 1SELECT 用户变量名2-2 局部变量 ## 作用域仅仅在定义它的 begin end 中有效 1) 声明DECLARE 变量名 类型 || DECLARE 变量名 类型 DEFAULT 值2) 赋值## 1SET 用户变量名:值(为了不跟等号起冲突);## 2SET 用户变量名值## 3SELECT 用户变量名:值## 4SELECT 字段 INTO 变量名 FROM 表3) 使用SELECT 局部变量名2-3 案例 #案例声明两个变量求和并打印#用户变量 SET m1; SET n1; SET summn; SELECT sum;#局部变量 DECLARE m INT DEFAULT 1; DECLARE n INT DEFAULT 1; DECLARE SUM INT; SET SUMmn; SELECT SUM;#用户变量和局部变量的对比作用域 定义位置 语法 用户变量 当前会话 会话的任何地方 加符号不用指定类型 局部变量 定义它的BEGIN END中 BEGIN END的第一句话 一般不用加,需要指定类型 1.5.11 存储过程函数 /* 含义一组预先编译好的 SQL 语句的集合理解成批处理语句1提高代码的重用性2简化操作3减少了编译次数和数据库服务器的连接次数提高了效率A.创建语法CREATE PROCEDURE 存储过程名字(参数列表) BEGIN 存储过程体 END;(1)参数列表包含三部分参数模式 参数名 参数类型 In stuname varchar(20);(2)参数模式三种模式a.In该参数可以作为输入需要调用方传入值 b.Out该参数可以作为输出也就是说该参数可以作为返回值 c.Inout该参数既可以作为输入又可以作为输出(3)如果存储过程仅仅只有一句话则begin end可以省略(4)存储过程中的每条SQL语句结尾要求必须加分号存储过程结尾可以使用delimiter 结束标记(5)调用语法call 存储过程名(实参列表);*/11-1 创建语法 CREATE PROCEDURE 存储过程名(参数列表) BEGIN存储过程体一组合法的SQL语句 END#注意 /* 1、参数列表包含三部分 参数模式 参数名 参数类型 举例 in stuname varchar(20)参数模式 in该参数可以作为输入也就是该参数需要调用方传入值 out该参数可以作为输出也就是该参数可以作为返回值 inout该参数既可以作为输入又可以作为输出也就是该参数既需要传入值又可以返回值2、如果存储过程体仅仅只有一句话begin end可以省略 存储过程体中的每条sql语句的结尾要求必须加分号。 存储过程的结尾可以使用 delimiter 重新设置 语法 delimiter 结束标记 案例 delimiter $ */11-2 调用语法 CALL 存储过程名(实参列表);2-1 空参列表 #案例插入到admin表中五条记录SELECT * FROM admin;DELIMITER $ CREATE PROCEDURE myp1() BEGININSERT INTO admin(username,password) VALUES(john1,0000),(lily,0000),(rose,0000),(jack,0000),(tom,0000); END $#调用 CALL myp1()$2-2 in模式 #案例1创建存储过程实现 根据女神名查询对应的男神信息CREATE PROCEDURE myp2(IN beautyName VARCHAR(20)) BEGINSELECT bo.*FROM boys boRIGHT JOIN beauty b ON bo.id b.boyfriend_idWHERE b.namebeautyName;END $#调用 CALL myp2(柳岩)$#案例2 创建存储过程实现用户是否登录成功CREATE PROCEDURE myp4(IN username VARCHAR(20),IN PASSWORD VARCHAR(20)) BEGINDECLARE result INT DEFAULT 0;#声明并初始化SELECT COUNT(*) INTO result#赋值FROM adminWHERE admin.username usernameAND admin.password PASSWORD;SELECT IF(result0,成功,失败);#使用 END $#调用 CALL myp3(张飞,8888)$ 2-3 out模式 #案例1根据输入的女神名返回对应的男神名 CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20)) BEGINSELECT bo.boyname INTO boynameFROM boys boRIGHT JOINbeauty b ON b.boyfriend_id bo.idWHERE b.namebeautyName ;END $#案例2根据输入的女神名返回对应的男神名和魅力值 CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT) BEGINSELECT boys.boyname ,boys.usercp INTO boyname,usercpFROM boys RIGHT JOINbeauty b ON b.boyfriend_id boys.idWHERE b.namebeautyName ; END $#调用 CALL myp7(小昭,name,cp)$ SELECT name,cp$2-4 in-out模式 #案例1传入a和b两个值最终a和b都翻倍并返回CREATE PROCEDURE myp8(INOUT a INT ,INOUT b INT) BEGINSET aa*2;SET bb*2; END $#调用 SET m10$ SET n20$ CALL myp8(m,n)$ SELECT m,n$ 11-3 删除存储过程 #语法drop procedure 存储过程名 DROP PROCEDURE p1; DROP PROCEDURE p2,p3;#×11-4 查看存储过程 DESC myp2; SHOW CREATE PROCEDURE myp2;11-5 存储过程案例讲解 #一、创建存储过程实现传入用户名和密码插入到admin表中CREATE PROCEDURE test_pro1(IN username VARCHAR(20),IN loginPwd VARCHAR(20)) BEGININSERT INTO admin(admin.username,PASSWORD)VALUES(username,loginpwd); END $#二、创建存储过程实现传入女神编号返回女神名称和女神电话CREATE PROCEDURE test_pro2(IN id INT,OUT NAME VARCHAR(20),OUT phone VARCHAR(20))BEGINSELECT b.name ,b.phone INTO NAME,phoneFROM beauty bWHERE b.id id;END $ #三、创建存储存储过程或函数实现传入两个女神生日返回大小CREATE PROCEDURE test_pro3(IN birth1 DATETIME,IN birth2 DATETIME,OUT result INT) BEGINSELECT DATEDIFF(birth1,birth2) INTO result; END $ #四、创建存储过程或函数实现传入一个日期格式化成xx年xx月xx日并返回 CREATE PROCEDURE test_pro4(IN mydate DATETIME,OUT strDate VARCHAR(50)) BEGINSELECT DATE_FORMAT(mydate,%y年%m月%d日) INTO strDate; END $CALL test_pro4(NOW(),str)$ SELECT str $#五、创建存储过程或函数实现传入女神名称返回女神 and 男神 格式的字符串 如 传入 小昭 返回 小昭 AND 张无忌 DROP PROCEDURE test_pro5 $ CREATE PROCEDURE test_pro5(IN beautyName VARCHAR(20),OUT str VARCHAR(50)) BEGINSELECT CONCAT(beautyName, and ,IFNULL(boyName,null)) INTO strFROM boys boRIGHT JOIN beauty b ON b.boyfriend_id bo.idWHERE b.namebeautyName;SET str END $CALL test_pro5(柳岩,str)$ SELECT str $#六、创建存储过程或函数根据传入的条目数和起始索引查询beauty表的记录 DROP PROCEDURE test_pro6$ CREATE PROCEDURE test_pro6(IN startIndex INT,IN size INT) BEGINSELECT * FROM beauty LIMIT startIndex,size; END $CALL test_pro6(3,5)$1.5.12 函数 12-1 创建语法 create function 函数名(函数列表) returns 返回类型 begin 函数体 end/* 含义一组预先编译好的SQL语句的集合理解成批处理语句 1、提高代码的重用性 2、简化操作 3、减少了编译次数并且减少了和数据库服务器的连接次数提高了效率区别 存储过程可以有0个返回也可以有多个返回适合做批量插入、批量更新 函数有且仅有1 个返回适合做处理数据后返回一个结果*/12-2 注意 1.参数列表包含两个部分参数名和参数类型 2.函数体肯定会有return语句如果没有会报错如果return语句没有放在函数体的最后也不报错但不建议 3.函数体中仅有一句话则可以省略begin end 4.使用delimiter语句设置结束标记12-3 调用语法 SELECT 函数名(参数列表)3-1 无参有返回 #1.无参有返回 #案例返回公司的员工个数 CREATE FUNCTION myf1() RETURNS INT BEGINDECLARE c INT DEFAULT 0;#定义局部变量SELECT COUNT(*) INTO c#赋值FROM employees;RETURN c; END $SELECT myf1()$3-2 有参有返回 #案例1根据员工名返回它的工资 CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE BEGINSET sal0;#定义用户变量 SELECT salary INTO sal #赋值FROM employeesWHERE last_name empName;RETURN sal; END $SELECT myf2(k_ing) $#案例2根据部门名返回该部门的平均工资 CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE BEGINDECLARE sal DOUBLE ;SELECT AVG(salary) INTO salFROM employees eJOIN departments d ON e.department_id d.department_idWHERE d.department_namedeptName;RETURN sal; END $SELECT myf3(IT)$12-4 查看函数 SHOW CREATE FUNCTION myf3;12 -5 删除函数 DROP FUNCTION myf3;12-6 案例 #一、创建函数实现传入两个float返回二者之和 CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT BEGINDECLARE SUM FLOAT DEFAULT 0;SET SUMnum1num2;RETURN SUM; END $SELECT test_fun1(1,2)$ 1.5.13 流程控制机构 13-1 分支结构 1-1 if函数 ## 语法## IF(表达式1表达式2表达式3)## 如果表达式1成立则返回表达式2的值不成立则返回表达式3的值1-2 case 结构 ① 一般用于实现等值判断 ② 一般用于实现区间判断语法1 CASE 变量|表达式|字段 WHEN 要判断的值1 THEN 返回的值1WHEN 要判断的值2 THEN 返回的值2WHEN 要判断的值3 THEN 返回的值3...ELSE 要返回的值nEND CASE; 语法2 CASE WHEN 要判断的条件1 THEN 返回的语句1或值WHEN 要判断的条件2 THEN 返回的值2或语句WHEN 要判断的条件3 THEN 返回的值3或语句...ELSE 要返回的条件nEND CASE; ## 特点可以作为表达式嵌套在其他语句中使用也可以作为独立的语句使用可以放在任何地方如果作为独立的语句只用只能放在begin end中#案例1创建函数实现传入成绩如果成绩90,返回A如果成绩80,返回B如果成绩60,返回C否则返回D CREATE FUNCTION test_case(score FLOAT) RETURNS CHAR BEGIN DECLARE ch CHAR DEFAULT A;CASE WHEN score90 THEN SET chA;WHEN score80 THEN SET chB;WHEN score60 THEN SET chC;ELSE SET chD;END CASE;RETURN ch; END $SELECT test_case(56)$1-3 if 结构 ## 语法IF 条件1 THEN 语句1ELSEIF 条件2 THEN 语句2,,,ELSE 条件n;END IF;## 应用在begin end 中#案例1创建函数实现传入成绩如果成绩90,返回A如果成绩80,返回B如果成绩60,返回C否则返回D CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR BEGINDECLARE ch CHAR DEFAULT A;IF score90 THEN SET chA;ELSEIF score80 THEN SET chB;ELSEIF score60 THEN SET chC;ELSE SET chD;END IF;RETURN ch; END $SELECT test_if(87)$#案例2创建存储过程如果工资2000,则删除如果5000工资2000,则涨工资1000否则涨工资500 CREATE PROCEDURE test_if_pro(IN sal DOUBLE) BEGINIF sal2000 THEN DELETE FROM employees WHERE employees.salarysal;ELSEIF sal2000 AND sal5000 THEN UPDATE employees SET salarysalary1000 WHERE employees.salarysal;ELSE UPDATE employees SET salarysalary500 WHERE employees.salarysal;END IF;END $CALL test_if_pro(2100)$13-2 循环结构 2-1 分类 WHILE, LOOP, REPEAT, 1.ITERATE 类似于continue结束本次循环继续下次循环 2.LEAVE 类似于 break跳出结束当前所在的循环2-2 语法 #1.while /* 语法【标签:】while 循环条件 do循环体; end while【 标签】;while(循环条件){循环体; } */#2.loop /* 语法 【标签:】loop循环体; end loop 【标签】;可以用来模拟简单的死循环 */#3.repeat /* 语法 【标签】repeat循环体; until 结束循环的条件 end repeat 【标签】;*/2-3 案例 #1.没有添加循环控制语句 #案例批量插入根据次数插入到admin表中多条记录 DROP PROCEDURE pro_while1$ CREATE PROCEDURE pro_while1(IN insertCount INT) BEGINDECLARE i INT DEFAULT 1;WHILE iinsertCount DOINSERT INTO admin(username,password) VALUES(CONCAT(Rose,i),666);SET ii1;END WHILE;END $CALL pro_while1(100)$/*int i1; while(iinsertcount){//插入i;}*/#2.添加leave语句#案例批量插入根据次数插入到admin表中多条记录如果次数20则停止 TRUNCATE TABLE admin$ DROP PROCEDURE test_while1$ CREATE PROCEDURE test_while1(IN insertCount INT) BEGINDECLARE i INT DEFAULT 1;a:WHILE iinsertCount DOINSERT INTO admin(username,password) VALUES(CONCAT(xiaohua,i),0000);IF i20 THEN LEAVE a;END IF;SET ii1;END WHILE a; END $CALL test_while1(100)$#3.添加iterate语句#案例批量插入根据次数插入到admin表中多条记录只插入偶数次 TRUNCATE TABLE admin$ DROP PROCEDURE test_while1$ CREATE PROCEDURE test_while1(IN insertCount INT) BEGINDECLARE i INT DEFAULT 0;a:WHILE iinsertCount DOSET ii1;IF MOD(i,2)!0 THEN ITERATE a;END IF;INSERT INTO admin(username,password) VALUES(CONCAT(xiaohua,i),0000);END WHILE a; END $CALL test_while1(100)$/*int i0; while(iinsertCount){i;if(i%20){continue;}插入 } */ 13-3 流程控制案例讲解 /*一、已知表stringcontent 其中字段 id 自增长 content varchar(20)向该表插入指定个数的随机的字符串 */ DROP TABLE IF EXISTS stringcontent; CREATE TABLE stringcontent(id INT PRIMARY KEY AUTO_INCREMENT,content VARCHAR(20)); DELIMITER $ CREATE PROCEDURE test_randstr_insert(IN insertCount INT) BEGINDECLARE i INT DEFAULT 1;DECLARE str VARCHAR(26) DEFAULT abcdefghijklmnopqrstuvwxyz;DECLARE startIndex INT;#代表初始索引DECLARE len INT;#代表截取的字符长度WHILE iinsertcount DOSET startIndexFLOOR(RAND()*261);#代表初始索引随机范围1-26SET lenFLOOR(RAND()*(20-startIndex1)1);#代表截取长度随机范围1-20-startIndex1INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startIndex,len));SET ii1;END WHILE;END $CALL test_randstr_insert(10)$1.6 python连接MySQL 1.6.1 连接数据库 import pymysql# 连接MySQL数据库 db pymysql.connect(host127.0.0.1, userroot, password123456, databasetest,port3306)# 设置字符集 防止乱码 db.set_charset(utf8)# 创建游标对象 cursor db.cursor()# 准备SQL sql select * from user # 执行SQL语句 cursor.execute(sql)# 获取所有 print(cursor.fetchall()) print(cursor.fetchone())# 关闭数据库连接 db.close()1.6.2 事件回滚 import pymysql# 连接MySQL数据库 db pymysql.connect(host127.0.0.1, userroot, password123456, databasetest,port3306)# 设置字符集 防止乱码 db.set_charset(utf8)# 创建游标对象 cursor db.cursor()try:# 准备插入SQL语句sql insert into user values(4,刘强东, 50, 男)# 执行SQL语句cursor.execute(sql)# 提交事务 保存到数据库中db.commit() except Exception as e:print(e)# 回滚db.rollback() # 对于插入获取受影响的行数 print(cursor.rowcount)# 关闭数据库连接 db.close()2Redis 举例普通连接 import redis# decode_responsesTrue 自动解码 r redis.Redis(host127.0.0.1,port6379,password123456,db0,decode_responsesTrue) #默认数据库为0 r redis.StrictRedis(host10.10.2.14,port6379,password123456,decode_responsesTrue)连接池connection pool 管理对一个redis server的所有连接避免每次建立释放连接的开销。默认每个redis实例都会维护一个自己的连接池可以直接建立一个连接池作为参数传给redis这样可以实现多个redis实例共享一个连接池。 举例连接池 pool redis.ConnectionPool(host127.0.0.1,port6379,db0,password123456,decode_responsesTrue)r redis.Redis(connection_poolpool)八Python进阶知识 1编码相关 1.1 指定默认的读文件的解码格式保证不乱码 这不是注释第一行是固定格式 #coding:用什么编码格式读文件 # coding:utg-8 (如果写代码时指定则就是用什么方式编码如果读文件时指定则以什么格式解码) # 代码内容#Python3里的str类型默认直接存成Unicode所以不存在乱码 #·若要保证Python2的str类型也不乱码 x u艾尼你好 # 前面加上u,意思就是Unicode编码注Python3默认用utf-8解码 Python2用ASCII码解码 2 读写文件 2.1 控制文件读写内容的模式t和b # 强调读写不能单独使用必须跟r/w/a连用open()方法with 语法 1t模式(默认的模式) # 读写都以strUnicode为单位# 必须指定encodingutf-8# 必须是文本文件才可以指定编码 2b模式# 是对字节进行操作# 不用指定编码#文件操作基本流程 1打开文件# window系统路径分割问题# 解决方案一推荐f open(rC:\a\b\c\aini.txt)# 解决方案二open这函数已经解决好了右斜杠也可以f open(C:/a/b/c/aini.txt) 2操作文件f open(./aini.txt,moder,encodingutf-8)res f.read() # 指针会停在最后所以第二次读的时候没内容需要重新打开文件重新读取# 会读取所有内容 3关闭文件f.close() #回收操作系统资源 2.2 文件操作的模式 # 文件操作模式# r w a 默认都是t模式对文本进行操作(rt,wt,at)# rb wb ab 对字节进行操作# a 是追加模式会往文件末尾开始写w会把源文件清空掉# rt 可读可写文件不存在直接报错# wt 可读可写# 指针移动# 指针移动的单位都是bytes字节为单位# 只有一种特殊情况# t模式下的read(n),n代表的是字符个数with open(./aini.txt,modert,encodingutf-8) as f:f.read(4) # 四个字符### 注意 只有0模式在t模式下使用f.seek(n,模式) # n值得是指针移动的字节个数n可以是负数可以倒着移动# 模式 # 0 参照的是文件开头位置# 1 参照的是当前指针的所造位置# 2 参照物是文件末尾f.tell ## 获取指针当前位置3函数参数详解 3.1 位置参数--------关键字参数---------混合使用 1位置实参:在函数调用阶段 按照从左到有的顺序依次传入的值 # 特点按照顺序与形参一一对应2 关键字参数 # 关键字实参在函数调用阶段按照keyvalue的形式传入的值 # 特点指名道姓给某个形参传值可以完全不参照顺序 def func(x,y):print(x,y)func(y2,x1) # 关键字参数 func(1,2) # 位置参数3混合使用强调# 1、位置实参必须放在关键字实参前def func(x,y):print(x,y)func(1,y2)func(y2,1)# 2、不能能为同一个形参重复传值def func(x,y):print(x,y)func(1,y2,x3)func(1,2,x3,y4)3.2 默认参数------位置参数与默认参数混用 4默认参数# 默认形参在定义函数阶段就已经被赋值的形参称之为默认参数# 特点在定义阶段就已经被赋值意味着在调用阶段可以不用为其赋值def func(x,y3):print(x,y)func(x1)func(x1,y44444)def register(name,age,gender男):print(name,age,gender)register(三炮,18)register(二炮,19) register(大炮,19)register(没炮,19,女)5位置形参与默认形参混用强调# 1、位置形参必须在默认形参的左边def func(y2,x): # 错误写法pass# 2、默认参数的值是在函数定义阶段被赋值的准确地说被赋予的是值的内存地址# 示范1m2def func(x,ym): # y2的内存地址print(x,ym3333333333333333333func(1)# 3、虽然默认值可以被指定为任意数据类型但是不推荐使用可变类型# 函数最理想的状态函数的调用只跟函数本身有关系不外界代码的影响m [111111, ]def func(x, ym):print(x, y)m.append(3333333)m.append(444444)m.append(5555)func(1)func(2)func(3)def func(x,y,z,lNone):if l is None:l[]l.append(x)l.append(y)l.append(z)print(l)func(1,2,3)func(4,5,6)new_l[111,222]func(1,2,3,new_l)3.3 可变长度的参数 6可变长度的参数*与**的用法# 可变长度指的是在调用函数时传入的值实参的个数不固定# 而实参是用来为形参赋值的所以对应着针对溢出的实参必须有对应的形参来接收6.1 可变长度的位置参数# I*形参名用来接收溢出的位置实参溢出的位置实参会被*保存成元组的格式然后赋值紧跟其后的形参名# *后跟的可以是任意名字但是约定俗成应该是argsdef func(x,y,*z): # z 3,4,5,6print(x,y,z)func(1,2,3,4,5,6)def my_sum(*args):res0for item in args:resitemreturn resresmy_sum(1,2,3,4,)print(res)# II: *可以用在实参中实参中带*先*后的值打散成位置实参def func(x,y,z):print(x,y,z)func(*[11,22,33]) # func(112233)func(*[11,22]) # func(1122)l[11,22,33]func(*l)# III: 形参与实参中都带*def func(x,y,*args): # args(3,4,5,6)print(x,y,args)func(1,2,[3,4,5,6])func(1,2,*[3,4,5,6]) # func(1,2,3,4,5,6)func(*hello) # func(h,e,l,l,o)6.2 可变长度的关键字参数# I**形参名用来接收溢出的关键字实参**会将溢出的关键字实参保存成字典格式然后赋值给紧跟其后的形参名# **后跟的可以是任意名字但是约定俗成应该是kwargsdef func(x,y,**kwargs):print(x,y,kwargs)func(1,y2,a1,b2,c3)# II: **可以用在实参中(**后跟的只能是字典)实参中带**先**后的值打散成关键字实参def func(x,y,z):print(x,y,z)func(*{x:1,y:2,z:3}) # func(x,y,z)func(**{x:1,y:2,z:3}) # func(x1,y2,z3)# 错误func(**{x:1,y:2,}) # func(x1,y2)func(**{x:1,a:2,z:3}) # func(x1,a2,z3)# III: 形参与实参中都带**def func(x,y,**kwargs):print(x,y,kwargs)func(y222,x111,a333,b444)func(**{y:222,x:111,a:333,b:4444})# 混用*与***args必须在**kwargs之前def func(x,*args,**kwargs):print(args)print(kwargs)func(1,2,3,4,5,6,7,8,x1,y2,z3)def index(x,y,z):print(index ,x,y,z)def wrapper(*args,**kwargs): #args(1,) kwargs{z:3,y:2}index(*args,**kwargs)# index(*(1,),**{z:3,y:2})# index(1,z3,y2)wrapper(1,z3,y2) # 为wrapper传递的参数是给index用的3.4 函数的类型提示 ## : 后面是提示信息可以随意写 def regidter(name:不能写艾尼,age:至少18岁)print(name)print(age)def register(name:str,age:int,hobbies:tuple)-int: # 返回值类型为 intprint(name)print(age)print(hobbies)# 添加提示功能的同时再添加默认值 def register(name:str aini,age:int 18 ,hobbies:tuple)-int: # 返回值类型为 intprint(name)print(age)print(hobbies)4装饰器 4.1 装饰器的一步步实现 ## 装饰器装饰器定义一个函数该函数是用来为其他函数添加额外的工能 ## 装饰器就是不修改源代码以及调用方式的基础上增加新功能## 开放封闭原则# 开放指的是对拓展工能是开放的# 封闭 指的是对修改源代码是封闭的## 添加一个计算代码运行时间的工能修改了源代码 import time def index(name,age):start time.time()time.sleep(3)print(我叫%s,今年%s岁%(name,age))end time.time()print(end - start) index(age 18,name aini)# --------------------------------------------------------------------------def index1(name,age):print(我叫%s,今年%s岁 % (name, age))def wrapper():start time.time()index1(nameaini, age18)time.sleep(3)end time.time()print(end - start)wrapper() # 解决了修改原函数但是也改变了函数调用方式# -------------------------------------------------------------------------------------- def index1(name,age):print(我叫%s,今年%s岁 % (name, age))def wrapper(name,age):start time.time()index1(name, age)time.sleep(3)end time.time()print(end - start)wrapper(aini,18)# ----------------------------------------------------------------------------------- def index1(name,age):print(我叫%s,今年%s岁 % (name, age))def wrapper(*args,**kwargs):start time.time()index1(*args,**kwargs)time.sleep(3)end time.time()print(end - start)wrapper(aini,age 18)# ------------------------------------------------------------------------------------ def index1(name,age):print(我叫%s,今年%s岁 % (name, age))def outer():func indexdef wrapper(*args,**kwargs):start time.time()fun(*args,**kwargs)time.sleep(3)end time.time()print(end - start)return wrapperf outer() # f本质就是wrapper函数### 继续改进 def index1(name,age):print(我叫%s,今年%s岁 % (name, age))def outer(fun):def wrapper(*args,**kwargs):start time.time()fun(*args,**kwargs)time.sleep(3)end time.time()print(end - start)return wrapperf outer(index1) # f本质就是wrapper函数 f(nameaini,age22)# 继续改进偷梁换柱 def index1(name,age):print(我叫%s,今年%s岁 % (name, age))def outer(fun):def wrapper(*args,**kwargs):start time.time()fun(*args,**kwargs)time.sleep(3)end time.time()print(end - start)return wrapperindex1 outer(index1) # f本质就是wrapper函数 index1(nameaini,age22) # 新功能加上了也没有修改函数的调用方式# --------------------------------------------------------- 4.2 装饰器最终版本 # 被装饰函数有返回值 ########### 装饰器最终版本def index1(name,age):print(我叫%s,今年%s岁 % (name, age))return [name,age] # 有返回值def outer(fun):def wrapper(*args,**kwargs):start time.time()arg fun(*args,**kwargs)time.sleep(3)end time.time()print(end - start)return arg # 返回index1 的返回值return wrapperindex1 outer(index1) # f本质就是wrapper函数 res index1(nameaini,age22) # 新功能加上了也没有修改函数的调用方式把原函数的返回值也拿到了 # --------------------------------------------------------------------------------------------------4.3 装饰器语法糖 def outer(fun):def wrapper(*args,**kwargs):start time.time()arg fun(*args,**kwargs)time.sleep(3)end time.time()print(end - start)return arg # 返回index1 的返回值return wrapper outer def index1(name,age):print(我叫%s,今年%s岁 % (name, age))return [name,age] # 有返回值# ----------------------------------------------- # 与原函数伪装的更像一点from functools import wraps # 用于把原函数的属性特征赋值给另一个函数 def outer(fun):wraps(fun) # 可以把fun函数的所有属性特征加到wrapper函数身上def wrapper(*args,**kwargs):# wrapper.__name__ fun.__name__# wrapper.__doc__ fun.__doc__# 手动赋值麻烦start time.time()arg fun(*args,**kwargs)time.sleep(3)end time.time()print(end - start)return arg # 返回index1 的返回值return wrapperouter def index1(name,age):我是index1 # 通过help(index)函数来查看 文档信息可以通过index.__doc__ xxxxx 来给某个函数赋值文档信息# 通过 index__name__ 可以获得函数的名字也可以对其进行赋值print(我叫%s,今年%s岁 % (name, age))return [name,age] # 有返回值4.4 有参装饰器 4.4.1 不用语法糖 ### 不用语法糖 def auth(func,db_type):def wrapper(*args,**kwargs):name input(your name:).strip()pwd input(your password:).strip()if db_type file:print(基于文件验证)if name aini and pwd aini123:print(login success)res func(*args,**kwargs)return reselse:print(用户名或者密码错误!!)elif db_type mysql:print(基于mysql验证)elif db_type ldap:print(基于ldap验证)else:print(基于其他途径验证)return wrapperdef index(x,y):print(index-%s:%s%(x,y))index auth(index,file) index(aini,22)4.4.2 语法糖01 #--------------------------------------------------------------------- # 语法糖01 def auth(db_type file):def deco(func):def wrapper(*args,**kwargs):name input(your name:).strip()pwd input(your password:).strip()if db_type file:print(基于文件验证)if name aini and pwd aini123:print(login success)res func(*args,**kwargs)return reselse:print(用户名或者密码错误!!)elif db_type mysql:print(基于mysql验证)elif db_type ldap:print(基于ldap验证)else:print(基于其他途径验证)return wrapperreturn decodeco auth(db_type file) deco def index(x,y):print(index-%s:%s%(x,y)) index(aini,22)deco auth(db_type mysql) deco def index(x,y):print(index-%s:%s%(x,y)) index(aini,22)4.4.3 标准语法糖 # --------------------------------------------------------------------------------- # 标准语法糖模板 def auth(外界传递的参数):def deco(func):def wrapper(*args,**kwargs):自己扩展的功能 res func(*args,**kwargs)return resreturn wrapperreturn deco auth(外界传递的参数) def index(x,y):print(x,y)return(x,y)# 标准语法糖02例子 def auth(db_type file):def deco(func):def wrapper(*args,**kwargs):name input(your name:).strip()pwd input(your password:).strip()if db_type file:print(基于文件验证)if name aini and pwd aini123:print(login success)res func(*args,**kwargs)return reselse:print(用户名或者密码错误!!)elif db_type mysql:print(基于mysql验证)elif db_type ldap:print(基于ldap验证)else:print(基于其他途径验证)return wrapperreturn decoauth(db_type file) def index(x,y):print(index-%s:%s%(x,y)) index(aini,22)auth(db_type file) def index(x,y):print(index-%s:%s%(x,y)) index(aini,22) 5 迭代器 5.1 基础知识 1迭代器迭代取值的工具迭代是重复的过程每一次重复都是基于上次的结果而继续的单纯的重复不是迭代 # 可迭代对象 但凡内置有__iter__()方法的都称之为可迭代对象 # 字符串---列表---元祖---字典---集合---文件操作 都是可迭代对象# 调用可迭代对象下的__iter__方法将其转换为可迭代对象 d {a:1, b:2, c:3}d_iter d.__iter__() # 把字典d转换成了可迭代对象# d_iter.__next__() # 通过__next__()方法可以取值print(d_iter.__next__()) # a print(d_iter.__next__()) # b print(d_iter.__next__()) # c# 没值了以后就会报错 抛出异常StopIteration #----------------------------------------------- d {a:1, b:2, c:3} d_iter d.__iter__() while True:try:print(d_iter.__next__())except StopIteration:break # 对同一个迭代器对象取值取干净的情况下第二次取值的时候去不了没值只能造新的迭代器5.2 迭代器与for循环工作原理 #可迭代对象与迭代器详解#可迭代对象内置有__iter__() 方法对象# 可迭代对象.__iter__(): 得到可迭代对象#迭代器对象内置有__next__() 方法# 迭代器对象.__next__()得到迭代器的下一个值# 迭代器对象.__iter__(): 得到的值迭代器对象的本身调跟没调一个样----------- 为了保证for循环的工作# for循环工作原理d {a:1, b:2, c:3}d_iter d.__iter__()# 1d.__iter__() 方法得到一个跌倒器对象# 2,迭代器对象的__next__()方法拿到返回值将该返回值赋值给k# 3,循环往复步骤2直到抛出异常for循环会捕捉异常并结束循坏for k in d:print(k)# 可迭代器对象不一定是迭代器对象------------迭代器对象一定是可迭代对象# 字符串---列表---元祖---字典---集合只是可迭代对象不是迭代器对象、# 文件操作时迭代器对象也是可迭代对象6生成器本质就是迭代器 # 函数里包含yield,并且调用函数以后就能得到一个可迭代对象 def test():print(第一次)yield 1print(第二次)yield 2print(第三次)yield 3print(第四次)g test() print(g) # generator object test at 0x0000014C809A27A0 g_iter g.__iter__() res1 g_iter.__next__() # 第一次 print(res1) # 1 res2 g_iter.__next__() # 第二次 print(res2) # 2 res3 g_iter.__next__() # 第三次 print(res3) # 3 # 补充 len(s) ------- s.__len__() next(s) ------ s.__next__() iter(d) ------- d.__iter__()1yield 表达式 def person(name):print(%s吃东西啦%name)while True:x yield Noneprint(%s吃东西啦---%s%(name,x))g person(aini) # next(g) g.send(None) next(g) next(g) # send()方法可以给yield传值 # 不能在第一次运行时用g.send()来传值需要用g.send(None)或者next(g) 来初始化第二次开始可以用g.send(值)来传值 g.send(雪糕) # aini吃东西啦---雪糕 g.send(西瓜) # aini吃东西啦---西瓜2 三元表达式 x 10 y 20 res x if x y else y # 格式 条件成立时返回的值 if 条件 else 条件不成立时返回的值3列表生成式 l [aini_aaa,dilnur_aaa,donghua_aaa,egon] res [name for name in l if name.endswith(aaa)] print(res)# 语法 [结果 for 元素 in 可迭代对象 if 条件]l [aini_aaa,dilnur_aaa,donghua_aaa,egon] l [name.upper() for name in l] print(l)l [aini_aaa,dilnur_aaa,donghua_aaa,egon] l [name.replace(_aaa,) for name in l if name.endswith(_aaa)] print(l)4其他生成器——没有元祖生成式—— ### 字典生成器 keys [name,age,gender] res {key: None for key in keys} print(res) # {name: None, age: None, gender: None}items [(name,aini),(age,22),(gender,man)] res {k:v for k,v in items} print(res)## 集合生成器 keys [name,age,gender] set1 {key for key in keys}## 没有元祖生成器 g (i for i in range(10) if i % 4 0 ) ## 得到的是一个迭代器#### 统计文件字符个数 with open(aini.txt, modert, encoding utf-8) as f:res sum(len(line) for line in f)print(res)5二分法 l [-10,-6,-3,0,1,10,56,134,222,234,532,642,743,852,1431]def search_num(num,list):mid_index len(list) // 2if len(list) 0:print(没找到)return Falseif num list[mid_index]:list list[mid_index 1 :]search_num(num,list)elif num list[mid_index]:list list[:mid_index]search_num(num, list)else:print(找到了 , list[mid_index])search_num(743,l)6匿名函数与lambdaj ## 定义 res lambda x,y : xy ## 调用 (lambda x,y : xy)(10,20) # 第一种方法 res(10,20) ## 第二种方法##应用场景 salary {aini:20000,aili:50000,dilnur:15000,hahhaha:42568,fdafdaf:7854 }res max(salary ,key lambda x : salary[x]) print(res)7模块 ## 内置模块 ## 第三方模块 ## 自定义模块## 模块的四种形式 1 使用Python编写的py文件 2 已被编译为共享库或DLL的C或C扩展 3 把一系列模块组织到一起的文件夹文件夹下面有个__init__.py 该文件夹称为包 3 使用C编写并链接到Python解释器的内置模块import foo ## 首次导入模块会发生什么 1执行foo.py 2, 产生foo.py的命名空间 3在当前文件中产生的有一个名字foo,改名字指向2中产生的命名空间## 无论是调用还是修改与源模块为准与调用位置无关## 导入模块规范 1 Python内置模块 2Python第三方模块 3自定义模块## 起别名import foo as f## 自定义模块命名应该纯小写下划线## 可以在函数内导入模块7.1 写模块时测试 # 每个Python文件内置了__name__,指向Python文件名# 当foo.py 被运行时 __name__ __main__# 当foo.py 被当做模块导入时 __name__ ! __main__##### 测试时可以if判断,在foo.py文件中写以下判断 if __name__ __main__ :## 你的测试代码7.2 from xxx import xxx # from foo import x 发生什么事情 1 产生一个模块的命名空间 2 运行foo.py 产生将运行过程中产生的名字都丢到命名空间去 3 在当前命名空间拿到一个名字改名字指向模块命名空间7.3 从一个模块导入所有 #不太推荐使用 form foo import * # 被导入模块有个 __all__ [] __all__ [] # 存放导入模块里的所有变量和函数 默认放所有的变量和函数也可以手动修改foo.py__all__ [x,change]x 10def change():global xx 20a 20b 30run.py from foo import * ## * 导入的是foo.py里的 __all__ 列表里的变量和函数print(x)change()print(a) # 会报错因为foo.py 里的 __all__ 列表里没有a变量7.4 sys.path 模块搜索路径优先级 1 内存内置模块 2 从硬盘查找import sys # 值为一个列表存放了一系列的文件夹 # 其中第一个文件夹是当前执行所在的文件夹 # 第二个文件夹当不存在因为这不是解释器存放的是pycharm添加的 print(sys.path) # sys.path 里放的就是模块的存放路径查找顺序 [ E:\\Desktop\\python全栈\\模块, E:\\Desktop\\python全栈, D:\\软件\\pycharm\\PyCharm 2021.3.1\\plugins\\python\\helpers\\pycharm_display, D:\\软件\\python\\python310.zip, D:\\软件\\python\\DLLs, D:\\软件\\python\\lib, D:\\软件\\python, C:\\Users\\艾尼-aini\\AppData\\Roaming\\Python\\Python310\\site-packages, D:\\软件\\python\\lib\\site-packages, D:\\软件\\python\\lib\\site-packages\\win32, D:\\软件\\python\\lib\\site-packages\\win32\\lib, D:\\软件\\python\\lib\\site-packages\\Pythonwin, D:\\软件\\pycharm\\PyCharm 2021.3.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend ]7.5 sys.modules 查看内存中的模块 import sys print(sys.module) # 是一个字典存放导入的模块## 可以判断一个模块是否已经在内存中 print(foo in sys.module) 7.6 编写规范的模块 this module is used to ...... # 第一行文档注释 import sys # 导入需要用到的包 x 1 # 定义全局变量 class foo: # 定义类pass def test(): #定义函数passif __name__ __main__:pass8包包本身就是模块 ### 包就是一个包含__init__.py的文件夹包的本质是模块的一种形式包用来被当做模块导入### 导入包运行时运行__inti__.py文件里的代码### 环境变量是以执行文件为准备的所有的被导入的模块或者说后续的其他的sys.path都是参照执行文件的sys.path9, 软件开发的目录规范 ATM --------------------------------- # 项目跟目录binstart.py ---------------------# 启动程序config ------------------------- # 项目配置文件setting.pydb ------------------------------- # 数据库相关的文件夹db_handle.pylib ------------------------------ # 共享库包common.pycore ------------------------------# 核心代码逻辑src.pyapi -------------------------------# API有关的文件夹api.pylog -------------------------------# 记录日志的文件夹user.logREADME --------------------------- # 对软件的解释说明__file__ # 当前文件的绝对路径# 在start.py中运行 print(__file__) ---------------------- E:\Desktop\python全栈\ATM\bin\start.pyimport osimport sysBASE_DIR os.path.dirname(os.path.dirname(__file__)) ## 这样可以动态拿到根目录sys.path.append(BASE_DIR) # 把项目根目录加到环境变量了,这样可以很好的导包了## 如果把运行文件 start.py 直接放在跟文件的目录下就不需要处理环境变量了 10反射 10.1 什么是反射 ## 反射--------------- 程序运行过程当中动态的获取对象的信息。10.2 如何实现反射 # 通过dir:查看某一个对象可以.出来那些属性来 # 可以通过字符串反射到真正的属性上得到熟悉值## 四个内置函数的使用 hasattr() ## 判断属性是否存在 getattr() ## 得到属性 setattr() ## 设置属性 delattr() ## 删除属性hasattr(obj,name) ## 判断对象 obj 有没有 name 属性 getattr(obj,;name,None) ## 得到对象 obj 的 name 属性,如果没有返回 None setattr(obj,name,aini) ## 设置对象 obj 的 name 属性为 aini delattr(obj,name) ## 删除对象 obj 的 name 属性九面向对象编程 1类的定义 ## 类名驼峰命名 ## 类体中可以写任意Python代码类体代码在定义时就运行 ## __dic__ 可以查看类的命名空间{__module__: __main__, school: donghua, adress: shanghai, local: classmethod(function Student.local at 0x000001BCF418E9E0), say_hello: staticmethod(function Student.say_hello at 0x000001BCF418EA70), __init__: function Student.__init__ at 0x000001BCF418EB00, say_score: function Student.say_score at 0x000001BCF418EB90, __dict__: attribute __dict__ of Student objects, __weakref__: attribute __weakref__ of Student objects, __doc__: None} class Student:# 类属性# 可以被所有的实例对象所共享school donghuaadress shanghaistu_count 0 # 统计注册的实例个数# 类方法classmethoddef local(cls):print(cls.adress)# 静态方法# 可以调用类的属性和方法staticmethoddef say_hello(str):print(str)Student.local()# 通过构造函数__init__创建对象的属性def __init__(self,name,age,score):self.name nameself.age ageself.score scoreStudent.stu_count 1# 创建实例对象方法def say_score(self):print(f{self.name}的分数是{self.score})print(Student.say_score) ## function Student.say_score at 0x00000255F6DDEB90s1 Student(aini,22,80) ## 实例化 Student.say_score(s1) ## aini的分数是80 s1.say_score() ----- ## 本质是 Student.say_score(s1) ## 通过类名可以调用实例方法需要传递实例进去## 实例化发生的三件事情 1先产生一个空对象 2Python会自动调用 __init__方法 3返回初始化完的对象print(s1.__dict__) ------ ## ## {name: aini, age: 22, score: 80} 2封装 2.1 私有属性 ## 在属性或方法前加__前缀可以对外进行隐藏 ## 这种隐藏对外不对内因为__开头的属性会在类定义阶段检查语法时统一变形class Foo:__x 1def __test(self):print(from test)def f2(self):print(self.__x) # 1print(self.__test) ## bound method Foo.__test of __main__.Foo object at 0x000002063304B7F0## 隐藏属性的访问 ## Python不推荐此方法 print(Foo._Foo__x) ## 1 print(Foo._Foo__test) ## function Foo.__test at 0x000001C42976E320## 这种变形操作只在检查类语法的时候发生一次之后定义__定义的属性都不会变形Foo.__y 3 print(Foo.__y) 2.2 property使用 ## 第一种类型 ## 把函数像普通属性一样调用 class Person:def __init__(self,name):self.__name namepropertydef get_name(self):return self.__nameaini Person(aini) print(aini.get_name) ## aini## 第二种类型 class Person:def __init__(self,name):self.__name namedef get_name(self):return self.__namedef set_name(self,val):if type(val) is not str:print(必须传入str类型)returnself.__name val## 伪装成数据接口的属性name property(get_name,set_name)aini Person(aini) print(aini.name) ## aini aini.name norah print(aini.name) ## norah## 第三种方法 ## 起一个一样的函数名用不同功能的property装饰 class Person:def __init__(self,name):self.__name nameproperty ## name property(name)def name(self):return self.__namename.setter def name(self,val):if type(val) is not str:print(必须传入str类型)returnself.__name val name.deleter def name(self):print(不能删除)3继承 Python里支持多继承 python3里没有继承任何类的类都继承了Object类 Python2 里有经典类和新式类 经典类没有继承Object ------------------ 新式类继承了Object class Parent1:passclass Parent2:passclass Sub1(Parent1): ## 单继承passclass Sub2(Parent1,Parent2): ## 多继承passprint(Sub1.__bases__) ## (class __main__.Parent1,) print(Sub2.__bases__) ## (class __main__.Parent1, class __main__.Parent2)3.1 继承的实现 class OldBoyPeople:school OLDBOYdef __init__(self, name, age, sex):self.name nameself.age ageself.sex sexclass Student(OldBoyPeople):def choose_course(self):print(f学生 {self.name}正在选课)class Teacher(OldBoyPeople):def __init__(self,name,age,sex,salary,level):# 调父类的属性就行OldBoyPeople.__init__(self,name,age,sex)self.salary salaryself.level leveldef score(self):print(老师 %s 正在给学生打分 %self.name)t Teacher(agen,25,man,50000,一级) print(t.__dict__) ## {name: agen, age: 25, sex: man, salary: 50000, level: 一级}stu_1 Student(aini,22,man) print(stu_1.name,stu_1.age,stu_1.sex) ## aini 22 man print(stu_1.school) ## OLDBOY stu_1.choose_course() ## 学生 aini正在选课3.2 单继承背景下的属性查找 class Foo:def f1(self):print(Foo.f1)def f2(self):print(Foo.f2)self.f1() ## z这里如何调用自己的f1函数# 第一种方法 Foo.f1(self)# 第二种方法把f1函数改为次有属性 self.__f1() class Bar(Foo):def f1(self):print(Bar.f1)obj Bar() obj.f2() ## 到父类调f2,也会把自己传进来随意 self.f1() obj.f1() ## Foo.f2 ## Bar.f13.3 菱形问题 大多数面向对象语言都不支持多继承而在Python中一个子类是可以同时继承多个父类的这固然可以带来一个子类可以对多个不同父类加以重用的好处但也有可能引发著名的 Diamond problem菱形问题(或称钻石问题有时候也被称为“死亡钻石”)菱形其实就是对下面这种继承结构的形象比喻 class A(object):def test(self):print(from A)class B(A):def test(self):print(from B)class C(A):def test(self):print(from C)class D(B,C):passobj D() obj.test() # 结果为from B3.4 继承原理 ## python2 和 Python3 里算出来的mro不一样的## python到底是如何实现继承的呢 对于你定义的每一个类Python都会计算出一个方法解析顺序(MRO)列表该MRO列表就是一个简单的所有基类的线性顺序列表如下D.mro() ## [class __main__.D, class __main__.B, class __main__.C, class __main__.A, class object]B.mro() ## [class __main__.B, class __main__.A, class object]## 1.子类会先于父类被检查 ## 2.多个父类会根据它们在列表中的顺序被检查 ## 3.如果对下一个类存在两个合法的选择,选择第一个父类3.5 深度优先和广度优先 ## 参照下述代码多继承结构为非菱形结构此时会按照先找B这一条分支然后再找C这一条分支最后找D这一条分支的顺序直到找到我们想要的属性class E:def test(self):print(from E)class F:def test(self):print(from F)class B(E):def test(self):print(from B)class C(F):def test(self):print(from C)class D:def test(self):print(from D)class A(B, C, D):# def test(self):# print(from A)pass print(A.mro())[class __main__.A, class __main__.B, class __main__.E, class __main__.C, class __main__.F, class __main__.D, class object]## 如果继承关系为菱形结构那么经典类与新式类会有不同MRO分别对应属性的两种查找方式深度优先和广度优先 #################### 这是经典类深度优先查找class G: # 在python2中未继承object的类及其子类都是经典类def test(self):print(from G)class E(G):def test(self):print(from E)class F(G):def test(self):print(from F)class B(E):def test(self):print(from B)class C(F):def test(self):print(from C)class D(G):def test(self):print(from D)class A(B,C,D):# def test(self):# print(from A)passobj A() obj.test() # 如上图查找顺序为:obj-A-B-E-G-C-F-D-object # 可依次注释上述类中的方法test来进行验证,注意请在python2.x中进行测试#################### 这是新式类广度优先查找class G(object):def test(self):print(from G)class E(G):def test(self):print(from E)class F(G):def test(self):print(from F)class B(E):def test(self):print(from B)class C(F):def test(self):print(from C)class D(G):def test(self):print(from D)class A(B,C,D):# def test(self):# print(from A)passobj A() obj.test() # 如上图查找顺序为:obj-A-B-E-C-F-D-G-object # 可依次注释上述类中的方法test来进行验证3.6 Mixins机制解决多继承问题 ## Mixins机制核心多继承背景下尽可能地提升多继承的可读性 ## 让多继承满足人类的思维习惯## 民航飞机、直升飞机、轿车都是一个is-a交通工具前两者都有一个功能是飞行fly但是轿车没有所以如下所示我们把飞行功能放到交通工具这个父类中是不合理的class Vehicle: # 交通工具def fly(self):飞行功能相应的代码 print(I am flying)class CivilAircraft(Vehicle): # 民航飞机passclass Helicopter(Vehicle): # 直升飞机passclass Car(Vehicle): # 汽车并不会飞但按照上述继承关系汽车也能飞了pass ## ------------------------------------------------------------------------------------------------------------- ## 解决方法 class Vehicle: # 交通工具passclass FlyableMixin:def fly(self):飞行功能相应的代码 print(I am flying)class CivilAircraft(FlyableMixin, Vehicle): # 民航飞机passclass Helicopter(FlyableMixin, Vehicle): # 直升飞机passclass Car(Vehicle): # 汽车pass# ps: 采用某种规范如命名规范来解决具体的问题是python惯用的套路 ## ------------------------------------------------------------------------------------------------------------- ## 使用Minin class Vehicle: # 交通工具passclass FlyableMixin:def fly(self):飞行功能相应的代码 print(I am flying)class CivilAircraft(FlyableMixin, Vehicle): # 民航飞机passclass Helicopter(FlyableMixin, Vehicle): # 直升飞机passclass Car(Vehicle): # 汽车pass# ps: 采用某种规范如命名规范来解决具体的问题是python惯用的套路 ## --------------------------------------------------------------------------------------------------------3.7 使用minin注意事项 ## 使用Mixin类实现多重继承要非常小心## 首先它必须表示某一种功能而不是某个物品python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀 ## 其次它必须责任单一如果有多个功能那就写多个Mixin类一个类可以继承多个Mixin为了保证遵循继承的“is-a”原则只能继承一个 标识其归属含义的父类 ## 然后它不依赖于子类的实现 ## 最后子类即便没有继承这个Mixin类也照样可以工作就是缺少了某个功能。比如飞机照样可以载客就是不能飞了3.8 派生与方法重用 # 子类可以派生出自己新的属性在进行属性查找时子类中的属性名会优先于父类被查找例如每个老师还有职称这一属性我们就需要在Teacher类中定义该类自己的__init__覆盖父类的class OldBoyPeople:def __init__(self,name,age,sex):self.name nameself.age ageself.sex sexdef f1(self):print(%s say hello %self.name)class Teacher(OldBoyPeople):def __int__(self,name,age,sex,level,salary):## 第一种方法不依赖于继承## OldBoyPeople.__init__(self,name,age,sex)## 第二种方法严格依赖继承,只能用于新式类## Python2中需要传入类和本身## super(Teacher, self).__init__(name.age, sex)## Python3中什么也不需要传super().__init__(name,age,sex)## super 根据当前类的mro去访问父类里面去找self.level levelself.salary salary## super 严格遵守 mor 去找父类而不是我们肉眼看到的#A没有继承B class A:def test(self):super().test()class B:def test(self):print(from B)class C(A,B):passC.mro() # 在代码层面A并不是B的子类但从MRO列表来看属性查找时就是按照顺序C-A-B-objectB就相当于A的“父类”## [class __main__.C, class __main__.A, class __main__.B,class ‘object] objC() obj.test() # 属性查找的发起者是类C的对象obj所以中途发生的属性查找都是参照C.mro() ## from B3.9 组合 在一个类中以另外一个类的对象作为数据属性称为类的组合。组合与继承都是用来解决代码的重用性问题。不同的是继承是一种“是”的关系比如老师是人、学生是人当类之间有很多相同的之处应该使用继承而组合则是一种“有”的关系比如老师有生日老师有多门课程当类之间有显著不同并且较小的类是较大的类所需要的组件时应该使用组合如下示例 class Course:def __init__(self,name,period,price):self.namenameself.periodperiodself.pricepricedef tell_info(self):print(%s %s %s %(self.name,self.period,self.price))class Date:def __init__(self,year,mon,day):self.yearyearself.monmonself.daydaydef tell_birth(self):print(%s-%s-%s %(self.year,self.mon,self.day))class People:school清华大学def __init__(self,name,sex,age):self.namenameself.sexsexself.ageage#Teacher类基于继承来重用People的代码基于组合来重用Date类和Course类的代码 class Teacher(People): #老师是人def __init__(self,name,sex,age,title,year,mon,day):super().__init__(name,age,sex)self.birthDate(year,mon,day) #老师有生日self.courses[] #老师有课程可以在实例化后往该列表中添加Course类的对象def teach(self):print(%s is teaching %self.name)pythonCourse(python,3mons,3000.0) linuxCourse(linux,5mons,5000.0) teacher1Teacher(lili,female,28,博士生导师,1990,3,23)# teacher1有两门课程 teacher1.courses.append(python) teacher1.courses.append(linux)# 重用Date类的功能 teacher1.birth.tell_birth()# 重用Course类的功能 for obj in teacher1.courses: obj.tell_info()4多态 4.1 多态的一种方式 ## 多态同一种事务的多种状态 ## 多态性指的是可以在不考虑对象具体类型的情况下而直接使用对象class Animal:def say(self):print(动物基本的发声)class Person(Animal):def say(self):super().say()print(啊啊啊啊啊啊啊啊)class Dog(Animal):def say(self):super().say()print(汪汪汪)class Pig(Animal):def say(self):super().say()print(哼哼哼)person Person() dog Dog() pig Pig()## 定义统一的接口实现多态 def animal_say(animal):animal.say()animal_say(person) animal_say(dog) animal_say(pig)## 多态的例子 def my_len(val):return val.__len__()my_len(aini) my_len([1,12,3,4,5,hhh]) my_len({name:aini,age:22})4.2 Python推崇的多态 ## 鸭子类型不用继承class Cpu:def read(self):print(cpu read)def write(self):print(cpu write)class Meu:def read(self):print(meu read)def write(self):print(meu write) class Txt:def read(self):print(txt read)def write(self):print(txt write) cpu Cpu() meu Meu() txt Txt()5classmethod import settingclass Mysql:def __init__(self,ip,port):self.ip ipself.port portdef func(self):print(%s %s %(self.ip,self.port))classmethod ## 提供一种初始化对象的方法def from_conf(cls):return cls(setting.IP,setting.PORT) ## 返回的就是一个实例化的对象不需要我自己一个个创建obj Mysql.from_conf() print(obj.__dict__) ## {ip: 127.0.0.1, port: 3306} 6staticmethod class Mysql:def __init__(self,ip,port):self.ip ipself.port portstaticmethoddef create_id():import uuidreturn uuid.uuid4()obj Mysql(127.0.0.1,3306)## 像普通函数一样调用就可以不会自动传参需要人工传参 print(Mysql.create_id()) ## 57c42038-b169-4f25-9057-d83795d097cc print(obj.create_id()) ## 485372bc-efca-4da8-a446-b11c7bbf3c9b7内置方法 7.1 什么是内置方法 ## 定义在类内部以__开头和__结尾的方法称之为内置方法## 会在满足某种情况下回自动触发执行 ## 为什么用 为了定制化我们的类或者对象7.2 如何使用内置方法 # __str__ # __del__class People:def __init__(self,name,age):self.name nameself.age agedef say(self):print(%s:%s%(self.name,self.age))obj People(aini,22) print(obj) ## __main__.People object at 0x00000276F6B8B730## ----------------------------------------------------------------------## __str__ 来完成定制化操作 class People:def __init__(self,name,age):self.name nameself.age agedef say(self):print(%s:%s%(self.name,self.age))def __str__(self):print(这是xxxxx对象) ## 值起到提示作用return %s:%s % (self.name, self.age) ## 必须要有return而且返回字符串obj People(aini,22) print(obj) ## aini:22## ---------------------------------------------------------------------------------------- # __del__ :在清理对象时触发会先执行该方法class People:def __init__(self,name,age):self.name nameself.age agedef say(self):print(%s:%s%(self.name,self.age))def __del__(self):print(running......)obj People(aini,22) print() ## 程序运行完了要清理对象 running...... ## 清理对象时云运行 ## --------------------------------------------------------------------------------------- class People:def __init__(self,name,age):self.name nameself.age agedef say(self):print(%s:%s%(self.name,self.age))def __del__(self):print(running......)obj People(aini,22) del obj print() running...... ## 清理对象时云运行 ## 程序运行完了 ## --------------------------------------------------------------------------------------------- ##### 对象本身占得是应用程序的内存空间所以没有多大用处##### 但是如果对象某个属性x 比如 obj.x 占得是操作系统内存空间对象运行完了以后Python回收的是程序中的内存空间 ### 操作系统不会被回收class People:def __init__(self,name,age):self.name nameself.age ageself.x open(aini.txt,w,encodingutf-8)def say(self):print(%s:%s%(self.name,self.age))def __del__(self):print(running......)## 发起系统调用告诉系统回收操作系统资源,比如如下self.x.close()obj People(aini,22) print()8,元类介绍 ## 元类---------------- 用来实例化产生类的那个类 ## 关系 元类---------------实例化 ---------------类---------------------- 对象class People:def __init__(self, name, age):self.name nameself.age agedef say(self):print(%s:%s % (self.name, self.age))## 查看内置元类 print(type(People)) # class type print(type(int)) # class type## class关键字定义的类和内置的类都是由type产生的8.1 class关键字创建类的步骤 # 类三大特征类名 class_name || 类的基类 clas_bases (Object) || 类体本身 -- 一对字符串执行类体代码拿到运行空间class People:def __init__(self, name, age):self.name nameself.age agedef say(self):print(%s:%s % (self.name, self.age)) class_body def __init__(self, name, age):self.name nameself.age agedef say(self):print(%s:%s % (self.name, self.age))class_dic {} # 定义类的命名空间# 类名 class_name People # 类的基类 clas_bases (object,) # 执行类体代码拿到运行空间exec(class_body,{},class_dic) # 空字典指的是全局命名空间 class_dic是类的命名空间 ## 运行拿到exec以后可以拿到类体代码的运行空间放在class_dic 里print(class_dic) ## {__init__: function __init__ at 0x0000016A0BDC9900, say: function say at 0x0000016A0BE2E320}# 调用元类People type(class_name,class_basis,class_dic)print(People) ## class __main__.People8.2 定制元类控制类的产生 ## 定制元类 class Mymeta(type): ## 只有继承了type类的类才可以称之为元## 运行__init__方法的时候空对象和这些class_name,class_basis,class_dic一共四个参数一起传进来了## 所以需要四个参数接受## 重写了造对象的方法不写__new__方法的话自动创建空对象## 参数为 类本身调用类时所传入的参数def __new__(xls,*args,**kwargs):##第一种方法 ---------------- 调父类的__new__()方法造对象 return super().__new__(cls,*args,**kwargs)## 第二种方法 ----------------- 调用元类的内置方法return type.__new__(cls,*args,**kwargs)## 可以控制类的产生def __init__(self,class_name,class_basis,class_dic):## 类的首字母大写if not x.capitalize():raise NameError(类名的首字母必须大写啊) class People(object ,metaclass Mymeta): # class产生类的话会自动继承object# 底层的话需要明确之指定继承object类def __init__(self, name, age):self.name nameself.age agedef say(self):print(%s:%s % (self.name, self.age))class_body def __init__(self, name, age):self.name nameself.age agedef say(self):print(%s:%s % (self.name, self.age))class_dic {} # 定义类的命名空间# 类名 class_name People # 类的基类 clas_bases (object,) # 执行类体代码拿到运行空间exec(class_body,{},class_dic) # 调用元类People Mymeta(class_name,class_basis,class_dic) ## 调用 type.__call__(方法)## 将参数先传给 __new__方法造空对象## 然后参数传递给 __init__方法初始化类## 调用Mymeta发生的事儿,调用Mymeta 就是type.__call__()# 先造一个空对象 People 调用__new__方法# 调用Mymeta这个类的__inti__方法完成初始化对象的操作(这个过程中可以控制类的产生)# 返回初始化好的对象## 总结# 控制造空对象过程 重写 __new__()方法# 控制类的产生 重写 __init__()方法8.3 new(方法) ## 具体看 8.2 控制造空对象的过程 ## __new__() 放下造对象时早于 __init__() 方法运行 8.4 call方法 ## 8.1 中 # 调用元类时People Mymeta(class_name,class_basis,class_dic) ## 本质就是调用 type的__call__()方法class Foo:def __init__(self,x,y):self.x xself.y ydef __call__(self,name,age):print(name,age)print(我运行了obj下面的__call__方法)obj Foo(111,222) obj(aini,22) # aini 22 # 我运行了obj下面的__call__方法## 对象的类里定义__call__方法的话实例对象可以调用### ------------------------------------------------------------------- ## 如果想要控制类的调用 那就重写__call__()方法 ## 定制元类 class Mymeta(type): def __call__(self,*args,**kwargs):## Mymeta.__call__函数内会调用People.__new__()方法people_obj self__new__(self)## 可以对类进行定制化obj.__dict__[xxxx] 所有的obj产生的类我新加了一个属性## Mymeta.__call__函数内调用People.__inti__()方法self.__init__(people_obj,*args,**kwargs)## 重写了造对象的方法不写__new__方法的话自动创建空对象## 参数为 类本身调用类时所传入的参数def __new__(xls,*args,**kwargs):##第一种方法 ---------------- 调父类的__new__()方法造对象 return super().__new__(cls,*args,**kwargs)## 第二种方法 ----------------- 调用元类的内置方法return type.__new__(cls,*args,**kwargs)## 可以控制类的产生def __init__(self,class_name,class_basis,class_dic):## 类的首字母大写if not x.capitalize():raise NameError(类名的首字母必须大写啊) class People(object ,metaclass Mymeta): # class产生类的话会自动继承object# 底层的话需要明确之指定继承object类def __init__(self, name, age):self.name nameself.age agedef __new__(cls,*args,**kwargs):# 造对象return object.__new__(cls,*args,**kwargs)def say(self):print(%s:%s % (self.name, self.age))## ------------------------------------------------------------ class_body def __init__(self, name, age):self.name nameself.age agedef say(self):print(%s:%s % (self.name, self.age))class_dic {} # 定义类的命名空间 class_name People clas_bases (object,) exec(class_body,{},class_dic) People Mymeta(class_name,class_basis,class_dic) ## 调用 type.__call__(方法) ## 调用Mymeta发生的事儿,调用Mymeta 就是type.__call__()# 先造一个空对象 People 调用__new__方法# 调用Mymeta这个类的__inti__方法完成初始化对象的操作(这个过程中可以控制类的产生)# 返回初始化好的对象obj People(aini,22)# 实例化People发生的三件事# 调用Mymeta.__call__(self,*args,**kwargs)方法# Mymeta.__call__函数内会调用People.__new__()方法# Mymeta.__call__函数内调用People.__inti__()方法 8.5 属性查找的原则 ## 属性查找的原则对象 ---- 类 -----------父类 ## 切记父类不是元类不会去从元类里找十网络编程 10.1 cs架构与bs架构 ## cs架构## Client ----------------------------------------- Server# 客服端软件 服务端软件# 操作系统 操作系统# 计算机硬件 计算机硬件## bs架构## Brower ----------------------------------------------- Server10.2 网络通信 ## 网络存在的意义就是跨地域数据传输---------》 称之为通信 ## 网络 物理链接介质 互联网通信协议10.3 OSI七层协议 ## 五层协议# 应用层# 传输层# 网络层# 数据链路层# 物理层## 协议规定数据的组织格式 格式头部 数据部分10.4 网络协议 ## 计算机1 ----------------------------计算机2、 ## 应用层 ------------------------------应用层 ## 传输层 ----------------------------- 传输层 ## 网络层 ----------------------------- 网络层 ------ (源IP地址目标IP地址) 数据1 ## 数据链路层 --------------------------数据链路层 ---(源mac地址目标mac地址) 数据2((源IP地址目标IP地址) 数据1) ## 物理层1 ------------二层交互机------------物理层2# 二层交互机将从 物理层1接受的 二进制数据接收到以后可以解析到数据链路层(源mac地址目标mac地址) 数据2 再转换成二进制 发给物理层210.4.1 物理层 ## 物理层由来上面提到孤立的计算机之间要想一起玩就必须接入internet言外之意就是计算机之间必须完成组网## 物理层功能主要是基于电器特性发送高低电压(电信号)高电压对应数字1低电压对应数字0## 物理层负责发送电信号## 单纯的电信号毫无意义必须对其进行分组 10.4.2 数据链路层帧 ## 数据链路层 Ethernet以太网协议## 规定一一组数据称之为一个数据帧## 规定二数据帧分成两部分 头 数据两部分## 头: 源地址与目标地址该地址是Mac地址## 数据包含的是网络层整体的内容## 规定三但凡介入互联网的主机必须有网卡每一块网卡在出场时标志好一个全世界独一无二的地址该地址称之为----- mac地址## mac地址(了解) head中包含的源和目标地址由来ethernet规定接入internet的设备都必须具备网卡发送端和接收端的地址便是指网卡的地址即mac地址mac地址每块网卡出厂时都被烧制上一个世界唯一的mac地址长度为48位2进制通常由12位16进制数表示前六位是厂商编号后六位是流水线号 ## head包含(固定18个字节) ----------------- 源地址与目标地址该地址是Mac地址 发送者源地址6个字节接收者目标地址6个字节数据类型6个字节data包含(最短46字节最长1500字节)## 数据包的具体内容 ## head长度data长度最短64字节最长1518字节超过最大限制就分片发送## 注意计算机通信基本靠吼既以太网协议的工作方式是广播10.4.3 网络层包 ## 网络层IP协议## 划分IP协议## 每一个广播域但凡要接通外部一定要有一个网关帮内部的计算机转发包到公网网关与外界通信走的是路由协议## 规定1一组数据称之为一个数据包 ## 规定2 数据帧分成两个部分---- 头 数据## 头包含源地址与目标地址该地址是IP地址## 数据包含传输层整体的内容 3-1 ip协议 # IP协议1,规定网络地址的协议叫ip协议它定义的地址称之为ip地址广泛采用的v4版本即ipv4它规定网络地址由32位2进制表示2,范围0.0.0.0-255.255.255.2553,一个ip地址通常写成四段十进制数例172.16.10.1## ip地址分成两部分# 网络部分标识子网# 主机部分标识主机# 注意单纯的ip地址段只是标识了ip地址的种类从网络部分或主机部分都无法辨识一个ip所处的子网# 例172.16.10.1与172.16.10.2并不能确定二者处于同一子网#ipv4地址# 8bit.8bit.8bit.8bit0.0.0.0 ~ 255.255.255.255## ipv6## 目前在逐渐普及3-2 子网掩码 ## 子网掩码# 8bit.8bit.8bit.8bit## 一个合法的IPv4地址组成部分ip地址/子网掩码 --------------------- 区分广播域## 172.16.10.1/255.255.255.0## ## 172.16.10.1/24 ----------------- 表示24位二进制数 知道”子网掩码”我们就能判断任意两个IP地址是否处在同一个子网络。方法是将两个IP地址与子网掩码分别进行AND运算两个数位都 为1运算结果为1否则为0然后比较结果是否相同如果是的话就表明它们在同一个子网络中否则就不是。 ## 同为1结果为1有0结果为0## 计算机1的## IP地址172.16.10.1 10101100.00010000.00001010.000000001## 子网掩码地址255255.255.255.0: 11111111.11111111.11111111.00000000## 网络地址10110101100.00010000.00001010.000000001-172.16.10.0## 计算机2的## IP地址172.16.10.2 10101100.00010000.00001010.000000010## 子网掩码地址255255.255.255.0: 11111111.11111111.11111111.00000000## 网络地址10101100.00010000.00001010.000000001-172.16.10.0## 两个计算机网络地址一样所以属于一个局域网内3-3 APR协议 ## 事先知道的是对方的IP地址 ## 但是计算机的底层通信是基于ethernet以太网协议的mac地址通信##API协议 ----------- 能够将IP地址解析成mac地址## 两台计算机再同一个局域网内直接发包就可以 计算计1 直接 计算机2 ARP 自己的IP对方的IP #-1 计算二者的网络地址如果一样那ARP协议拿到计算机2的mac地址就可以 #-2 发送广播包## 两台计算机不在同一个局域网内 计算计1 网关 计算机2 ARP 自己的IP对方的IP # 计算二者的网络地址如果不一样应该拿到网关的mac地址## FF:FF:FF:FF:FF:FF ----------------------意思就是要对方的Mac地址 ##-1 如果在同一个局域网内那就拿到了对方的Mac地址 ##-2 发送广播包 ![image-20230704153508853](htt lucky ↩︎ a ↩︎
文章转载自:
http://www.morning.tbcfj.cn.gov.cn.tbcfj.cn
http://www.morning.zhiheliuxue.com.gov.cn.zhiheliuxue.com
http://www.morning.rxwnc.cn.gov.cn.rxwnc.cn
http://www.morning.pjtnk.cn.gov.cn.pjtnk.cn
http://www.morning.rkjb.cn.gov.cn.rkjb.cn
http://www.morning.ctxt.cn.gov.cn.ctxt.cn
http://www.morning.nmkfy.cn.gov.cn.nmkfy.cn
http://www.morning.lflsq.cn.gov.cn.lflsq.cn
http://www.morning.kxgn.cn.gov.cn.kxgn.cn
http://www.morning.xnkh.cn.gov.cn.xnkh.cn
http://www.morning.nndbz.cn.gov.cn.nndbz.cn
http://www.morning.zjcmr.cn.gov.cn.zjcmr.cn
http://www.morning.dqwykj.com.gov.cn.dqwykj.com
http://www.morning.cgdyx.cn.gov.cn.cgdyx.cn
http://www.morning.brrxz.cn.gov.cn.brrxz.cn
http://www.morning.qbmjf.cn.gov.cn.qbmjf.cn
http://www.morning.tkztx.cn.gov.cn.tkztx.cn
http://www.morning.zlgr.cn.gov.cn.zlgr.cn
http://www.morning.jpzcq.cn.gov.cn.jpzcq.cn
http://www.morning.sh-wj.com.cn.gov.cn.sh-wj.com.cn
http://www.morning.mfbzr.cn.gov.cn.mfbzr.cn
http://www.morning.nktgj.cn.gov.cn.nktgj.cn
http://www.morning.srbbh.cn.gov.cn.srbbh.cn
http://www.morning.ysjjr.cn.gov.cn.ysjjr.cn
http://www.morning.hrjrt.cn.gov.cn.hrjrt.cn
http://www.morning.mlhfr.cn.gov.cn.mlhfr.cn
http://www.morning.skrxp.cn.gov.cn.skrxp.cn
http://www.morning.mcjyair.com.gov.cn.mcjyair.com
http://www.morning.tnktt.cn.gov.cn.tnktt.cn
http://www.morning.wbhzr.cn.gov.cn.wbhzr.cn
http://www.morning.addai.cn.gov.cn.addai.cn
http://www.morning.rwlns.cn.gov.cn.rwlns.cn
http://www.morning.qrzwj.cn.gov.cn.qrzwj.cn
http://www.morning.rahllp.com.gov.cn.rahllp.com
http://www.morning.ztqj.cn.gov.cn.ztqj.cn
http://www.morning.mlpch.cn.gov.cn.mlpch.cn
http://www.morning.rfwkn.cn.gov.cn.rfwkn.cn
http://www.morning.2d1bl5.cn.gov.cn.2d1bl5.cn
http://www.morning.fnrkh.cn.gov.cn.fnrkh.cn
http://www.morning.tqbyw.cn.gov.cn.tqbyw.cn
http://www.morning.kfmnf.cn.gov.cn.kfmnf.cn
http://www.morning.qyfqx.cn.gov.cn.qyfqx.cn
http://www.morning.tnbas.com.gov.cn.tnbas.com
http://www.morning.syxmx.cn.gov.cn.syxmx.cn
http://www.morning.tzzkm.cn.gov.cn.tzzkm.cn
http://www.morning.tntgc.cn.gov.cn.tntgc.cn
http://www.morning.qtyfb.cn.gov.cn.qtyfb.cn
http://www.morning.xcdph.cn.gov.cn.xcdph.cn
http://www.morning.mytmx.cn.gov.cn.mytmx.cn
http://www.morning.ymyhg.cn.gov.cn.ymyhg.cn
http://www.morning.rttp.cn.gov.cn.rttp.cn
http://www.morning.fhsgw.cn.gov.cn.fhsgw.cn
http://www.morning.yuanshenglan.com.gov.cn.yuanshenglan.com
http://www.morning.qhmql.cn.gov.cn.qhmql.cn
http://www.morning.ykrck.cn.gov.cn.ykrck.cn
http://www.morning.mcjp.cn.gov.cn.mcjp.cn
http://www.morning.hsksm.cn.gov.cn.hsksm.cn
http://www.morning.nfccq.cn.gov.cn.nfccq.cn
http://www.morning.fqtzn.cn.gov.cn.fqtzn.cn
http://www.morning.wztlr.cn.gov.cn.wztlr.cn
http://www.morning.kljhr.cn.gov.cn.kljhr.cn
http://www.morning.mnkhk.cn.gov.cn.mnkhk.cn
http://www.morning.dodoking.cn.gov.cn.dodoking.cn
http://www.morning.zrqs.cn.gov.cn.zrqs.cn
http://www.morning.qbpqw.cn.gov.cn.qbpqw.cn
http://www.morning.yjmns.cn.gov.cn.yjmns.cn
http://www.morning.jgzmr.cn.gov.cn.jgzmr.cn
http://www.morning.crdtx.cn.gov.cn.crdtx.cn
http://www.morning.mdfxn.cn.gov.cn.mdfxn.cn
http://www.morning.nylbb.cn.gov.cn.nylbb.cn
http://www.morning.zmlnp.cn.gov.cn.zmlnp.cn
http://www.morning.kwcnf.cn.gov.cn.kwcnf.cn
http://www.morning.bpmdg.cn.gov.cn.bpmdg.cn
http://www.morning.fgtls.cn.gov.cn.fgtls.cn
http://www.morning.ygkk.cn.gov.cn.ygkk.cn
http://www.morning.wyctq.cn.gov.cn.wyctq.cn
http://www.morning.qjrjs.cn.gov.cn.qjrjs.cn
http://www.morning.bpmnq.cn.gov.cn.bpmnq.cn
http://www.morning.qcslh.cn.gov.cn.qcslh.cn
http://www.morning.xtkw.cn.gov.cn.xtkw.cn
http://www.tj-hxxt.cn/news/273732.html

相关文章:

  • 怎样让网站做301处理软件开发工程师怎么考
  • 地方网站开发网站开发基础知识简述
  • 做网站密云如何查网站的外链
  • 淘宝联盟的网站管理怎么做网站建设都 包括哪些
  • 高德地图搜索不到国外学seo推广
  • 旅游景点网站建设如何建设社区网站
  • 视频网站app怎么做的东莞网站设
  • dede淘宝客网站网站搭建后台
  • 兑换网站建设北湖区网站建设哪个好
  • 制作网站费用明细wordpress后台账号密码
  • 怎让做淘宝网站wordpress按钮编辑器
  • 做商城网站需要备案什么域名福田网站建设设计公司哪家好
  • 腾讯云如何建设网站首页家乡网站建设策划案
  • 网站排名优化首页网站建设优化服务咨询
  • 医疗机构 网站备案wordpress 站内搜索 慢
  • 做印刷网站公司做文案策划有些网站可看
  • 如何给网站做301重定向河北邢台有几个区县
  • 做网站设计前景怎么样视频模板套用免费
  • 人才网官方网站大连网站推广爱得科技
  • 镇网站建设管理工作总结做编程网站有哪些
  • 优秀网站模板长治公司网站建设
  • 网站海外推广外包对seo的理解
  • 前端网站设计电商的推广主要是做什么的
  • 网站文章内容互联网保险理赔到底有多难
  • 中小型企业电子商务网站建设什么网站可以做数据调查
  • 建立一个小型网站多少钱wordpress怎么实现注册功能
  • 做外贸有哪些网站平台网站做国际化
  • 2 如何写一份详细的网站开发方案asp
  • 那些企业需要做网站中国机械设计网
  • 响应式网站 框架河南省建设厅网站师林峰