爬虫(四)数据清洗-正则表达式
正则表达式介绍
正则表达式
即,数据筛选的表达方式(匹配)
import re strr = "张三李四王五赵六" pat = "王五" # 正则表达式 rst = re.search(pat,strr) print(rst)
体验-分析《天龙八部》主角到底是谁
import re with open(r"C:\\Users\\Administrator\\Desktop\\tianlong.txt","rb") as f: data = f.read().decode() pat1 = "乔峰" pat2 = "萧峰" pat3 = "乔帮主" pat4 = "段誉" pat5 = "虚竹" n1 = re.findall(pat1,data) n2 = re.findall(pat2,data) n3 = re.findall(pat3,data) n4 = re.findall(pat4,data) n5 = re.findall(pat5,data) print("乔峰出现次数:",len(n1)+len(n2)+len(n3),"段誉出现次数:",len(n4),"虚竹出现次数:",len(n5))
匹配普通字符
原子:正则表达式中实现匹配的基本单位
元字符:正则表达式中具有特殊含义的字符
以普通字符作为原子(匹配一个普通字符)
import re a = "湖南湖北广东广西" pat = "湖北" result = re.search(pat,a) print(result)
匹配通用字符
匹配通用字符
- \w 任意字母、数字、下划线
- \W 和小写w相反
- \d 十进制数字
- \D 除了十进制以外的值
- \s 空白字符
- \S 非空白字符
import re b = "13617054927" part = "\d\d\d\d\d\d\d\d\d\d\d" result = re.search(part,b) print(result)
import re # b = "13617054927" # # part = "\d\d\d\d\d\d\d\d\d\d\d" # # result = re.search(part,b) # # print(result) c1 = "fj2d9fj92jfoejf934jtoerjgfosjgo3u0t34" c2 = "@@@@@@@@2jfoejf934jtoerjgfosjgo3u0t34" part = r"\w\w\w" print(re.search(part,c1)) print(re.search(part,c2))
匹配数字、中文、英文
数字:[0,9]
英文:[A-Z][a-z]
中文:[\u4e00-\u9fa5]
import re # 数字:[0,9] # 英文:[A-Z][a-z] # 中文:[\u4e00-\u9fa5] d = "f920U)F)jf302rk3fkrelgb即300为热裤股票开盘部分的可怕扩容394u093rfj34ofH" part1 = r"[0,9][0,9]" part2 = r"[a-z][a-z]" part3 = r"[\u4e00-\u9fa5][\u4e00-\u9fa5]" result1 = re.search(part1,d) result2 = re.search(part2,d) result3 = re.search(part3,d) print("result1:",result1,"result2:",result2,"result3:",result3)
原子表
原子表:是定义一组平等的原子,这组原子中,只要有一个满足条件那就匹配成功
import re b = "13822748902" part = "1[3572]\d\d\d\d\d\d\d\d\d" # 可以匹配以1开头第二位3、5、7或2的数字 print(re.search(part,b)) c = "djfoejfoj4pychonrj4oj43o9r034" part2 = r"py[abcdt]hon" # 可以匹配以py开头后面a\b\c\d\t当中满足任意一个即可 print(re.search(part2,c))
常用元字符
元字符:正则表达式中具有特殊意义的字符
- · . 匹配任意字符 \n除外
- · ^ 匹配字符串开始的位置 ^136
- · $ 匹配字符串结束的位置 6666$
- · * 重复0次1次多次前面的原子 /d*
- · ? 重复一次或者多次前面的原子 /d?要么有1个数字或者多个数字
- · + 重复一次或多次前面的原子 /d+
import re d = "135594384390909583998883848392" part1 = "..." part2 = "135\d\d\d\d\d\d\d\d" part3 = ".*8392$" part4 = "8*" part5 = "8+" print("part1:",re.search(part1,d)) print("part2:",re.search(part2,d)) print("part3:",re.search(part3,d)) print("part4:",re.search(part4,d)) print("part5:",re.search(part5,d))
匹配固定次数
我们需要元组固定出现多少次
{n} 前面的原子出现了n次
{n,} 至少出现n次
{n,m} 出现次数介于n-m之间
import re a = "2345654jisw" part1 = r"\d{6}" part2 = r"\d{4,}" # 至少4位字符 part3 = r"\S{8,10}" # \S 非空白字符 print(re.search(part1,a)) print(re.search(part2,a)) print(re.search(part3,a))
匹配多个正则表达式
多个表达式 |
import re a = "13409537832" b = "021-8333627" part1 = r"1[3578]\d{9}" part2 = r"\d{3}-\d{7}" part3 = r"1[3578]\d{9}|\d{3}-\d{7}" # 满足两个正则表达式 print(re.search(part1,a)) print(re.search(part2,b)) print(re.search(part3,a)) print(re.search(part3,b))
分组
import re # 分组() a = "jiwdfdjskjfoe#pythonR$Wr2roef2#rjavafdsfe#$@$FSFWFDS13876439027FSF#@$RGFSA@$34" part1 = r"python.{0,}java.{0,}1[3578]\d{9}" part2 = r"(python).{0,}(java).{0,}(1[3578]\d{9})" part3 = r"FDS(.*?)FSF" print(re.search(part1,a)) print(re.search(part2,a).group(1)) # 1表示第一个分组python print(re.search(part2,a).group(2)) # 2表示第一个分组java print(re.search(part3,a).group(1)) # 只获取括号内的电话号码 print(re.findall(part3,a)) # 只获取括号内的电话号码
贪婪模式和非贪婪模式
贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配
非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配
python里默认是贪婪的
import re strr = "aa<div>test1</div>bb<div>test2</div>cc<div>test3</div>dd" part1 = r"<div>.*</div>" part2 = r"<div>.*?</div>" # 加上问好 就是【非贪婪模式】 part3 = r"<div>(.*?)</div>" print(re.search(part1,strr)) # 贪婪模式 print(re.search(part2,strr)) # 非贪婪模式 print(re.findall(part3,strr))
compile函数
compile函数--将正则表达式转换成内部格式,提高执行效率
import re strr = "Python666java" part1 = r"\d+" part2= re.compile(r"\d+") part3= re.compile(r"python",re.I) # re.I模式修正符:忽略大小写 print(re.search(part1,strr)) print(part2.search(strr)) print(part3.search(strr))
match函数和search函数
· match函数-匹配开头
· search函数-匹配任意位置
这两个函数都是一次匹配,就是说匹配到一次就不再匹配了
import re strr = "pythonjavahtmljs" part1 = re.compile(r"python") part2 = re.compile(r"java") print(part1.match(strr)) print(part2.search(strr)) print(part1.match(strr).group())
findall()函数finditer()函数
· findall() 查找所有匹配的内容,装到列表中
· finditer() 查找所有匹配的内容,装到迭代器中
迭代器:可以用for循环取出来
import re strr = r"hello-----------------------------------\------------------\--------hello--hello-----------------hello----------\hello------" part1 = re.compile(r"hello") print(part1.findall(strr)) # findall效率更高一些 data = part1.finditer(strr) list1 = [] for i in data: print(i.group()) list1.append(i.group()) print("list:",list1)
split()函数和sub()函数
· split() 按照能够匹配的子串将字符串分割后返回列表
· sub() sub方法用于替换
import re strr1 = "张三,李四,,,王五,,,,,,赵六" part1 = re.compile(r",+") result1 = part1.split(strr1) print(result1) strr2 = "hello 123,hello 456" part2 = re.compile(r"\d+") result2 = part2.sub("666",strr2) # sub()里传两个参数 print(result2)
爬取网站电话号码
http://changyongdianhuahaoma.51240.com/
import requests import re #构造请求头信息 header={ "User-Agent":"Mozilla/5.0 (Linux; U; An\ droid 8.1.0; zh-cn; BLA-AL00 Build/HUAW\ EIBLA-AL00) AppleWebKit/537.36 (KHTML, l\ ike Gecko) Version/4.0 Chrome/57.0.2987.13\ 2 MQQBrowser/8.9 Mobile Safari/537.36" } url = "http://changyongdianhuahaoma.51240.com/" response = requests.get(url,headers=header).text part1 = r'<tr bgcolor="#EFF7F0">[\s\S]*?<td>(.*?)</td>[\s\S]*?<td>[\s\S]*?</td>[\s\S]*?</tr>' part2 = r'<tr bgcolor="#EFF7F0">[\s\S]*?<td>[\s\S]*?</td>[\s\S]*?<td>(.*?)</td>[\s\S]*?</tr>' pattern1 = re.compile(part1) pattern2 = re.compile(part2) data1 = pattern1.findall(response) data2 = pattern2.findall(response) # print(data1) # print(data2) resultList = [] for i in range(0,len(data1)): resultList.append(data1[i]+data2[i]) print(resultList)
爬取豆瓣电影排行榜
import re import requests import time # 首 页html-url http://movie.douban.com/top250?start=0&filter= # 第2页html-url http://movie.douban.com/top250?start=25&filter= # 第2页html-url http://movie.douban.com/top250?start=50&filter= header = { "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" } resultList = [] for i in range(1,11): url = "http://movie.douban.com/top250?start=" + str((i-1)*25) + "&filter=" response = requests.get(url,headers = header).text part1 = r'<em class="">(.*?)</em>[\s\S]*?<a href="https://movie.douban.com/subject/[\s\S]*?/">[\s\S]*?<img width="100" alt="[\s\S]*?" src' part2 = r'<em class="">[\s\S]*?</em>[\s\S]*?<a href="https://movie.douban.com/subject/[\s\S]*?/">[\s\S]*?<img width="100" alt="(.*?)" src' parttern1 = re.compile(part1) parttern2 = re.compile(part2) data1 = parttern1.findall(response) data2 = parttern2.findall(response) for k in range(0,len(data1)): resultList.append(data1[k]+data2[k]) print(resultList)