正则re

时间:2023-03-09 19:55:16
正则re

1.简介

其实re在基本模块里已经介绍过,但是在爬虫中re是非常重要的,所以在这里再进行详细描述。

re在解析html内容时是效率最高的,但是也是最难的,一般来说,都是结合xpath和re使用,这样解析html文件会事半功倍

2.单个字符串的匹配

#  -*-coding:utf8 -*-

import re
#本节匹配单个字符
#1.匹配某个字符串
# text="hello"
# text2="ahello"
#match只能从开头开始匹配
# ret=re.match('he',text)
#调用group方法,就得得到匹配结果。如果没有匹配到,是None的话,调用group()会报错
# print(ret.group())

#2.点,匹配任意的字符
#可以匹配到空格,但是不能匹配到换行符
# text='hello'
# text2='\n'
# ret=re.match(".",text)
# ret=re.match(".",text2)
# print(ret.group())

#3.\d 匹配任意的数字(0-9)
# text='12'
# ret=re.match("\d",text)
# print(ret.group())

#4.\D 匹配任意的非数字
# text='+'
# ret=re.match("\D",text)
# print(ret.group())

#5.\s,匹配空白字符(\n,\t,\r,空格)
# text=' asd'
# ret=re.match("\s",text)
# print(ret.group())

#6.\w,匹配字母,数字及下划线
# text='_'
# ret=re.match("\w",text)
# print(ret.group())

#7.\W,匹配非字母数字下划线
# text='+()*&^%'
# ret=re.match("\W+",text)
# print(ret.group())

#8.[]组合的方式,只要满足中括号中的字符,就可以匹配
# text='-0731-888888'
#\可以转义有特殊含义的字符
# ret=re.match("[\d\-]+",text)
# print(ret.group())

#group()和groups()的区别
'''
groups()以元组返回所有分组匹配的字符。
group(0)代表整个匹配结果,group(1)列出第一个分组匹配部分,group(2)列出第二个分组匹配部分。
如果没有分组,则调用group(),则可以显示匹配内容。没有分组,使用groups会匹配到空
'''

#8.1 中括号的形式代替\d
# text='0731-888888'
# ret=re.match("[0-9]+",text)
# print(ret.group())

#8.2 中括号的形式代替\D
# text='0731-888888'
# ret=re.match("[^0-9]",text)
# print(ret.group())

#8.3 中括号的形式代替\w
# text='s0731-888888'
# ret=re.match("[a-zA-Z_]",text)
# print(ret.group())

#8.4 中括号的形式代替\W
# text='PW31-888888'
# ret=re.match("[^a-zA-Z_]",text)
# print(ret.group())

3.匹配多个字符

#  -*-coding:utf8 -*-

import re
#9.  * 可以匹配0或任意多个字符
# text='  0731'
# ret=re.match('\d*',text)
# print(ret.group())

#10. + 匹配一个或者多个字符(最少要有一个字符匹配上)
# text='abcd'
# ret=re.match('\w+',text)
# print(ret.group())

#11. ? 匹配一个或者0个字符(要么没有,要么只有一个)
# text='+abcd'
# ret=re.match('\w?',text)
# print(ret.group())

#12. {m},匹配m个字符
# text='abcd'
# ret=re.match('\w{2}',text)
# print(ret.group())

#13. {m,n},匹配m-n个字符
# text='abcd'
# ret=re.match('\w{1,5}',text)
# print(ret.group())

4.多个小案例

#  -*-coding:utf8 -*-

import re

#1.验证手机号码:手机号码的规则是以1开头,第二位可以是34587,后面9位随意
# text='18570662061'
# ret=re.match("1[34578]\d{9}",text)
# print(ret.group())

#2.验证邮箱
# text='hynever123_@qq.com'
# ret=re.match('\w+@[a-z0-9]+\.com',text)
# print(ret.group())

#3.验证URL:URL的规则是前面是http或者是https或者是ftp然后再加上一个冒号,再加上一个斜杠,再后面
# 就是可以出现任意非空白字符了
# text='http://www.baidu.com/s?wd=python'
# ret=re.match('(http|https|ftp)://[^\s]+',text)
# print(ret.group())

