• 发文
  • 评论
  • 微博
  • 空间
  • 微信

python修炼 - 协程、正则表达式

QYFabc 2019-02-22 17:24 发文

  本文阅读时长大约为13分钟

今日内容概述:

协程、正则表达式

昨日回顾
迭代器

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.requestimport geventfrom gevent import monkeymonkey.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()  # 提取匹配出来的数据

正则表达式

匹配单个字符

.   匹配任意一个字符,除了  d  匹配 0-9 的数字D 匹配非数字   与d 相反[]  匹配 [] 中列举的字符 w  匹配 0-9 a-z A-Z _    慎用,可以匹配中文W  匹配非 ws   匹配空白,即空格、tab键,     表示 tab 键S  匹配非空   与s 相反

匹配多个字符

{m,n}  匹配前一个字符 m-n 次{m}  匹配前一个字符 m 次?  匹配前一个字符1次或0次,可有可无       # python 默认贪婪,加 ?变为非贪婪*     匹配前一个字符0次或任意次,不匹配   可以使用模块中的 re.S 模块来忽略+   匹配枪一个字符 1次或任意次

开头结尾

^  匹配字符串开头       #  [^>]    在 [] 中 ^ 表示非$ 匹配字符串结尾

匹配分组

|  匹配左边或者右边,表示 或(ab)  将括号中的字符作为一个分组um  引用分组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 redef 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 reimport urllib.requestimport geventfrom gevent import monkeyimport timemonkey.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 retdef 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()

小任务:爬取图片,

从给定的网页中写正则取出图片地址,放到列表中

根据过滤出来的链接去网上下载图片,方法 img 文件夹中

给定一个网址,下载其中所有的图片到 image 文件夹中

要求用协程实现

"""实现打开一个网址,从中下载图片"""import urllib.requestimport reimport geventdef get_url():    header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}  # 请求头,来模仿浏览器    # r = urllib.request.Request("https://www.douyu.com/g_yz", headers=header)  # 请求一个网站(斗鱼),将请求头传过去,服务器会返回一个值    r = urllib.request.Request("https://www.huya.com/g/1663", headers=header)  # 虎牙    req = urllib.request.urlopen(r)  # 打开服务器返回的源代码    img_content = req.read().decode("utf-8")  # 将数据保存到一个变量中,  进行解码    # print(img_content)    # 使用正则从网页数据中取出所有的 图片地址并保存到一个列表中    img_all_url = re.findall(r"https://.*?.jpg", img_content)    print(img_all_url)    # img_all_url.pop(0)  # 不知为何斗鱼网站匹配出来的前两个网址是错的,强行进行删除    # img_all_url.pop(0)    # print(img_all_url)    return img_all_urldef download_img(img_url, num):    """对得到的每个图片地址执行下载操作"""    ret = urllib.request.urlopen(img_url)  # 得到每个图片返回的数据    img_content = ret.read()  # 得到每个图片的内容    with open("./douyu_img/huya_img/img" + str(num) + ".jpg", "wb") as f:  # 打开文件时注意路径        f.write(img_content)    print("正在从 %s 下载" % img_url)    print("这是第 %d 张" % num)def main():    # 调用取得所有图片地址的函数    img_all_url = get_url()    # 新建一个 gevent 列表    gevent_list = []    num = 0    for img_url in img_all_url:  # 遍历得到每个图片地址        num += 1        # download_img(img_url, num)  # 调用函数对得到的每个图片内容下载        gevent_list.append(gevent.spawn(download_img, img_url, num))
   # 实现协程    gevent.joinall(gevent_list)if __name__ == '__main__':    main()

今天的内容需要记忆的很多,不过也很好玩,爬虫真的是很有趣,不过现在只是实现了简单的爬取图片,而且实验的这两个网址对于图片的反爬机制不是那么好,以后要爬的肯定不是简单的图片,而且也不会那么好爬的,需要再学更多的知识,才能做到想爬什么就爬什么。

爬虫、反爬虫、反反爬虫、一个想爬,一个不让爬,最后变为两个程序员之间的战争,有意思。。。

END

              

微信搜索公众号【QYFabc】,一起交流学习

声明:本文为OFweek维科号作者发布,不代表OFweek维科号立场。如有侵权或其他问题,请及时联系我们举报。
2
评论

评论

    相关阅读

    暂无数据

    QYFabc

    python 学习分享...

    举报文章问题

    ×
    • 营销广告
    • 重复、旧闻
    • 格式问题
    • 低俗
    • 标题夸张
    • 与事实不符
    • 疑似抄袭
    • 我有话要说
    确定 取消

    举报评论问题

    ×
    • 淫秽色情
    • 营销广告
    • 恶意攻击谩骂
    • 我要吐槽
    确定 取消

    用户登录×

    请输入用户名/手机/邮箱

    请输入密码