Python之并发+网络编程
off999 2024-12-13 15:36 23 浏览 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()
相关推荐
- 让 Python 代码飙升330倍:从入门到精通的四种性能优化实践
-
花下猫语:性能优化是每个程序员的必修课,但你是否想过,除了更换算法,还有哪些“大招”?这篇文章堪称典范,它将一个普通的函数,通过四套组合拳,硬生生把性能提升了330倍!作者不仅展示了“术”,更传授...
- 7 段不到 50 行的 Python 脚本,解决 7 个真实麻烦:代码、场景与可复制
-
“本文整理自开发者AbdurRahman在Stackademic的真实记录,所有代码均经过最小化删减,确保在50行内即可运行。每段脚本都对应一个日常场景,拿来即用,无需额外依赖。一、在朋...
- Python3.14:终于摆脱了GIL的限制
-
前言Python中最遭人诟病的设计之一就是GIL。GIL(全局解释器锁)是CPython的一个互斥锁,确保任何时刻只有一个线程可以执行Python字节码,这样可以避免多个线程同时操作内部数据结...
- Python Web开发实战:3小时从零搭建个人博客
-
一、为什么选Python做Web开发?Python在Web领域的优势很突出:o开发快:Django、Flask这些框架把常用功能都封装好了,不用重复写代码,能快速把想法变成能用的产品o需求多:行业...
- 图解Python编程:从入门到精通系列教程(附全套速查表)
-
引言本系列教程展开讲解Python编程语言,Python是一门开源免费、通用型的脚本编程语言,它上手简单,功能强大,它也是互联网最热门的编程语言之一。Python生态丰富,库(模块)极其丰富,这使...
- Python 并发编程实战:从基础到实战应用
-
并发编程是提升Python程序效率的关键技能,尤其在处理多任务场景时作用显著。本文将系统介绍Python中主流的并发实现方式,帮助你根据场景选择最优方案。一、多线程编程(threading)核...
- 吴恩达亲自授课,适合初学者的Python编程课程上线
-
吴恩达教授开新课了,还是亲自授课!今天,人工智能著名学者、斯坦福大学教授吴恩达在社交平台X上发帖介绍了一门新课程——AIPythonforBeginners,旨在从头开始讲授Python...
- Python GUI 编程:tkinter 初学者入门指南——Ttk 小部件
-
在本文中,将介绍Tkinter.ttk主题小部件,是常规Tkinter小部件的升级版本。Tkinter有两种小部件:经典小部件、主题小部件。Tkinter于1991年推出了经典小部件,...
- Python turtle模块编程实践教程
-
一、模块概述与核心概念1.1turtle模块简介定义:turtle是Python标准库中的2D绘图模块,基于Logo语言的海龟绘图理念实现。核心原理:坐标系系统:原点(0,0)位于画布中心X轴:向右...
- Python 中的asyncio 编程入门示例-1
-
Python的asyncio库是用于编写并发代码的,它使用async/await语法。它为编写异步程序提供了基础,通过非阻塞调用高效处理I/O密集型操作,适用于涉及网络连接、文件I/O...
- 30天学会Python,开启编程新世界
-
在当今这个数字化无处不在的时代,Python凭借其精炼的语法架构、卓越的性能以及多元化的应用领域,稳坐编程语言排行榜的前列。无论是投身于数据分析、人工智能的探索,还是Web开发的构建,亦或是自动化办公...
- Python基础知识(IO编程)
-
1.文件读写读写文件是Python语言最常见的IO操作。通过数据盘读写文件的功能都是由操作系统提供的,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个...
- Python零基础到精通,这8个入门技巧让你少走弯路,7天速通编程!
-
Python学习就像玩积木,从最基础的块开始,一步步搭建出复杂的作品。我记得刚开始学Python时也是一头雾水,走了不少弯路。现在回头看,其实掌握几个核心概念,就能快速入门这门编程语言。来聊聊怎么用最...
- 一文带你了解Python Socket 编程
-
大家好,我是皮皮。前言Socket又称为套接字,它是所有网络通信的基础。网络通信其实就是进程间的通信,Socket主要是使用IP地址,协议,端口号来标识一个进程。端口号的范围为0~65535(用户端口...
- Python-面向对象编程入门
-
面向对象编程是一种非常流行的编程范式(programmingparadigm),所谓编程范式就是程序设计的方法论,简单的说就是程序员对程序的认知和理解以及他们编写代码的方式。类和对象面向对象编程:把...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)