#4.验证身份证
text='45621524214712387X'
ret=re.match('\d{17}[\dxX]',text)
print(ret.group())

5.开始、结束、或语法

#  -*-coding:utf8 -*-

import re

#1.^(脱字号)表示匹配以什么开头
# text='hello world'
# ret=re.search('^h',text)
# print(ret.group())
#放在中括号[]中,表示取反

#2. $ 表示以匹配以什么结尾
# text='xxx@163.comasdasdas'
# ret=re.match('\w+@163.com$',text)
# print(ret.group())

#3. | 匹配多个字符串或者表达式
# text='httpsdasda'
# ret=re.match('(ftp|http|https)',text)
# print(ret.group())

#4.贪婪模式与非贪婪模式(默认采用的都是贪婪模式)
# text='0123456'
# ret=re.match('\d+',text)
# print(ret.group())
#想用非贪婪模式,在匹配条件后面加一个问号.这样匹配的就是满足的最小条件
# text='0123456'
# ret=re.match('\d+?',text)
# print(ret.group())

# text='<h1>标题</h1>'
# ret=re.match('<.+>',text)
# ret=re.match('<.+?>',text)
# print(ret.group())

#案例:匹配0-100之间的数字
#可以出现的:0,1,2,3,4,...
#不可以出现的:09,101  (09这种数字写法是不合法的,第一个不能为0)

#有三种情况:1,99,100
text='
ret=re.match('[1-9]\d?$|100$',text)
print(ret.group())

6.转义字符和原生字符串

#  -*-coding:utf8 -*-
import re
#转义字符和原生字符串
'''
在正在表达式中,有些字符是有特殊意义的字符。因此如果想要匹配这些字符,那么就必须使用反斜杠进行转义。
比如$代表的是以...结尾,那么就必须使用\$
'''
# text='apple price is $499'
# ret=re.search('\$\d+',text)
# print(ret.group())

#原生字符串
'''
在正则表达式中,\是专门用来做转义的。在python中\也是用来做转义的。因此如果想要在普通的字符串中
匹配出\,那么要给出4个\。
'''
# text='\c'
#在python语言层面,'\\\\c'经过转义,成了'\\c',然后扔给正则去匹配,又经过转义成了'\c'
# ret=re.search('\\\\c',text)
# print(ret.group())

#在python语言层面,还有一种转义方式,r'\c',这是python自带的转义,r=raw表示原生的意思
#推荐使用这种写法,以免太过复杂
# text='\c'
# ret=re.search(r'\\c',text)
# print(ret.group())

# print('\n')
# print(r'\n')

7.group分组

#  -*-coding:utf8 -*-
import re

#re模块常用函数
#match:从开始的位置进行匹配。如果开始的位置没有匹配到,那就直接失败了

#search:在字符串中找满足条件的字符。如果找到,就返回。说白了,就是只会找到第一个满足条件的

#分组
'''
在正则表达式中,可以通过对过滤到的字符串进行分组。分组使用圆括号的方式
'''

text="apple's price is $99,orange's price is $10"
ret=re.search('.*(\$\d+).*(\$\d+)',text)

#可以打印每个分组里面的内容
# print(ret.group(2))
# print(ret.group(1,2))
#拿到所有的子分组都拿到
print(ret.groups())

#整个正则表达式是一个大的分组,直接用group()或group(0)拿到
# print(ret.group())
# print(ret.group(0))

8.常用函数

#  -*-coding:utf8 -*-

import re

# findall
# 找出所有满足条件的,返回的是一个列表
# text="apple's price is $99,orange's price is $10"
# ret=re.findall('\$\d+',text)
# print(ret)

# sub
# 用来替换字符串。
# text="apple's price is $99,orange's price is $10"
# sub要先传一个匹配条件,再传要修改成的内容,然后传要进行匹配的字符串,再传入count:要修改几个
# count不传个数,则默认全部修改
# ret=re.sub('\$\d+','0',text)
# ret=re.sub('\$\d+','0',text,1)
# print(ret)

