3.正则表达式re
正则表达式是对字符串操作的一种逻辑公式,我们使用正则表达式对字符串进行匹配和过滤
优点:灵活,功能性强,逻辑性强
缺点:上手难,一旦上手,会爱上这个东西
正则匹配在线工具
元字符
元字符才是正则表达式的灵魂.
1.字符组
字符组很简单用[]括起来,在[]中出现的内容会被匹配,列如:[abc] 匹配a或b或c
如果字符组中的内容过多还可以使用 - ,列如:[a-z]匹配a-z之间的字母[0-9]匹配所有的阿拉伯数字
2.简单的元字符
. 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线
\s 匹配任意的空白符 \d 匹配数字 \n 匹配一个换行符 \t 匹配一个制表符 \b 匹配一个单词的结尾 ^ 匹配字符串的开始 $ 匹配字符串的结尾 \W 匹配非字母或数字或下划线 \D 匹配非数字 \S 匹配非空白符 a|b 匹配字符a或字符b () 匹配括号内的表达式,也表示一个组 [...] 匹配字符组中的字符 [^...] 匹配除了字符组中字符的所有字符
3.量词
一次性要匹配多个字符就要使用到量词
* 重复零次或更多次 + 重复一次或更多次 ? 重复零次或一次 {n} 重复n次 {n,} 重复n次或更多次 {n,m} 重复n到m次
4.惰性匹配和贪婪匹配
在量词种*,+,{} 都属于贪婪匹配,就是尽可能多的匹配结果
.*?尽可能少的匹配,表示惰性匹配
.*?x的特殊含义 找到下一个x为止
5.分组
正则表达式使用()进行分组
6.转义
在正则表达式中有许多特殊意义的转义字符,比如\n和\s在匹配一次\n,字符串中要写成\\n,正则表达式中要写成\\\\n这样太麻烦了,就需要用到r'\n'这个概念,正则中就可以使用r'\\n'
匹配邮箱
[a-z0-9-_]+@\w+\.[a-z0-9.]+
匹配手机号
1[3456789][0-9]{9}
匹配生日格式(yyyy-MM-dd)
\d{4}(\_|\-|\/)\d{1,2}\1\d{1,2}
re模块
findall 查找所有,返回list
ret = re.findall("\d","baby电话是137") print(ret)
search 会进行匹配,但是如果匹配到了结果就会返回这个结果,没有匹配上就返回None
result = re.search("\d","电话号码") print(result) # print(result.group())
match 只能从字符串的开头进行匹配
result = re.match("\d+",'137电话号码') # print(result) print(result.group())
finditer 和findall差不多,只不过这时返回的是迭代器
ret = re.finditer('\d',"baby123456789") for i in ret: print(i.group())#分组 result = re.finditer("姓名:(?P<name>.*?),爱好:(?P<hobby>.*?)","姓名:宝宝,爱好:女,性格:开朗大方") for el in result: print(el.group("name"),el.group("hobby"))
search和match的区别:
search查找 ,找到的结果就返回 match从头开始匹配
其他操作
# 正则正常操作 result = re.split("\d+","宝宝110来找你了,你收拾收拾去119报道") print(result)#['宝宝', '来找你了,你收拾收拾去', '报道'] #用正则替换 s = re.sub("\d+","__Sb__","宝宝110来找你了,你收拾收拾去119报道") print(s)#宝宝__Sb__来找你了,你收拾收拾去__Sb__报道 s = re.subn("\d+","__Sb__","宝宝110来找你了,你收拾收拾去119报道") #替换了多少次 print(s)#('宝宝__Sb__来找你了,你收拾收拾去__Sb__报道', 2) code = "for i in range(10):print(i)" c = compile(code ,"","exec") exec(c) reg = re.compile(r"\d+") lst = reg.findall("宝宝110来找你了,你收拾收拾去119报道") print(lst) result = re.findall(r"\d+","宝宝110来找你了,你收拾收拾去119报道") print(result) lst = re.findall(r"a(?:\d+)c","a123456c")# 把括号python中的分组变成了原来正则表达式中的分组 print(lst)
findall中的坑
ret = re.findall("www.(baidu|oldboy).com","www.oldboy.com") print(ret)#['oldboy'] ret = re.findall("www.(?:baidu|oldboy).com","www.oldboy.com") print(ret)#['www.oldboy.com']
split中的坑
ret = re.split("\d+","alex2wusir3yuan") print(ret)#['alex', 'wusir', 'yuan'] ret = re.split("(\d+)","alex2wusir3yuan") print(ret)#['alex', '2', 'wusir', '3', 'yuan']
爬取电影天堂
from urllib.request import urlopen import re import json main_url = "https://www.dytt8.net/" reg = re.compile(r'\[<a href="/html/gndy/dyzz/index.html">最新电影下载</a>\]<a href=\'(?P<url>.*?)\'>', re.S) son_reg = re.compile(r'<div id="Zoom">.*?◎片 名(?P<name>.*?)<br />.*?◎主 演(?P<main>.*?)<br />◎简 介.*?<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">', re.S) # 获取主页面内容 def get_main_page(): main_page = urlopen(main_url).read().decode("gbk") # 主页面 it = reg.finditer(main_page) lst = [] for el in it: d = get_son_page(main_url+el.group("url")) lst.append(d) # indent 控制格式 json.dump(lst, open("movie.json", mode="w", encoding="utf-8"), indent=4, ensure_ascii=False) # 获取子页面内容 def get_son_page(son_url): content = urlopen(son_url).read().decode("gbk") it = son_reg.finditer(content) for el in it: return {"name":el.group("name").strip(), "main":el.group("main").strip().replace(" ", "").split("<br />"), "download":el.group("download").strip()} get_main_page()