正则表达式
匹配单个字符
. 匹配任意一个字符,除了 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()
今天的内容需要记忆的很多,不过也很好玩,爬虫真的是很有趣,不过现在只是实现了简单的爬取图片,而且实验的这两个网址对于图片的反爬机制不是那么好,以后要爬的肯定不是简单的图片,而且也不会那么好爬的,需要再学更多的知识,才能做到想爬什么就爬什么。
爬虫、反爬虫、反反爬虫、一个想爬,一个不让爬,最后变为两个程序员之间的战争,有意思...