正则表达式(下)

正则表达式元字符、预定义字符、重复匹配总结

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+5
      7/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']
  • 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 66,banana price is24'实现分组功能提取66,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级
至此,正则表达式知识点总结完毕,还需多加练习!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容