协程and正则
迭代器
iter next
生成器
yield 关键字 代码执行到 yield 就会停止
next 进行解阻塞
列表推导式: a = [x for x in range(10)]
生成器表达式:把列表推导式的 [] 改成 ()
生成器函数:加了 yield 的函数
gevent 库
踩的坑:python3.7 版本对这个库不太友好,重新换成 python 3.6.4 的32位版本。
gevent 是对 greenlet 库进行封装,greenlet 是对 yield 关键字进行封装
gevent.sleep() 在协程等待的时候,先去执行下一个任务以此来实现多任务
from gevent import monkey
monkey.patch_all() # monkey 可以把代码中所有的延时换成 gevent
gevent.joinall([]) 推荐这种方式
"""
简单的爬虫,使用协程并发来下载两张斗鱼图片
"""
import urllib.request
import gevent
from gevent import monkey
monkey.patch_all()
def downloader(img_name, img_url):
req = urllib.request.urlopen(img_url)
img_content = req.read()
with open(img_name, "wb") as f:
f.write(img_content)
def main():
gevent.joinall([
gevent.spawn(downloader, "3.jpg",
"https://rpic.douyucdn.cn/appCovers/2017/09/22/1760931_20170922133718_big.jpg"),
gevent.spawn(downloader, "4.jpg",
"https://rpic.douyucdn.cn/appCovers/2017/09/17/2308890_20170917232900_big.jpg")
])
if __name__ == '__main__':
main()
协程
协程依赖于线程,线程依赖于进程。进程消耗资源最大,线程其次,协程最小,
正则
import re
ret = re.match(正则表达式,要匹配的数据)
ret.group() # 提取匹配出来的数据
正则表达式
匹配单个字符
. 匹配任意一个字符,除了 \n
\d 匹配 0-9 的数字
\D 匹配非数字 与\d 相反
[] 匹配 [] 中列举的字符
\w 匹配 0-9 a-z A-Z _ 慎用,可以匹配中文
\W 匹配非 \w
\s 匹配空白,即空格、tab键, \t 表示 tab 键
\S 匹配非空 与\s 相反
匹配多个字符
{m,n} 匹配前一个字符 m-n 次
{m} 匹配前一个字符 m 次
? 匹配前一个字符1次或0次,可有可无 # python 默认贪婪,加 ?变为非贪婪
* 匹配前一个字符0次或任意次,不匹配\n 可以使用模块中的 re.S 模块来忽略\n
+ 匹配枪一个字符 1次或任意次
开头结尾
^ 匹配字符串开头 # [^>] 在 [] 中 ^ 表示非
$ 匹配字符串结尾
匹配分组
| 匹配左边或者右边,表示 或
(ab) 将括号中的字符作为一个分组
\num 引用分组num匹配到的字符串
(?p<name>) 给分组起别名
(?p=name) 引用别名为name的分组取到的字符串
re模块高级用法
re.match() 能够匹配出以xxx开头的字符串
re.search() 能够匹配出包含xxx的字符串
re.findall() 能够找出所有xxx字符串
re.sub() 将匹配到的数据进行替换
re.split() 根据匹配进行切割字符串,并返回一个列表
Python里数量词默认是贪婪的
贪婪:总是尝试匹配尽可能多的字符
非贪婪:总是尝试匹配尽可能少的字符。
在"","?","+","{m,n}"后面加上 ? , 使贪婪变成非贪婪。
r的作用
python中字符串加上 r 表示原生字符串,不需要频繁转义
练习代码
import re
"""判断变量名是否符合要求"""
# 一些变量名
names = ["age", "_age", "1age", "age1", "a_age", "age_1_", "age!", "a#123", "__________"]
for name in names:
# 使用正则来判断是否符合要求
# 只能由字母、数字、下划线组成,不能以数字开头
# 正则以 ^ 开头, $ 结尾
ret = re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", name)
# 判断是否有数据
if ret:
print("%s 变量名符合要求,正则匹配的数据是 %s" % (name, ret.group()))
else:
print("%s 不符合要求" % name)
import re
def email_1():
"""
匹配网易邮箱
qinyifan__123@163.com
命名规范:由 0-9 a-z A-Z _ 组成,不能以数字开头
"""
# 提示输入邮箱
email_str = input("请输入你的邮箱:")
# 正则判断邮箱是否正确
ret = re.match(r"^[a-zA-Z_][0-9a-zA-Z_]{3,19}@163\.com", email_str)
if ret:
print("邮箱 %s 名字合法" % email_str)
else:
print("邮箱 %s 名字不合法" % email_str)
def email_2():
"""
匹配任意邮箱
:return:
"""
# 提示输入邮箱
email_str = input("请输入你的邮箱:")
# 正则判断邮箱是否正确
# ret = re.match(r"^[0-9a-zA-Z_]*@[0-9a-z]{3,5}\.(com|com\.cn|net|org\.cn\.com)", email_str)
ret = re.match(r"^[0-9a-zA-Z_]+@[0-9a-zA-Z]+(\.[a-zA-Z])", email_str)
if ret:
print("邮箱 %s 名字合法" % email_str)
else:
print("邮箱 %s 名字不合法" % email_str)
def phone_1():
"""
匹配座机号码
要求:区号3-4位,号码7-8位,号码和区号之间可有有-号,可以没有
:return:
"""
# 提示输入手机号
phone_num = str(input("请输入你的手机号:"))
# 正则判断
ret = re.match(r"^[\d]{3,4}-?[\d]{7,8}$", phone_num)
if ret:
print("手机号 %s 正确" % phone_num)
else:
print("手机号 %s 不正确" % phone_num)
def phone_2():
"""
匹配尾号不是4和7的手机号
:return:
"""
# 提示输入手机号
phone_num = str(input("请输入你的手机号:"))
# 正则判断
ret = re.match(r"^[0-35-68-9]{11}$", phone_num)
if ret:
print("手机号 %s 正确" % phone_num)
else:
print("手机号 %s 不正确" % phone_num)
def main():
email_1()
email_2()
phone_1()
phone_2()
if __name__ == '__main__':
main()
"""
使用正则判断来爬取一整个网页的图片,简单的爬虫
思路:
1.先打开要爬取的网页,找到网页源代码,保存在 douyu.txt 文件中,
2.进行文件打开操作,使用正则判断得到每个图片地址并且保存在一个列表中
3.遍历得到每个图片地址,使用urllib库取得每个图片的信息,指定路径进行写入操作。
"""
import re
import urllib.request
import gevent
from gevent import monkey
import time
monkey.patch_all()
"""
封装函数
实现一下多任务 失败
"""
def find_img_url():
"""打开存储网页源代码的文件,使用正则得到图片网址列表"""
with open("douyu.txt", "rb") as f:
file = f.read().decode("utf-8")
# print(file)
ret = re.findall(r"https://.*\.jpg", file)
print(ret)
return ret
def download_img(ret):
"""对得到的网址列表进行操作"""
num = 0
for img_url in ret:
num += 1
content = urllib.request.urlopen(img_url)
img = content.read()
with open("./douyu_img/img" + str(num) + ".jpg", "wb") as f:
f.write(img)
print("第 %d 张下载完毕" % num)
print("全部下载完毕")
def main():
# 先调用获取网址列表的函数
ret = find_img_url()
# download_img(ret)
# 创建协程
# g = gevent.spawn(download_img, ret)
# g.join()
gevent.joinall([
gevent.spawn(download_img, ret)
])
if __name__ == '__main__':
main()