正则表达式元字符、预定义字符、重复匹配总结
import re
def fun(ftn,lst):
for n in lst:
result = re.match(ftn,n)
if result:
print(n,'匹配正确',result.group())
else:
print(n,'匹配不正确')
#匹配.元字符
ftn='p.t'
lst=['python','pacdoc','peade','patonm']
fun(ftn,lst)
运行结果:
python 匹配正确 pyt
pacdoc 匹配不正确
peade 匹配不正确
patonm 匹配正确 pat
#匹配|逻辑或
ftn='p|t'
lst=['python','pacdoc','tpeade','patonm']
fun(ftn,lst)
运行结果:
python 匹配正确 p
pacdoc 匹配正确 p
tpeade 匹配正确 t
patonm 匹配正确 p
#匹配[]字符集一个字符
ftn='p[yt]'
lst=['python','pacdoc','tpeade','ptonmy']
fun(ftn,lst)
python 匹配正确 py
pacdoc 匹配不正确
tpeade 匹配不正确
ptonmy 匹配正确 pt
#转义\.(转义后只是普通的.标点符号)
ftn=r'p\w\.'
lst=['py.thon','pa.cdoc','pes.ade','pt.onmy']
fun(ftn,lst)
运行结果
py.thon 匹配正确 py.
pa.cdoc 匹配正确 pa.
pes.ade 匹配不正确
pt.onmy 匹配正确 pt.
#\w预定义可匹配字符及(m)重复m次以上
ftn=r'p\w{3}'
lst=['python','pacdoc','pe','ptonmy']
fun(ftn,lst)
运行结果
python 匹配正确 pyth
pacdoc 匹配正确 pacd
pe 匹配不正确
ptonmy 匹配正确 pton
#\w预定义可匹配字符及(m,n)重复m次以上n次以下
ftn=r'p\w{3,4}'
lst=['python','pacdoc','pe','ptonmy']
fun(ftn,lst)
运行结果
python 匹配正确 pytho
pacdoc 匹配正确 pacdo
pe 匹配不正确
ptonmy 匹配正确 ptonm
#\w预定义可匹配字符及(m,)重复m次以上
ftn=r'p\w{6,}'
lst=['python','pacdoc5','pe','ptonmy']
fun(ftn,lst)
运行结果
python 匹配不正确
pacdoc5 匹配正确 pacdoc5
pe 匹配不正确
ptonmy 匹配不正确
#.*?
ftn=r'.*?'
lst=['python','pacdoc5','pe','ptonmy']
fun(ftn,lst)
运行结果
python 匹配正确
pacdoc5 匹配正确
pe 匹配正确
ptonmy 匹配正确
re 常用方法
- compile(pattern, flags=0)
用于将字符串形式的正则表达式编译为Pattern模式对象,可以实现更加效率的匹配。
import re
pat = re.compile(r'abc')
result = pat.match('abc123abc456abc789').group()
result1 = pat.search('abc123abc456abc789').group()
result2 = pat.findall('abc123abc456abc789')
result2 = pat.search('abc123abc456abc789').group()
print(result)
s = '<div>abc</div><div>efg</div><div>hij</div>'
pat = re.compile(r'<div>(.*?)</div>')
result = pat.findall(s)
print(result)
运行结果
['abc', 'efg', 'hij']
import re
pat = re.compile(r'Abc',re.I)
result = pat.match('abc123abc456abc789').group()
print(result)
运行结果
abc
总结:re.I 不区分大小写匹配
- search()和match()方法基本上使用一样,区别在于它查找位置不同, search()查找不区分开头字符。
import re
result = re.search(r'abc','afe123abc1r3',re.I).group()
print(result)
运行结果
abc
- findall(pattern, string, flags=0)
作为re模块的三大搜索函数之一,findall()和match()、search()的不同之处在于,前两者都是单值匹配,找到一个就忽略后面,直接返回不再查找了。而findall是全文查找,它的返回值是一个匹配到的字符串的列表。这个列表没有group()方法,没有start、end、span,更不是一个匹配对象,仅仅是个列表!如果一项都没有匹配到那么返回一个空列表
import re
s = '<div>abc</div><div>efg</div><div>hij</div>'
result1 = re.findall(r'<div>(.*?)</div>',s)
print(result1[2])
运行结果
hij
-
split(pattern, string, maxsplit=0, flags=0)
re模块的split()方法和字符串的split()方法很相似,都是利用特定的字符去分割字符串。但是re模块的split()可以使用正则表达式,因此更灵活,更强大
split有个参数maxsplit,用于指定分割的次数- 思路将以下字符串number=4+57/2分割成数字
用findall()方法
number='4+57/2'
result = re.findall(r'[^+*/]',number)
print(result)
['4', '5', '7', '2']
用split()方法
number='4+5*7/2'
result = re.split(r'[+*/]',number)
print(result)
['4', '5', '7', '2']
result1 = re.split(r'[+*/]',number,maxsplit=2)
print(result1)
['4', '5', '7/2']
- 思路将以下字符串number=4+57/2分割成数字
sub(pattern, repl, string, count=0, flags=0)
sub()方法类似字符串的replace()方法,用指定的内容替换匹配到的字符,可以指定替换次数.
import re
str1='i am very good,i am very nice'
result = re.sub('i','I',str1)
print(result)
运行结果
I am very good,I am very nIce
重点部分:分组功能(匹配与提取)
Python的re模块有一个分组功能。所谓的分组就是去已经匹配到的内容再筛选出需要的内容,相当于二次过滤。实现分组靠圆括号(),而获取分组的内容靠的是group()、groups(),其实前面我们已经展示过。re模块里的积个重要方法在分组上,有不同的表现形式,需要区别对待
如下例match方法下取得分组功能应用
import re
s = '<div>abc</div><div>efg</div><div>hij</div>'
result1 = re.match(r'<div>(.*?)</div><div>(.*?)</div><div>(.*?)</div>',s).groups()
print(result1)
result2 = re.match(r'<div>(.*?)</div><div>(.*?)</div><div>(.*?)</div>',s).group(2)
print(result2)
运行结果:
('abc', 'efg', 'hij')
efg
如下例findall方法下取得分组功能应用
import re
s = '<div>abc</div><div>efg</div><div>hij</div>'
result1 = re.findall(r'<div>(.*?)</div>',s)
print(result1)
print(result1[1])
运行结果
['abc', 'efg', 'hij']
efg
思考:将下列字符串'apple price is 24'实现分组功能提取24'
思路一:
import re
str1 = 'apple price is $66,banana price is $24'
result = re.findall(r'.*?(\$\d{2})',str1)
print(result)
['$66', '$24']
思路二:
import re
str1 = 'apple price is $66,banana price is $24'
result = re.match(r'.*?(\$\d{2,}).*?(\$\d{2,})',str1).groups()
print(result)
('$66', '$24')
csv快速入门
- 什么是csv?
是一种常用的文本格式,用以存储表格数据,包括数字或者字符。很多程序在处理数据时都会碰到csv这种格式的文件。python自带了csv模块,专门用于处理csv文件的读取
-
csv模块的使用
- 写入csv文件
[列表法]通过创建writer对象,主要用到2个方法。一个是writerow,写入一行。另一个是writerows写入多行
import csv
headers = ['姓名','性别','年龄']
content = [('李明','男','16'),('李小明','男','26'),('李大 明','男','36'),('李老明','男','46')]
with open('examp.csv','w',encoding='utf-8',newline='')as obj_file:
writer = csv.writer(obj_file)
writer.writerow(headers)
writer.writerows(content)
import csv
headers = ['姓名','性别','年龄']
content = [('李明','男','16'),('李小明','男','26'),('李大 明','男','36'),('李老明','男','46')]
with open('examp.csv','w',encoding='utf-8',newline='')as obj_file:
writer = csv.writer(obj_file)
writer.writerow(headers)
for data in content:
writer.writerow(data)
[字典法]使用DictWriter 可以使用字典的方式把数据写入进去
headers = ('name','age','height')
persons = [
{'name':'笔记本','age':18,'height':175},
{'name':'张同学', 'age': 18,'height':175},
{'name':'杨同学', 'age': 18,'height':175},
]
with open('examp.csv','w',encoding='utf-8',newline='')as obj_file:
writer = csv.DictWriter(obj_file,headers)
writer.writeheader()
writer.writerows(persons)
读取文件
1 通过reader()读取到的每一条数据是一个列表。可以通过下标的方式获取具体某一个值
2 通过DictReader()读取到的数据是一个字典。可以通过Key值(列名)的方式获取数据
with open('persons.csv','r',encoding='utf-8',newline='') as file_obj:
reader = csv.reader(file_obj)
for x in reader:
print(x[2])
with open('persons.csv', 'r', encoding='utf-8', newline='') as file_obj:
Dreader = csv.DictReader(file_obj)
for x in Dreader:
print(x['name'])
爬虫案例总结
- 需求:爬取7天的 天气情况 日期 天气状况温度 风力--> 保存到CSV
- 解决方法:正则表达式解析网页
- URL网址:http://www.weather.com.cn/weather/101250101.shtml
- 检查网页结构,是否是静态网页Elements网页喧染是否与网页源代码一致
<ul class="t clearfix"标签在网页源代码对应的是
···
</ul>
<div id="7d" class="c7d">
<input type="hidden" id="hidden_title" value="04月29日20时 周四 晴 16/32°C" />
<input type="hidden" id="fc_24h_internal_update_time" value="2021042920"/>
<input type="hidden" id="update_time" value="18:00"/>
<ul class="t clearfix">
<li class="sky skyid lv2 on">
<h1>29日(今天)</h1>
<big class="png40"></big>
<big class="png40 n00"></big>
<p title="晴" class="wea">晴</p>
<p class="tem">
<i>16℃</i>
</p>
<p class="win">
<em>
<span title="南风" class="S"></span>
</em>
<i><3级</i>
</p>
<div class="slid"></div>
</li>
···
通过对比发现网页喧染是否与网页源代码一致,所以可以利用正则、xpath对网页进行解析 - 要对网页数据进行解析,首先我们知道<ul class="t clearfix">标签内的内容对应的就是我们要解析的数据,所以利用分组将其匹配提取出来,从而进一步缩小了要解析的范围.
- 7天的数据都在UL标签下级LI标签里,所以我们可以进一步匹配7天的数据
- 通过for语句,得到1天的数据,同时利用分组提取一天所需的元素,并将其放入列表中,同时通过append()得到七天的数据
- 最后利用CSV模块将数据存储到CSV文件中
import re
import csv
import requests
class WeatherSpider():
def __init__(self):
self.headers = {'User-Agent':
'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'}
def Readurlsourse(self,url):
response = requests.get(url,headers= self.headers)
res = response.content.decode('utf-8')
return res
def Parsingpages(self,res):
result = re.match(r'.*?(<ul class="t clearfix">.*?</ul>).*?',res,re.S).group(1)
lis = re.findall(r'<li.*?>.*?</li>',result,re.S)
pat = re.compile(r'<li.*?>.*?<h1>(.*?)</h1>.*?<p.*?>(.*?)</p>.*?<i>(.*?)</i>.*?<i>(.*?)</i>.*?</li>', re.S)
lst_all=[]
for li in lis:
r = pat.match(li)
lst_one = [r.group(1), r.group(2), r.group(3), r.group(4)]
lst_all.append(lst_one)
return lst_all
def Datasave(self,lst_all):
has = ['日期', '天气', '温度', '风力']
with open('weather7day.csv', 'w', encoding='utf-8', newline='') as file_obj:
writer = csv.writer(file_obj)
writer.writerow(has)
writer.writerows(lst_all)
def main(self):
url = 'http://www.weather.com.cn/weather/101250101.shtml'
res = self.Readurlsourse(url)
lst_all = self.Parsingpages(res)
self.Datasave(lst_all)
if __name__ == '__main__':
ws = WeatherSpider()
ws.main()
得到最后结果是:
日期,天气,温度,风力
29日(今天),晴,16℃,<3级
30日(明天),晴,17℃,<3级
1日(后天),多云,18℃,<3级
2日(周日),多云转小雨,21℃,<3级
3日(周一),中雨转大雨,21℃,<3级
4日(周二),小雨转阴,19℃,<3级
5日(周三),阴,18℃,<3级
至此,正则表达式知识点总结完毕,还需多加练习!