re模块
1.re模块
python中专门操作正则表达式的模块

1.1findall()
将匹配到的所有数据放入列表中
缺点是占内存,一个10G的文件,匹配到8G,那么内存就会被占满,所以一般不用,或者数据很少如下时才使用
正则表达式在python看来就是一个字符串
import re #找到所有匹配到的结果放入列表中 #返回匹配到的元素放到一个列表中,默认为贪婪模式 print(re.findall(r"[a-z]+","asd2fbs4dfa"))
import re ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 #findall正则里面引入分组的目的就是过滤掉虽然匹配到了,但是不想要的数据,所以findall优先显示分组数据,不是分组内数据不显示 ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['www.oldboy.com']
1.2search()
找到一个就返回,返回的是一个对象,需要调用group()可以获得值
一个坑就是,如果没有找到,调用group就会报错,所以要用if判断一下
import re ret = re.search("[a-z]+", "asd2fbs3dfa") print(ret) if ret: print(ret.group())
虽然group()返回一个结果,但是这个结果里面也可能包含不想要的数据
拿到的对象调用group()拿到匹配到的所有结果,而往往匹配到的信息中包含了想要的信息和不想要的信息
把想要的信息用分组包围,然后ret.group(1)拿到第一个分组结果,
因此可以看出,分组在正则里面是对多个规则组合在一起进行约束
分组在python中其实是用来在匹配的数据里面含有不想要的数据的时候,用分组来提取想要的数据
默认group()传的是0是拿到所有的匹配结果,加入1是从匹配结果里面拿到第一个分组里面的内容
import re s= "<a>https://www.baidu.com</a>" #将a标签中间的内容匹配出来 #想要的包含在了不想要的里面 ret = re.search(">(.+)<",s) #0是所有的结果,是默认值,1则是分组的第一个 print(ret.group())#>https://www.baidu.com< print(ret.group(1))#https://www.baidu.com
#这里也引出了爬虫里面的技巧,.*?x将不想要的信息,全部用.*?来匹配,直至找到想要的信息前,用精确的字符x定位到,然后后面就是分组信息,然后把想要的数据提取出来
1.3match()
必须从头开始匹配,相当于正则表达式中隐藏了开头的$,最好别用,就用search(),在里面显示的加$表示从头匹配
1.4使用正则处理字符串,用的不多
import re s= "lsjdfj3lkj1s3lf" #按正则切割字符串放入列表 #如果正则加了分组,那么就会把切掉的内容放回原来的地方 ret = re.split("\d",s) print(ret) ret = re.split("(\d)",s) print("加了分组",ret) #sub使用正则替换,默认替换所有,count控制替换个数 ret = re.sub("\d","你好",s,count=1) print(ret) ##subn,贴心的给你结果,和替换了几次 ret = re.subn("\d","你好",s,count=1) print(ret)
ret=re.split("\d+","eva3egon4yuan") print(ret) #结果 : ['eva', 'egon', 'yuan'] ret=re.split("(\d+)","eva3egon4yuan") print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan'] #在匹配部分加上()之后所切出的结果是不同的, #没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项, #这个在某些需要保留匹配部分的使用过程是非常重要的。
1.5compile()
用户多了之后每次调用都需要将正则表达式编译一次,因为正则定了之后就基本不会变化了,所以可以一次编译,多次被调用
com_pattern = re.compile(r"\d+?")
#编译之后的结果,可以调用re模块中的方法
#因为直接调用re模块中的方法,是调用方法的时候编译,compile只是将编译提前了而已 ret = com_pattern.findall("198h2o34n2) print(ret)
1.6finditer()返回一个迭代器,装有查询结果
每一个迭代的元素就是search的结果
#####finditer节省空间,不会像findall一样将所有结果一次性放入内存 import re #对findall的优化,几千万的结果,慢慢放入内存,是一个迭代器 ret = re.finditer("\d+","laj1232134lsjf234") print(ret) for i in ret:
print(i) print(i.group())
findall拆解步骤
1.先finditer拿到迭代器
2.遍历迭代器,拿到元素,每个元素调用search()方法拿到Match对象
3.然后调用group()拿到需要的数据,放入列表中.
而我们下面的其他方法只不过是进行了拆解
1.7分组命名
为分组起一个名字,下次group的时候直接就可以用名字作为标识,而不是索引了
ret = re.search(">(?P<test>.+)<",s) print("test",ret.group("test")) #使用了分组之后就可以判断标签是否匹配 #前面的分组是一个名字,和后面的分组匹配到的值不一致就会是None s="<a>https://www.baidu.com</b>"
#第一个分组起名为test,后面可以直接使用这个分组的名字,标识和前面的匹配结果必须相同,不相同就是没有匹配上 pattern = "<(?P<test>\w+)>(.+)</(?P=test)>" ret = re.search(pattern,s) print("分组命名,判断标签匹配",ret)
2.爬虫实例
爬虫基本步骤:
1.发出请求:自带urllib模块,后期用requests更加方便,文件头等字段更加形象的模拟浏览器行为
2.获得响应:
3.提取数据:re模块加正则
4.存储数据:文件操作,或者数据库操作
1 import requests 2 import re 3 import json 4 5 #从网页获取数据 6 def get_response(url): 7 resp = requests.get(url) 8 return resp.text 9 10 def parse_data(data): 11 pattern = '<div class="item">.*?<em.*?>(?P<id>\d+).*?<span.*?>(?P<title>.*?)</span>.*?<span class="rating_num".*?>(?P<score>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>' 12 compiled = re.compile(pattern,re.S) 13 result = compiled.finditer(data) 14 for i in result: 15 #循环一次拿到一个网页里面的所有电影信息,存放到一个字典中 16 #一个网页会产生10个字典 17 yield { 18 "id":i.group("id"), 19 "title":i.group("title"), 20 "score":i.group("score"), 21 "comment_num":i.group("comment_num") 22 } 23 24 #构造url 25 def main(num): 26 url = "https://movie.douban.com/top250?start=%s&filter="%num 27 data = get_response(url) 28 #拿到一个网页10个字典信息 29 msgs = parse_data(data) 30 with open("top250.info","a",encoding="utf8") as f: 31 for msg in msgs: 32 print(msg) 33 str_msg = json.dumps(msg,ensure_ascii=False) 34 f.write(str_msg+"\n") 35 36 if __name__ == "__main__": 37 count = 0 38 for i in range(10): 39 main(count) 40 count+=25

浙公网安备 33010602011771号