Python之并发+网络编程
off999 2024-12-13 15:36 21 浏览 0 评论
第一节:网络模块概述与urllib.parse模块讲解
- 网络分层及协议(TCP/IP)
- Python的网络模块
- socket:基于传输层TCP、UDP协议进行网络编程的模块
- email:Email和MIME消息处理模块
- smtplib:支持SMTP协议(发送邮件)的客户端模块
- poplib:支持POP3协议的客户端模块
- urllib及其子模块:支持URL处理的模块
- urllib.parse:用于解析URL
- 使用urlparse()函数来解析字符串
- 使用urlunparse()函数则可以把一个parseresult对象或元组恢复成URL字符串
import urllib.parse
# urlparse()用于解析URL字符串,返回值为ParseResult(tuple的子类)
# urlunparse()将URL各部分(ParseResult或tuple)恢复成URL字符串
s = 'http://www.crazyit.org:80/index.html;abc?name=yeeku#myfrag'
# 解析url字符串
r = urllib.parse.urlparse(s)
# ParseResult对象
print(r)
# ParseResult是tuple的子类
print('协议', r.scheme, r[0])
print('位置', r.netloc, r[1])
print('资源路径', r.path, r[2])
print('参数', r.params, r[3])
print('字符串查询', r.query, r[4])
print('fragment', r.fragment, r[5])
# 元组
tu = ('https', 'www.python.org:80', '/index.html', 'wawa', 'name=yoku', 'title')
# 恢复查询字符串
print(urllib.parse.urlunparse(tu))
- 处理查询字符串
- parse_qs()和parse_qsl()(这个l代表list)两个函数都用于解析查询字符串,只不过返回值不同而已,parse_qsl()返回的是list
- urlencode()则是他们的逆函数
import urllib.parse
# parse_qs()和parse_qsl()用于解析查询字符串,得到字典或者列表
# urlencode()将列表或者字典恢复成查询字符串
#查询字符串格式:key=value,多个key=value之间用&隔开
qs = 'name=python&name=crazyit&age=27&height=182'
# 返回字典
print(urllib.parse.parse_qs(qs))
# 返回列表
print(urllib.parse.parse_qsl(qs))
# 已有列表
lt = [('name', 'python'), ('name', 'crazyit'), ('age', '23')]
# 将列表恢复成查询字符串
print(urllib.parse.urlencode(lt))
# 已有字典
query_dict = {'name': 'python', 'age': '23', 'height': '183'}
# 将字典恢复成查询字符串
print(urllib.parse.urlencode(query_dict))
第二节:案例实操-使用urllib模块读取网络资源及提交请求
- urllib.request.urlopen(url, data=None)方法,用于打开url指定的资源,并从中读取数据
import urllib.request
# urlopen(url, data=None) 打开URL对应的资源
# 打开网络资源之后,该资源就像一个文件,可以按照文件的方式进行处理
with urllib.request.urlopen('https://www.crazyit.org/index.php') as f:
print(f.read(510).decode('UTF-8'))
- 使用urlopen()函数时可以通过data参数向被请求的url发送数据
- 发送GET请求参数时,只要将请求参数追加到URL后面即可
import urllib.request
# 用字典代表请求参数
params = {'name': 'python', 'passwd': '665815'}
# GET请求参数,只需添加到URL之后即可(使用自己本身的IP地址及路径下的文件测试)
with urllib.request.urlopen('https://192.168.1.17:8888/test/get.jsp?%s' % urllib.parse.urlencode(params)) as f:
print(f.read().decode('UTF-8'))
# post请求参数,用data参数来指定
with urllib.request.urlopen('https://192.168.1.17:8888/test/post.jsp?%s' data = urllib.parse.urlencode(params).encode('utf-8')) as f:
print(f.read().decode('UTF-8'))
- 如果发送PUT、PATCH、DELETE等请求,此时需要用urllib.request.Request来构建请求参数
- 构建Request对象时,可以用method参数指定请求方法
import urllib.request
# 定义需要put的请求参数
params = 'put数据'.encode('utf-8')
# 如果发送PUT、PATCH、DELETE等请求,此时需要用urllib.request.Request来构建请求参数
req = urllib.request.Request(url='https://192.168.1.17:8888/test/put', data=params, method='PUT')
# 有了Request对象之后,用urlopen打开对象即可
with urllib.request.urlopen(req) as f:
print(f.read().decode('UTF-8'))
- 访问被保护的资源,需要先登录再访问
import urllib.request
import http.cookiejar
# 如果你要能保持客户端多次请求的状态,那么必须借助于cookie
# 创建cookiejar对象
cookie_jar = http.cookiejar.MozillaCookieJar('a.txt')
# 创建一个cookie处理器
cookie_proc = urllib.request.HTTPCookieProcessor(cookie_jar)
# 创建OPenerDirector对象,当程序使用OPenerDirector对象来发送多次请求时,
# 他们使用相同的cookie,因此服务端就可以维持多次访问的状态
opener = urllib.request.build_opener(cookie_proc)
# 用字典代表请求参数
params = {'name': 'crazyit.org', 'pass': 'leegang'}
with opener.open('https://192.168.1.17:8888/test/login.jsp'\
, data=urllib.parse.urlencode(params).encode('utf-8')) as f:
print(f.read().decode('UTF-8'))
# 尝试访问被保护的资源(必须先登录才能访问的字眼)
with opener.open('https://192.168.1.17:8888/test/secret.jsp') as f:
print(f.read().decode('UTF-8'))
第三节:TCP协议概述及python的TCP支持与创建TCP服务器
- tcp/ip协议相关的网络知识就不在这里赘述了
# server端
import socket,threading
'''
参数一:指定网络类型 AF_INET:IPV4网络, AF_INET6:IPV6网络 AF_UNIX:UNIX网络
参数二:指定socket类型 SOCK_STREAM:TCP SOCK_DGRAM:UDP
'''
'''
创建套接字之后,需要绑定到指定的IP和端口,监听来自客户端的链接,接受来自客户端的链接
创-》绑-》监-》接-》关
'''
# 定义一个列表
client_list = []
def server_target(server_socket):
# 一旦建立链接之后,server与client虚拟链路建立成功
while True:
content = client_socket.recv(2048).decode('UTF-8')
if content is not None:
# 读取到数据之后,将数据打印出来
print(content)
# 将数据再送回到每个客户端
for cl in client_list:
cl.send(content.encode('utf-8'))
# 步骤一:创建套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
# 步骤二:绑定套接字
s.bind(('10.10.24.15', 23))
# 步骤三:监听套接字
s.listen()
# 步骤四:链接套接字
while True:
# 接收来自客户端的链接
# 该方法返回两个参数,c代表与客户端socket对应的、通信的socket
# addr代表客户端的地址
c, addr = s.accept()
print(addr)
# 将所有客户端对应的socket保存到列表中
client_list.append(c)
# 为客户端对应的socket启动对应的线程
threading.Thread(target=server_target, argc=(c,)).start()
# 步骤五:关闭套接字
c.close()
第四节:使用socket通信并加入多线程
- 通过threading.Thread创建线程
- 服务端为每个客户端启动一条线程,保证各客户端互不干扰
- 客户端为网络IO启动一条线程,为用户交互启动一条线程
# client端
import socket,threading
def read_server(client_socket):
# 一旦建立链接之后,server与client虚拟链路建立成功
while True:
content = client_socket.recv(2048).decode('UTF-8')
if content is not None:
print(content)
# 步骤一:创建套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
# 步骤二:connect链接服务端
client_socket.connect(('10.10.24.15', 23))
# 将read_server函数以多线程的方式启动,这样该函数(包含死循环)能与下面的死循环并发执行
threading.Thread(target=read_server, args=(client_socket,)).start()
while True:
# 获取用户输入
line = input('')
if line is None or line == 'exit':
break
# 将用户输入的内容写入网络
client_socket.send(line.encode('UTF-8'))
# 关闭套接字
client_socket.close()
第五节:案例实操-使用smtplib模块发送邮件
- 使用smtplib库来发送邮件大致只要三步:
- 1. 链接smtp服务器,并使用用户名密码登录服务器
- 2. 创建EmailMessage对象,该对象代表了邮件本身
- 3. 调用代表与SMTP服务器链接对象的sendmail()方法发送邮件
- 添加附件
- 调用EmailMessage的add_attachment()方法,支持的参数如下
- maintype:指定附件的主题
- subtype:指定附件的子类型
- filename:指定该附件的文件名
- cid=img:指定该附件的资源ID
import smtplib
import email.message
import email.utils
'''
# smtplib.SMTP 代表普通的SMTP连接
# smtplib.SMTP_SSL() 代表基于SSL的SMTP连接
# coon = smtplib.SMTP('smtp.qq.com', 21)
# coon = smtplib.SMTP_SSL('smtp.qq.com', 465)
'''
# 生成一个cid
first_id = email.utils.make_msgid()
fromaddr = 'kongyeeku@qq.com'
# qq邮箱要开启安全码
password = 'diwpwjfoasosng'
# 创建SMTP连接
coon = smtplib.SMTP_SSL('smtp.qq.com', 465)
coon.set_debuglevel(1)
# 步骤一:登录邮件服务器
conn.login(fromaddr, password)
# 步骤二:创建EmailMessage对象
msg = email.message.EmailMessage()
# 设置邮件内容(普通邮件)
# msg.set_content('您好,Python邮件')
# 设置邮件内容(HTML邮件)
msg.set_content('<h2>HTML邮件</h2>'
+ '<div style="border:lps:solod red">html邮件内容</div>', 'html', 'UTF-8')
# 用于设置邮件的主题、发件人和收件人
msg['subject']='HTML邮件'
msg['from']='xxx<%s>' % fromaddr
msg['to']='xxx<%s>' % 'aaaa@qq.com'
# 添加附件
# 附件指定了cid之后,邮件正文可通过cid来引用该图片
with open('e:/logo.jpg', 'rb') as f:
msg.add_attachment(f.read(), maintype='image',
subtype='jpeg', filename='test.jpg', cid=first_id)
# 步骤三:sendmail方法发送邮件
conn.sendmail(fromaddr,['aaaa@qq.com', 'bbbb@qq.com'],msg.as_string())
# 退出文件
conn.quit()
第六节:使用poplib模块收取文件
- 使用poplib模块提供的poplib.POP3和poplib.POP_SSL两个类,分别用于连接普通的pop服务器和基于SSL的pop服务器,现在都使用poplib.POP_SSL类
- pop3的命令和响应都是基于ASCII文本的,并以CR和LF(/r/n)作为行结束符
- 响应包括一个表示返回状态的符号(+/-),和描述信息
- 请求和响应的标准格式如下:
- 请求标准格式:命令[参数]CRLF
- 响应标准格式:+OK/[-ERR] description CRLF
- 常见命令
- stat:统计邮件服务器状态,包括邮件数和总大小
- list[mas_no]:列出全部邮件或者指定邮件,返回邮件编号和对应的大小
- retr msg_no:获取指定邮件的内容(根据邮件序号来获取,序号从1开始)
import poplib
import email.parser, email.policy
# 创建与邮件服务器的链接
# conn = poplib.POP3('pop.qq.com', 110) 传统的不安全的
# 基于SSL
conn = poplib.POP3_SSL('pop.qq.com', 995)
coon.set_debuglevel(1)
print(conn.getwelcome().decode('utf-8'))
conn.user('kongyeeku@qq.com')# 相当于使用user命令
conn.pass_('diwpwjfoasosng')# 相当于使用pass命令,qq安全码
# 统计邮件信息,相当于stat命令
num, totalsize = conn.stat()
print('邮件数', num)
print('总大小', totalsize)
# 获取邮件列表,相当于list命令
resp, maillist,r = conn.list()
print('响应:', resp)
print('邮件列表:', maillist)
# 获取最后一封邮件
resp, maildata, r = conn.retr(len(maillist))
print('响应:', resp)
print('邮件数据:', maildata)
data = b'\r\n'.join(maildata)
# 将邮件数据恢复成EmailMessage对象
msg = email.parser.BytesParser(policy=email.policy.default).parsebytes(data)
print(type(msg))
print('发件人', msg['from'])
print('收件人', msg['to'])
print('主题', msg['subject'])
print('第一个发件人用户名', msg['from'].address[0].username)
print('第一个收件人用户名', msg['to'].address[0].username)
# 遍历邮件内容,邮件每个部分都是一个part
for part in msg.walk():
# multipart代表邮件内容的容器,无需处理,继续读取它包含的part即可
if part.get_content_tpye() == 'multipart':
continue
# 代表邮件的正文
elif part.get_content_tpye() == 'test':
print(part.get_comtent())
# 剩下的就是邮件的附件
else:
filename = part.get_filename # 得到附件的文件名
# 将附件下载(写入)本地磁盘文件
with open(filename, 'wb') as f:
f.write(part.get_payload(decode=True))
# 退出服务器,相当于quit命令
conn.quit()
相关推荐
- 面试官:来,讲一下枚举类型在开发时中实际应用场景!
-
一.基本介绍枚举是JDK1.5新增的数据类型,使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错...
- 一日一技:11个基本Python技巧和窍门
-
1.两个数字的交换.x,y=10,20print(x,y)x,y=y,xprint(x,y)输出:102020102.Python字符串取反a="Ge...
- Python Enum 技巧,让代码更简洁、更安全、更易维护
-
如果你是一名Python开发人员,你很可能使用过enum.Enum来创建可读性和可维护性代码。今天发现一个强大的技巧,可以让Enum的境界更进一层,这个技巧不仅能提高可读性,还能以最小的代价增...
- Python元组编程指导教程(python元组的概念)
-
1.元组基础概念1.1什么是元组元组(Tuple)是Python中一种不可变的序列类型,用于存储多个有序的元素。元组与列表(list)类似,但元组一旦创建就不能修改(不可变),这使得元组在某些场景...
- 你可能不知道的实用 Python 功能(python有哪些用)
-
1.超越文件处理的内容管理器大多数开发人员都熟悉使用with语句进行文件操作:withopen('file.txt','r')asfile:co...
- Python 2至3.13新特性总结(python 3.10新特性)
-
以下是Python2到Python3.13的主要新特性总结,按版本分类整理:Python2到Python3的重大变化Python3是一个不向后兼容的版本,主要改进包括:pri...
- Python中for循环访问索引值的方法
-
技术背景在Python编程中,我们经常需要在循环中访问元素的索引值。例如,在处理列表、元组等可迭代对象时,除了要获取元素本身,还需要知道元素的位置。Python提供了多种方式来实现这一需求,下面将详细...
- Python enumerate核心应用解析:索引遍历的高效实践方案
-
喜欢的条友记得关注、点赞、转发、收藏,你们的支持就是我最大的动力源泉。根据GitHub代码分析统计,使用enumerate替代range(len())写法可减少38%的索引错误概率。本文通过12个生产...
- Python入门到脱坑经典案例—列表去重
-
列表去重是Python编程中常见的操作,下面我将介绍多种实现列表去重的方法,从基础到进阶,帮助初学者全面掌握这一技能。方法一:使用集合(set)去重(最简单)pythondefremove_dupl...
- Python枚举类工程实践:常量管理的标准化解决方案
-
本文通过7个生产案例,系统解析枚举类在工程实践中的应用,覆盖状态管理、配置选项、错误代码等场景,适用于Web服务开发、自动化测试及系统集成领域。一、基础概念与语法演进1.1传统常量与枚举类对比#传...
- 让Python枚举更强大!教你玩转Enum扩展
-
为什么你需要关注Enum?在日常开发中,你是否经常遇到这样的代码?ifstatus==1:print("开始处理")elifstatus==2:pri...
- Python枚举(Enum)技巧,你值得了解
-
枚举(Enum)提供了更清晰、结构化的方式来定义常量。通过为枚举添加行为、自动分配值和存储额外数据,可以提升代码的可读性、可维护性,并与数据库结合使用时,使用字符串代替数字能简化调试和查询。Pytho...
- 78行Python代码帮你复现微信撤回消息!
-
来源:悟空智能科技本文约700字,建议阅读5分钟。本文基于python的微信开源库itchat,教你如何收集私聊撤回的信息。[导读]Python曾经对我说:"时日不多,赶紧用Python"。于是看...
- 登录人人都是产品经理即可获得以下权益
-
文章介绍如何利用Cursor自动开发Playwright网页自动化脚本,实现从选题、写文、生图的全流程自动化,并将其打包成API供工作流调用,提高工作效率。虽然我前面文章介绍了很多AI工作流,但它们...
- Python常用小知识-第二弹(python常用方法总结)
-
一、Python中使用JsonPath提取字典中的值JsonPath是解析Json字符串用的,如果有一个多层嵌套的复杂字典,想要根据key和下标来批量提取value,这是比较困难的,使用jsonpat...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python自定义函数 (53)
- python进度条 (67)
- python吧 (67)
- python字典遍历 (54)
- python的for循环 (65)
- python格式化字符串 (61)
- python串口编程 (60)
- python读取文件夹下所有文件 (59)
- java调用python脚本 (56)
- python操作mysql数据库 (66)
- python字典增加键值对 (53)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python人脸识别 (54)
- python多态 (60)
- python命令行参数 (53)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)