常见模块解析
文章目录
1. math库
数学函数
函数 | 返回值 ( 描述 ) |
---|---|
abs(x) | 返回数字的绝对值,如abs(-10) 返回 10 |
ceil(x) | 返回数字的上入整数,如math.ceil(4.1) 返回 5 |
cmp(x, y) | 如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1。 **Python 3 已废弃,使用 (x>y)-(x。 |
exp(x) | 返回e的x次幂(ex),如math.exp(1) 返回2.718281828459045 |
fabs(x) | 返回数字的绝对值,如math.fabs(-10) 返回10.0 |
floor(x) | 返回数字的下舍整数,如math.floor(4.9)返回 4 |
log(x) | 如math.log(math.e)返回1.0,math.log(100,10)返回2.0 |
log10(x) | 返回以10为基数的x的对数,如math.log10(100)返回 2.0 |
max(x1, x2,…) | 返回给定参数的最大值,参数可以为序列。 |
min(x1, x2,…) | 返回给定参数的最小值,参数可以为序列。 |
modf(x) | 返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示。 |
pow(x, y) | x**y 运算后的值。 |
round(x [,n]) | 返回浮点数 x 的四舍五入值,如给出 n 值,则代表舍入到小数点后的位数。其实准确的说是保留值将保留到离上一位更近的一端。 |
sqrt(x) | 返回数字x的平方根。 |
三角函数
Python的math库包括以下三角函数:(比如:math.sin(math.pi/2))
函数 | 描述 |
---|---|
acos(x) | 返回x的反余弦弧度值。 |
asin(x) | 返回x的反正弦弧度值。 |
atan(x) | 返回x的反正切弧度值。 |
atan2(y, x) | 返回给定的 X 及 Y 坐标值的反正切值。 |
cos(x) | 返回x的弧度的余弦值。 |
hypot(x, y) | 返回欧几里德范数 sqrt(xx + yy)。 |
sin(x) | 返回的x弧度的正弦值。 |
tan(x) | 返回x弧度的正切值。 |
degrees(x) | 将弧度转换为角度,如degrees(math.pi/2) , 返回90.0 |
radians(x) | 将角度转换为弧度 |
数学常量
常量 | 描述 |
---|---|
math.pi | 数学常量 pi(圆周率,一般以π来表示) |
math.e | 数学常量 e,e即自然常数(自然常数)。 |
2. random库
Python的random库包含以下常用随机数函数:
import random
# 生成一个 [0, 1) 范围内的随机小数
print(random.random())
# 生成一个 [1, 10] 范围内的随机整数
print(random.randint(1, 10))
# 生成一个 [0, 1] 范围内的随机小数
print(random.uniform(0, 1))
# 从序列中随机选择一个元素
seq = ['apple', 'banana', 'orange']
print(random.choice(seq))
# 将序列中的元素随机打乱(shuffle洗牌)
seq = [1, 2, 3, 4, 5]
random.shuffle(seq)
print(seq)
3. re 模块
1. 常用正则表达式
模式 | 描述 |
---|---|
\w | 匹配字母数字及下划线 |
\W | 匹配非字母数字下划线 |
\s | 匹配任意空白字符,等价于[\t,\n,\r,\f] |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于[0-9] |
\D | 匹配任意非数字 |
\A | 匹配以xx字符串开始 |
\Z | 匹配xx字符串结束,如果是存在换行,只匹配到换行前的结束字符串 |
\z | 匹配xx字符串结束 |
\G | 匹配最后匹配完成的位置 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾 |
. | 匹配任意字符, 除了换行符, 当 re.DOTALL 标记被指定时, 则可以匹配包括换行符的任意字符 |
[…] | 用来表示一组字符, 单独列出:[amk] 匹配 ‘a’,‘m’ 或 ‘k’ |
[^…] | 不在 [ ] 中的字符:[^abc] 匹配除了a, b, c之外的字符 |
* | 匹配0个或多个的表达式 |
+ | 匹配1个或多个的表达式 |
? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
{n} | 精确匹配n个前面表达式。 |
{n,m} | 匹配n到m次由前面的正则表达式定义的片段,贪婪方式 |
alb | 匹配a或b |
() | 匹配括号内的表达式,也表示一个组 |
注意:[ ]
所有的特殊字符在字符集中都失去其原有的特殊含义,在字符集中如果要使用]
、-
或^
,可以在前面加上反斜杠,或把]
、-
放在第一个字符,把^
放在非第一个字符
2. 常用函数
函数 | 说明 |
---|---|
re.match( ) | 从字符串的起始位置匹配, 匹配成功, 返回一个匹配的对象, 否则返回None |
re.search( ) | 扫描整个字符串并返回第一个成功的匹配 |
re.findall( ) | 在字符串中找到正则表达式所匹配的所有子串, 并返回一个列表, 如果没有找到匹配的, 则返回空列表 |
re.split( ) | 将一个字符串按照正则表达式匹配结果进行分割, 返回列表类型 |
re.finditer( ) | 在字符串中找到正则表达式所匹配的所有子串, 并把它们作为一个迭代器返回 |
re.sub( ) | 把字符串中所有匹配正则表达式的地方替换成新的字符串 |
re.complie( ) | 将正则表达式传入, 返回一个匹配对象, 一般与其他方法组合使用 |
3. 正则匹配使用示例
print("hello".replace("llo","ooo")) # heooo
print("hello".find("abcd")) # -1 (找不到返回 -1)
print("hello".find("he")) # 0
import re
print(re.findall("\w","ab* 12$ _")) # ['a', 'b', '1', '2', '_']
print(re.findall("\s","ab* 12$ _ ")) # [' ', ' ', ' ']
print(re.findall("\Aab","ab* 12$ _")) # ['ab']
print(re.findall("\Aaa","ab* 12$ _")) # [] 没匹配到为空
print(re.findall("_\Z","ab* 12$ _")) # ['_']
print(re.findall("0\Z","ab* 12$ _")) # [] 没匹配到为空
print(re.findall("\t","ab* 12$ \t_")) # ['\t']
#"\s" 可以匹配"\t"和"\n"
print(re.findall("^ab","ab* 12$ _")) # ['ab']
print(re.findall("_$","ab* 12$ _\n")) # ['_']
重复匹配
#.匹配任意一个字符
import re
print(re.findall("a.b","a\tb")) # ['a\tb']
print(re.findall("a.b","a\nb")) # [] (换行符匹配不到,匹配为空)
print(re.findall("a.b","a b a*b abb a_b")) # ['a b', 'a*b', 'abb', 'a_b']
print(re.findall("a.b","a\nb",re.S)) # ['a\nb'] (加入参数, 包含换行)
print(re.findall("a.b","a\nb",re.DOTALL)) # ['a\nb'] (同上效果一样)
#* 匹配前面那个字符0个或者n个
print(re.findall("a*","aaaa aa"))# ['aaaa', '', 'aa', ''] (零个或多个a)
print(re.findall("ab*","abab aa"))# ['ab', 'ab', 'a', 'a'] (一个a零个或多个b)
print(re.findall("a*b","ababaaaba aa")) # ['ab', 'ab', 'aaab'] (零个或多个a一个b)
print(re.findall("ab*","bbbbbbbb")) # [] (没有匹配到一个a零个或多个b)
#? 匹配前面那个字符0个或者1个
print(re.findall("ab?","a")) # ['a'],匹配1个a,0个b
print(re.findall("ab?","abbb")) # ['ab']
#{n,m} 匹配n~m个
print(re.findall("a{2}","aaaa")) # ['aa', 'aa']
print(re.findall("ab{2,6}","abbb")) # ['abbb'] (一个a,2~6个b)
print(re.findall("ab{1,}","abbb")) # ['abbb'] (相当于 ab+)
print(re.findall("ab{0,}","abbb")) # ['abbb'] (相当于 ab*)
#[ ]逐个匹配
print(re.findall("a[*1_c-]b","a*ba1b a_baaba-b")) # ['a*b', 'a1b', 'a_b', 'a-b']
print(re.findall("a[^a-zA-Z0-9]b","a*banb aPbaa7b")) # ['a*b'] (非a~z,A~Z,0~9)
#( )分组
print(re.findall('ab+','ababab123')) # ['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) # ['ab'],匹配到末尾的 ab123 中的 ab
print(re.findall('(?:ab)+123','ababab123'))
#['ababab123'], findall的结果不是匹配的全部内容,而是组内的内容, ?: 可以让结果为匹配的全部内容,详见非捕获匹配
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">点击</a>'))# ['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">点击</a><a href="http://www.aiqiyi.com">点击2</a>'))
# ['href="http://www.baidu.com"', 'href="http://www.aiqiyi.com"']
print(re.findall("a\.b","a1b a.b")) # ['a.b']
print(re.findall("shawn|song","shawn is man song is shawn")) # ['shawn', 'song', 'shawn']
print(re.findall("A(?:abc|cba)A","AabcA")) # ['AabcA']
print(re.findall("com(?:puter|e)","come on! Here is a computer ")) # ['come', 'computer']
#匹配所有数字
print(re.findall("\d+\.?\d*","12as3.45qw2k7")) # ['12', '3.45', '2', '7']
贪婪匹配.*
与懒惰匹配.*?
print(re.findall("a.*b","a11b22222b33")) # ['a11b22222b']
print(re.findall("a.*?b","a11b22222b3")) # ['a11b']
4. 方法示例
#re.findall(pattern,string)
#在字符串中找到正则表达式所匹配的所有子串, 并返回一个列表, 如果没有找到匹配的, 则返回空列表
print(re.findall("(ab)+(cd)+","ababcdcd abcd"))
#[('ab', 'cd'), ('ab', 'cd')],返回元组列表
#re.search()
匹配整个字符串, 只到找到第一个匹配然后返回一个包含匹配信息的对象(re.Match对象)
该对象可以通过调用 group()方法得到匹配的字符串,如果字符串没有匹配,则返回None
如果没有匹配到值就调用 group() 方法, 抛出异常
print(re.search("abc","112abc333abc"))
# <re.Match object; span=(3, 6), match='abc'>
print(re.search("abc","112abc333abc").group()) # abc
print(re.search("abcd","12abc333abc")) # None
print(re.search("abcd","12abc333abc").group())
# 报错 "AttributeError" 因为没拿到这个对象,所以没有group()属性
#re.match()
与 re.search 功能相同, 但必须匹配起始位置, 不然返回 None
print(re.match("abc","abc22abc"))
# <re.Match object; span=(0, 3), match='abc'>
print(re.match("abc","abc22abc").group()) # abc
print(re.match("abc","1abc22abc")) # None
#re.split()
以规定字符作为分隔符对字符串进行切分, 切分结果放入列表, 没匹配到返回原字符串列表
将规定字符放入 [ ] 则是逐个匹配
print(re.split("ab","abcoababcoabc")) #['', 'co', '', 'co', 'c']
print(re.split("a","nbc")) #['nbc'],返回原字符串
print(re.split("[ob]","abcoabcoabc")) # ['a', 'c', 'a', 'c', 'a', 'c']
#re.sub()和re.subn()
匹配字符, 并将其该成指定字符, 返回改变后的字符串, 后面可跟个数参数, 不指定默认替换所有
re.subn( ) 返回一个元组, 第二个元素返回的是替换的个数
print(re.sub("a","AA","i am a man")) # i AAm AA mAAn
print(re.sub("a","AA","i am a man",100)) # i AAm AA mAAn,不报错
print(re.subn("a","A","i am a man")) # ('i Am A mAn', 3) (显示替换的个数)
#re.compile() 返回一个对象
obj=re.compile("\d{2}")
print(obj) # re.compile('\\d{2}')
print(obj.findall("ab123bc123")) #['12', '12']
print(obj.search("ab123bc123").group()) # 12
print(obj.match("123ab123bc123").group()) # 12
substitude 替换
5. 非捕获匹配?: ?! ?=
# ?:
(?:)非捕获分组,只会进行单纯的模式匹配并不会将匹配到的值进行保存,与()区分
print(re.findall("jk(loli)+","jkloli")) # ['loli']
print(re.findall("jk(?:loli)+","jkloli")) # ['jkloli']
# ?! 正向否定预查
1.在没匹配到字符串的前提下,再进行后续的正则,后续匹配仍然从被匹配字符串的头开始
res = re.match("(?![\d]+$)(?![a-zA-Z]+$)[\da-zA-Z]{6}$",passwd)
#匹配6位数字与字母组合,不能纯数字或字母
2.匹配位置 后面 不能跟着指定表达式。
print(re.findall("19(?!99)","1999"))
print(re.findall("\d{2}(?!99)","1999 1988"))#['99', '19', '88']
#先尝试匹配"1999",再'999 '(成功),再"9 19",再" 198",再"1988"(成功),再"88",理解下匹配的窗格移动
# ?= 正向肯定预查
1.在匹配到字符串的前提下,再进行后续的正则,后续匹配仍然从被匹配字符串的头开始
res = re.search("(?=.*[\d])(?=.*[a-z])(?=.*[A-Z])(?=.*)(?=.*[!@#%&])^([\da-zA-Z!@#%&]{7,})$",passwd)
#至少七位密码,包含大小写,数字,特殊字符(!,@,#,%,&)
2.匹配位置 后面 必须跟着指定表达式。
r"foo(?=bar)"可以匹配foobar中的foo,不能匹配foobaz中的foo
# ?<=
匹配位置 前面 必须跟着指定表达式。
print(re.findall("(?<=jk).*?(?=li)","mcjli jkloli liejk")) #['lo']
# ?<!
匹配位置 前面 不能跟着指定表达式。
print(re.findall("\\B(?<!18)\d{2}\\b","1988 1899")) #['88']
6. 边界匹配问题
\b表示单词边界,\B表示非单词边界
一般空格、换行、标点符号或者特殊符号来表示边界
或者说非数字、字母、下滑线、unicode汉字表示边界
中文字符串为边界的话要用re.A编码模式
print(re.findall("\\b19(?:[^9]{2})\\b","1999 1988")) #['1988']
print(re.findall("\\b19(?:[^9]{2})\\b","你也玩1999?1988带我一个",re.A))
# ['1988']
4. requests库
基于urllib库的HTTP库,比urllib库方便。
超文本传输协议(HTTP)是一种基于"请求与响应"模式的、无状态的应用层协议。
URL一般格式
protocol://host[:port]/path/[?query]#fragment
http://www.itcast.cn/index.html?name=andy&age=18#link
GET与POST区别
使用:GET通常用于获取网页数据,查询数据等,POST通常用于提交表单,上传文件等。
安全性:GET请求将参数附加在URL中,对用户可见。POST请求的参数包含在请求体中,对用户不可见。
请求长度限制:GET请求将参数附加到URL中,URL的长度有限制。POST请求将参数包含在请求体中,可以传递较大数据量。
缓存:GET请求可以被缓存,POST请求不会被缓存。
对数据类型的限制:GET只允许ASCII字符,POST允许二进制数据。
requests库常用方法 | |
---|---|
r=requests.get(url, params=None, **kwargs) | get请求,params得是一个字典,kwargs一般有headers请求头 |
r=requests.post(url, data=None, json=None, **kwargs) | post请求,data得是一个字典 |
r=requests.Session() | 使用Session类维持会话 |
常见可变参数 | |
---|---|
headers | 请求头 |
cookies | 设cookie来维持登陆状态 |
proxies | 代理设置 |
files | 用来post上传文件 |
timeout=60 | 连接和读取总超时时间(秒) |
auth=(‘admin’,‘123’) | 身份验证 |
response的属性 | |
---|---|
r.status_code | http请求的返回状态,若为200则表示请求成功。 |
r.cookies.items() | 获取cookies,用key,value遍历 |
r.text | http响应内容的字符串形式,即返回的页面内容 |
r.content | http响应内容的二进制形式 |
r.json() | 得到对应的json格式 |
r.encoding | 从http header 中猜测的相应内容编码方式 |
r.apparent_encoding | 从内容中分析出的响应内容编码方式(备选编码方式) |
f={'file':'open('1.jpg',"rb")'}
proxies={
'http':'http://127.0.0.1:80',
# 'https':'https://127.0.0.1:80',
'https':'socks5://user:password@192.168.123.1:80'
}
r=requsets.post("http://baidu.com/",files=f,proxies=proxies)
import requests
import os
from urllib import parse
string={'t':'1','from':'0','comm_exist':'on','kw':"月星中央公园"}
string=parse.urlencode(string)# url编码一下
cookie="ctid=39; aQQ_ajkguid=48F4121D-3F8D-0077-F423-82558C46ABD7; id58=CrIclWU30oyGjaJ4LaR6Ag==; ajk-appVersion=; seo_source_type=1; fzq_h=475856ba31bb9179139bb04430940fd8_1705814357915_34bf968494bc41539dea738e0278cf08_2028294646; lp_lt_ut=26f889a16be9d3724fab580f7353e7b0; isp=true; 58tj_uuid=74bed1ad-98fe-4120-91e6-0ee5e400d6c1; new_uv=1; als=0; xxzlclientid=4c186e92-9252-49e3-a441-1705816054130; xxzlxxid=pfmxQcvbGG0JAmeSXOHwuGZagiOoTmFdcwnahVpL/gL6nPEOcXjJIPev+Dr7CvHH9VmI; xxzlbbid=pfmbM3wxMDMyNXwxLjUuMXwxNzA1OD…mctid=188; sessid=75FB0FE2-B6E9-87EA-661E-10DEDA44EEBD; obtain_by=1; twe=2; fzq_js_anjuke_ershoufang_pc=05ed67efa31983351a3cde4b55d7acba_1705819197158_24; lps=https%3A%2F%2Fshen.zu.anjuke.com%2F%3Fkw%3D%25E6%259C%2588%25E6%2598%259F%25E4%25B8%25AD%25E5%25A4%25AE%25E5%2585%25AC%25E5%259B%25AD%26comm_exist%3Don%26from%3Dlist_ac%26facet_comm_id%3D100668077%7Chttps%3A%2F%2Fsy.anjuke.com%2F; xxzl_cid=676c948039454a4b851884286e2878df; xxzl_deviceid=W69KvVyR07t3zIA7fgB7dplSWQbqPXDJr9UgO+3mZe1z643gASf+/vurnxxXytg7"
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
'Host':'shen.zu.anjuke.com',
'Cookie':cookie.encode('utf-8') # cookie有些字符没法识别,需要编码一下
}
r=requests.get("https://shen.zu.anjuke.com/?",params=string,headers=headers)
print(r.status_code)# 状态码
r.encoding=r.apparent_encoding # apparent_encoding会从内容中分析出响应内容编码
# r.encoding="gb2312" 或者手动赋值防止中文乱码
content=r.text
if not os.path.exists('./test1.txt'):
open('./test1.txt','w').close()# 新建txt
with open('./test1.txt','w+') as fp: # 这边是读写形式新建(或覆盖)一个文件
fp.write(content)
5. threading库
1. 基本概念
Thread类的构造方法
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
类与方法 | 作用 |
---|---|
Thread(target,args,kwargs) | Thread类,target线程函数,args是传递给目标函数的参数,kwargs关键字参数 |
start() | 启动线程,调用线程的run()方法来执行线程函数。 |
join(timeout) | 等待线程执行完毕再执行后面代码,可选地指定一个超时时间。 |
is_alive() | 返回线程是否处于活动状态 |
getName() | 返回线程的名称 |
setName(name) | 设置线程的名称 |
sleep(seconds) | 在指定的秒数内让线程休眠 |
enumerate() | 返回当前活动的Thread对象列表 |
current_thread() | 返回当前线程对象 |
active_count() | 当前活动线程数量 |
属性 | |
name | 线程名称 |
is_alive | 线程是否处于活动状态 |
ident | 线程的标识符 |
import threading
import time
l=["a","b","c"]
def task(e):
print("线程名%s,参数%s"%(threading.current_thread().name,e))
print("id:%s"%(threading.current_thread().ident))
time.sleep(5)
if __name__=='__main__':
for i in l:
t=threading.Thread(target=task,args=(i,))# 创建线程
t.start() # 启动线程
print(f"{threading.current_thread().name}")# MainThread # 主线程
print(f"{threading.active_count()}") # 4 # 包含了主线程
2. daemon 守护线程
设为True的时候,当主程序执行完成后,马上就终止当前任务,不管是否完成。
设为None的时候(默认),当主程序执行完成后,会等待子线程完成再退出。
import threading
import time
l=["a","b","c"]
def task(e):
c=threading.current_thread()
print("线程名%s,参数%s"%(c.name,e))
time.sleep(2)
print("线程名%s,id:%s"%(c.name,c.ident))
if __name__=='__main__':
for i in l:
t=threading.Thread(target=task,args=(i,),daemon=None)
t.start() # 启动线程
print(f"{threading.current_thread().name}")
print(f"{threading.active_count()}")
3. 线程间的等待join
import threading
import time
l=["a","b","c","d"]
def task(e):
c=threading.current_thread()
print("线程名%s,参数%s"%(c.name,e))
time.sleep(2)
print("线程名%s,id:%s"%(c.name,c.ident))
threads=[]
if __name__=='__main__':
for i in l:
t=threading.Thread(target=task,args=(i,))
t.start() # 启动线程
threads.append(t)
for i in threads:
i.join()# 当threads[0]线程执行完后才会遍历threads[1]线程,以此类推
# 但是sleep阻塞结束后,线程调度将自行选择一个线程执行,没法保证顺序
print("结束")
4. Lock 锁解决资源竞争问题(丢失更新)
import threading
num=100
num2=200000
count=0
lock=threading.Lock() # 新建锁对象
threads=[]
def task():
global count
for i in range(num2):
#with lock:
lock.acquire()# 获取锁
count+=1
lock.release()# 释放锁
if __name__=='__main__':
for i in range(num):
t=threading.Thread(target=task)
t.start() # 启动线程
threads.append(t)
for i in threads:
i.join()# 线程的结束顺序是乱序的,必须等全部结束才打印
print(f"{count}")# 20000000,结果要等很久
5. 线程终止
import ctypes
import inspect
def _async_raise( tid, exctype): # 参考stackoverflow代码,通过向线程抛异常杀死线程
"""raises the exception, performs cleanup if needed"""
tid = ctypes.c_long(tid) # 线程id转成c的long类型
if not inspect.isclass(exctype): # 检查exctype是否是一个类
exctype = type(exctype) # 不是类的转换为类
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) # 用于在一个指定的线程中异步地抛出一个异常
# 成功返回1,线程id无效返回0,其他问题返回大于1的数字
if res == 0:
print("ValueError(invalid thread id)")
elif res != 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
#ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
print("PyThreadState_SetAsyncExc failed")
def stop_thread(thread): # 终止线程
_async_raise(thread.ident, SystemExit) # 线程id,异常类型
6. 协程实现
对于卖票问题,就不适合用线程实现,得用协程。
生成器函数每次执行yield 返回值
将返回一次返回值,并记录函数执行的位置,待下次next()的时候,会从记录的位置执行。
生成器函数return或没有yield就结束会抛异常,for捕获后会停止遍历。
from threading import Thread # 导入Thread类,但并未在代码中使用
from random import random # 导入random函数,用于生成随机数
#协程允许在一个函数中暂停和恢复执行,并且可以在每个帧之间进行切换。协程是异步机制
# 模拟是否有客人来
def lai():
return random() < 0.5 # 如果生成的随机数小于0.5,则返回True(表示有客人来)
piao = 100 # 初始化票的数量为100
# 定义一个生成器函数,用于模拟售票过程
def task(name):
global piao # 声明piao为全局变量
n = 0 # 初始化售出的票数
while piao > 0: # 当票数大于0时,继续售票
if lai(): # 如果有客人来
print("{}卖出第{}张票,剩余{}张".format(name, piao, piao - 1)) # 打印售票信息,但这里有个小错误,应该是piao的当前值而不是piao-1
piao -= 1 # 票数减1
n += 1 # 售出的票数加1
yield True # 返回一个True值,表示该任务还在进行
print(name, '卖出票数', n) # 当票售完时,打印售出的票数
yield False # 返回一个False值,表示该任务已完成
# 创建一个列表,包含三个售票任务(生成器)
L = [task("李明"), task('张华'), task("王宜")]
T = True # 初始化一个标志,用于控制外层循环
while T: # 当T为True时,继续循环
T = False # 先假设所有任务都已完成
n = len(L) # 获取当前任务列表的长度
for i in range(n): # 遍历任务列表
t = L[i] # 取出当前任务
if t: # 如果任务还未完成(即t不是None)
r = next(t) # 执行任务的下一步(即售票或结束)
if not r: # 如果任务返回False,表示任务已完成
L[i] = None # 将任务列表中的该任务设为None
T = T or r # 如果任务返回True,则T保持为True或变为True
print('over') # 所有任务都完成后,打印'over'
6. time库
print(time.ctime())# Sat Jan 20 18:10:40 2024
print(time.time())# 1705745440.5832005
# 时间戳,从格林尼治时间1970.1.1到当前时间经过的浮点秒数
time.sleep(5) # 程序停五秒
7. os库
操作文件和目录 | 作用 |
---|---|
os.getcwd() | 获取当前工作目录的路径。 |
os.chdir(path) | 改变当前工作目录到指定的路径。 |
os.listdir(path) | 返回指定目录下的文件和目录列表。 |
os.mkdir(path) | 创建一个目录。 |
os.makedirs(path) | 递归地创建多层目录。 |
os.remove(path) | 删除一个文件。 |
os.rmdir(path) | 删除一个目录。 |
os.rename(src, dst) | 重命名文件或目录。 |
os.system(“chcp 65001 && cls”) | 执行系统命令 |
路径相关操作 | |
---|---|
os.path.exists(path) | 判断路径是否存在。 |
os.path.isfile(path) | 判断路径是否为文件。 |
os.path.isdir(path) | 判断路径是否为目录。 |
os.path.join(path1, path2, …) | 拼接多个路径组件。 |
8. beautifulsoup4库
pip install lxml
pip install beautifulsoup4
使用lxml作为beautifulsoup4解释器
1. 节点选择器
使用tag(标签)类对象来选择节点元素,其属性有name,attrs,string。
from bs4 import BeautifulSoup
str="""<html>
<head><title>大标题</title></head>
<body style="background-color:yellow;">
<h2 style="background-color:red;" class="bb88" >这是一个标题</h2>
444<p style="background-color:green;">这是一个段落。</p>666
555<p>hello</p>
<p>brother</p>
<a href="https://baidu.com" class="stay" id="link1">百度</a>
</body>
</html>
"""
s=BeautifulSoup(str,'lxml')# 实例化对象
print(s.p)# 多个相同标签,只提取第一个p标签
# <p style="background-color:green;">这是一个段落。</p>
print(s.h2.name) #名称
print(s.h2.attrs)# 属性
print(s.h2.string)# 值
print(s.body.a.string) #嵌套使用
# h2
# {'style': 'background-color:red;', 'class': ['bb88']}
# 这是一个标题
# 百度
关联选择 | 说明 | 返回值 |
---|---|---|
contents | 子节点 | 列表 |
children | 迭代器 | |
descendants | 子孙节点 | 生成器 |
parent | 父节点 | Tag类对象(节点元素) |
parents | 子孙节点 | 生成器 |
next_sibling | 兄弟节点 | NavigableString类对象 |
next_siblings | 生成器 | |
previous_sibling | NavigableString类对象 | |
previous_siblings | 生成器 |
s=BeautifulSoup(str,'lxml')# 实例化对象
print(s.p.contents) # ['这是一个段落。']
for i in s.p.children:
print(i)
# 这是一个段落。
for i in s.html.descendants:
print(i)
# 先打印<head>...</head>再打印<title>...</title>再打印 大标题
print(s.title.parent)# 父节点,title外一层的结点
# <head><title>大标题</title></head>
for i in s.p.parents:# 获取祖先节点,包含html
print(i)
# 先打印<body>...</body>再打印<html>...</html>
print(s.p.next_sibling)
'''
666
555'''
for i in s.p.next_siblings:# 从666 555开始打印到<a>...</a>
print(i)
print(s.p.previous_sibling)
'''
444'''
for i,j in enumerate(s.p.previous_siblings):# 枚举一下
print(i,j)
'''
0
444
1 <h2 class="bb88" style="background-color:red;">这是一个标题</h2>
2 '''
2. CSS选择器
s.select()
html="""
<body>
<div class='any'>
<ul class='list1' id='m87'>
<li><a href="#miao" id='a'>去找喵星人</a></li>
<li><a href="#wang" id='b'>去找汪星人</a></li>
<li><a href="#meng" id='c'>其他萌物</a></li>
</ul>
<a name="miao"></a><!--设置锚点方法1-->
<h3 id="miao">喵星人基地</h3><!--设置锚点方法2-->
<ul class='list2' id='c4'>
<li>喵喵</li>
<li>喵喵喵</li>
</ul>
</div>
</body>
"""
CSS选择器 | 格式 |
---|---|
id选择器 | #a |
类选择器 | .list2 |
标签选择器 | h3 |
s=BeautifulSoup(html,'lxml')# 实例化对象
print(s.select(".any #c4"))
'''[<ul class="list2" id="c4">
<li>喵喵</li>
<li>喵喵喵</li>
</ul>]'''
print(s.select("ul #b"))
# [<a href="#wang" id="b">去找汪星人</a>]
# 嵌套使用
for i in s.select("ul"):
print(i.select("li"))# i是Tag类对象
'''[<li><a href="#miao" id="a">去找喵星人</a></li>, <li><a href="#wang" id="b">去找汪星人</a></li>, <li><a href="#meng" id="c">其他萌物</a></li>]
[<li>喵喵</li>, <li>喵喵喵</li>]'''
3. 方法选择器
方法 | 说明 | 返回值 |
---|---|---|
find_all() | 获取所有符合条件的元素 | ResultSet类 |
find() | 获取符合条件的第一个元素 | Tag类对象 |
find_parents() | 获取所有符合条件的祖先节点 | |
find_parent() | 获取符合条件的父节点 | |
find_next_sibling() | 获取后面第一个符合条件的兄弟节点 | |
find_next_siblings() | 获取后面所有符合条件的兄弟节点 | |
find_previous_sibling() | 获取前面第一个符合条件的兄弟节点 | |
find_previous_siblings() | 获取前面所有符合条件的兄弟节点 | |
find_all_next() | 获取后面所有符合条件的节点(包括子孙节点) | |
find_next() | 获取后面第一个符合条件的节点 | |
find_all_previous() | 获取前面所有符合条件的节点(包括子孙节点) | |
find_previous() | 获取前面第一个符合条件的节点 |
find_all(self, name=None, attrs={}, recursive=True, string=None, limit=None, **kwargs)
name参数:规定了Tag类对象名字为name。可接受字符串,列表,正则,True
attrs参数:接收属性的键值对字典
kwargs参数:接收常用变量赋值的形式,如id=‘link1’,class_=‘sister’ 注意下划线
text参数:接收文本信息
limit参数:限制返回结果数量
recursive参数:决定是否获取子孙节点,默认True
print(s.find_all('span')) #查找所有的span标签,并以列表形式打印
for i in s.find_all(re.compile('^b')):# 查找所有以b开头的标签
print(i) # i是Tag类对象
print(s.find_all(name=['a','h3'])) # 获取a标签和h3标签
print(s.find_all(name=True))# 递归地获取所有标签
9. pymysql库
db=pymysql.connect(host='localhost', user='user', password='password', port=3306)#连接数据库
cursor=db.cursor()#游标创建
sql="""SELECT * from table_name"""
cursor.execute(sql)#执行SQL
result=cursor.fetchall()#获取查询结果
db.commit() #提交到数据库执行
cursor.close()#关闭游标
db.close()#关闭连接
10. socket库
参考下面伪代码
import tkinter
import threading
import socket
import queue
import json
class Server:
def __init__(self):
self.thread_list=queue.Queue()#连接线程池
pass #请自行实现
def start_server(self):
if self.thread_list.empty() == False:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # AF_INET服务器之间的网络通信,SOCK_STREAM流式socket,使用TCP
try:
s.bind((self.host, self.port)) # 服务器端函数,绑定本地端口
s.listen() # 使用TCP服务器端开启监听模式,参数位可以挂起的最大连接数
print(f'Server is listening on {self.host}:{self.port}')
self.conn = s
conn, self.addr = s.accept() # 接收客户端请求,返回(conn,address),
# conn为新的套接字对象,可以用来接收客户端数据和发送数据,address是连接客户端的地址。
print(f'Connected by {self.addr}')
while True: # 建立连接后,持续接收客户端信息
data = conn.recv(8192) # 接收TCP套接字的数据(8192字节),并以bytes形式返回,需要decode()
if not data:
break
data_dict = json.loads(data.decode())
print(data_dict.keys())
if (data_dict.get('a') and data_dict.get('b') and data_dict.get('c')): # 处理客户端发来的a,b,c
self.a=data_dict.get('a')
self.b=data_dict.get('b')
message = json.dumps(
{"a": str(self.a), "b": str(self.b)}).encode()
# 转json格式
conn.sendall(message)
#self.refresh()
# 这里刷新gui界面
except ConnectionResetError as e:
print("客户端连接关闭")
self.stop_connect()#关闭连接函数
except ConnectionAbortedError as e:
print("你的主机中的软件中止了一个已建立的连接。")
self.stop_connect()
def stop_connect(self):
while self.thread_list.empty() == False:
#服务器端没法停止监听,只能杀线程
self.conn=0
t = self.thread_list.get_nowait()
self.create_gui()
stop_thread(t)#需要使用ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
import json
import tkinter
import threading
import socket
import queue
class Client:
def __init__(self):
pass
def start_client(self):
try:
if self.thread_list.empty()==False:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: #AF_INET服务器之间的网络通信,SOCK_STREAM流式socket,使用TCP
s.connect((self.host, self.port)) #客户端用来连接服务器端函数,连接本地的端口
self.refresh()#刷新gui界面
self.conn=s#保存连接对象
self.addr=s.getsockname()#获取客户端地址和端口号
message_1 = json.dumps({'a':str(self.a),'b':str(self.b),'c':str(self.c)}).encode()#转为json格式字符串
s.sendall(message_1)#完整发送TCP数据,成功返回None,失败则抛出异常
# 持续接收服务器响应
while True:
data = s.recv(8192)#recv接收TCP套接字的数据(8192字节),并以bytes形式返回,需要decode()
if not data: # 如果recv返回空字节串,说明服务器已经关闭连接
break
data_dict = json.loads(data.decode())
if data_dict['a'] and data_dict['b']:
message_2=json.dumps({"result":"你说得对"}).encode()
s.sendall(message_2)
self.refresh()
else:
print("已建立一条连接!")
except ConnectionResetError as e:
print("客户端连接关闭")
self.stop_connect()
except ConnectionAbortedError as e:
print("你的主机中的软件中止了一个已建立的连接。")
self.stop_connect()
except ConnectionRefusedError as e:
print("由于目标计算机积极拒绝,无法连接。")
self.stop_connect()
def stop_connect(self):
if self.thread_list.empty()==False:
try:
t = self.thread_list.get_nowait()#下一个可能因为线程已自动退出而抛异常,所以线程先出队列
self.conn.close()#连接终止,使线程退出
self.refresh()
except AttributeError as e:
print("线程已自动终止")
self.refresh()