# html = """
# <p>服务端研发工程师<br><br>职责:<br><br>负责服务端后台功能的研发,包括Web服务、数据分析统计、运营管理系统。<br><br>要求:<br><br>1. 熟练使用Python及其常用类库<br>2. 熟练使用SQL语言<br>3. 熟悉Linux和MySQL的使用<br>4. 熟悉常用网络协议,譬如HTTP<br><br>加分项:<br><br>1. 热爱技术<br>2. 熟悉Android系统<br>3. 熟悉Java语言</p>
# """
# ret = re.sub('<.+?>', '', html)
# print(ret)

#split
#使用正则表达式来分隔字符串。用什么进行分隔,返回的是一个列表。
# text='hello &world ni hao'
# ret=re.split(' ',text)
# ret=re.split(' |&',text)
# ret=re.split('[^a-zA-Z]',text)
# print(ret)

#compile
#对于一些经常要用到的正则表达式,可以使用compile进行编译,后期再使用的时候可以直接拿过来用,
#执行效率会更快。而且compile还可以指定flag=re.VERBOSE,在写正则表达式的时候可以做好注释

# text='the number is 20.50'
#先写匹配条件。这个正则匹配条件是存放在内存当中,如果是高并发场景,可以用这个
# r=re.compile('\d+\.?\d*')
# ret=re.search(r,text)
# print(ret.group())

#re.VERBOSE     注释功能,省的每次看正则匹配要花时间,直接把注释给上
# text='the number is 20.50'
# r=re.compile(r"""
#             \d+ #小数点前面的数字
#             \.? #小数点本身
#             \d* #小数点后面的数字
#             """,re.VERBOSE)
# ret=re.search(r,text)
# print(ret.group())

9.古诗文网爬虫实战

#  -*-coding:utf8 -*-

import re
import requests

def parse_page(url):
    headers={
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',

    }
    response=requests.get(url,headers=headers)
    text=response.text
    # . 不能匹配\n      如果想要它匹配\n等字符,要加上flags=re.DOTALL
    #re.S=re.DOTALL
    titles=re.findall(r'<div\sclass="cont">.*?<b>(.*?)</b>',text,re.S)
    dynasties=re.findall(r'<p class="source">.*?<a.*?>(.*?)</a>',text,re.DOTALL)
    authors=re.findall(r'<p class="source">.*?<a.*?>.*?<a.*?>(.*?)</a>',text,re.DOTALL)
    content_tags=re.findall(r'<div class="contson".*?>(.*?)</div>',text,re.DOTALL)
    contents=[]
    for content in content_tags:
        x=re.sub(r'<.*?>','',content)
        contents.append(x.strip())
    poems = []
    for value in zip(titles,dynasties,authors,contents):
        title,dynasty,author,content=value
        poem={
            'title':title,
            'dynasty':dynasty,
            'author':author,
            'content':content
        }
        poems.append(poem)
    print(poems)
    #zip函数
    pass

def main():
    url='https://www.gushiwen.org/default_1.aspx'
    parse_page(url)

if __name__ == '__main__':
    main()

10.糗事百科爬虫实战

#  -*-coding:utf8 -*-
import re
import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
}

def parse_page(url):
    response =requests.get(url,headers=headers)
    text=response.text
    authors=re.findall(r'<div class="author clearfix">.*?<h2>(.*?)</h2>',text,re.S)
    authors=[author.strip() for author in authors]
    content_tags=re.findall(r'<div class="content">(.*?)</span>',text,re.S)
    contents=[]
    for content in content_tags:
        x=re.sub(r'<.*?>','',content)
        x=x.replace('\t','')
        x=x.replace('\n','')
        contents.append(x)
    poems=[]
    for value in zip(authors,contents):
        author,content=value
        poem={
            'author':author,
            'content':content
        }
        poems.append(poem)
    return poems

def main():
    urls=['https://www.qiushibaike.com/text/page/{}/'.format(i) for i in range(10)]
    duanzi=[]
    for url in urls:
        poems=parse_page(url)
        duanzi.extend(poems)
    return duanzi
if __name__ == '__main__':
    res=main()
    print(res)
    print(len(res))