天天看點

正規表達式文法--&--re子產品

一.正規表達式文法和re子產品

1.正規表達式的含義

正規表達式,又稱規則表達式,通常被用來檢索,替換那些符合某個模式(規則的文本)

通過正規表達式,從文本字元串中擷取我們想要的特定部分(’ 過濾 ')

正規表達式文法--&--re子產品

2.常見的元字元

元字元 含義
^ 比對行首
$ 比對行尾
? 重複比對0次或一次
* 重複比對零次或者更多次
+ 重複比對一次或者更多次
{n} 重複比對n次
{n,} 重複比對n次或者更多次
{n,m} 重複比對n-m次
[a-z] 任意a-z的一個字母
. 比對除\n之外的任意一個字元
\d 比對任意一個數字,相當于[0-9]
\D 比對任意一個非數字,相當于[^0-9]
\w 比對任意一個數字,字母,下劃線
\W 比對任意一個非數字,字母,下劃線
\s 比對任意一個空白,如:\t,\n,\r,空格等
\S 比對任意一個非空白
[] 比對括号中幾個字元非任意一個
[abc] 比對abc中的任意一個字元
[a-z] 比對任意a-z的一個字元
[^123abc] 比對除了123abc這幾個字元以外的任意字元
^[abc] 比對以a/b/c開頭的任意一個字元

3.比對的一些方法

方法 描述
match 從起始位置開始查找,一次比對
search 從任意位置開始查找,一次比對
findall 全部比對,傳回清單
finditer 全部比對,傳回疊代器
split 分割字元串,傳回清單
sub 替換

二.貪婪模式和非貪婪模式

含義

貪婪模式: 在整個表達式比對成功的前提下,盡可能多的比對 (.*)

非貪婪模式: 在整個表達式比對成功的前提下,盡可能少的比對 (.*?)

.

三.案例

1.正則比對

#1.導入re子產品
import re

#2.制定規則
# 使用compile()
# pattern=re.compile()

#定義字元竄
str='123hello789world'

#3.開始比對
#3.1 match('待比對字元串',[起始索引,結束索引])

#注:如果開頭的字元不符合比對規則,直接傳回None
match_pattern=re.compile(r'\d+')
result=match_pattern.match(str)
# result=match_pattern.match(str,8,12)
print(result)    #<re.Match object; span=(0, 3), match='123'>
print(result.group())   #123

#3.2 group() 分組
group_str='123hello123everybody'
# match_pattern=re.compile(r'\d+')
match_pattern=re.compile(r'(\d+)(\w+)(\d+)')
result=match_pattern.match(group_str)
print(result.group())    #123hello123
print(result.group(1))   #123
print(result.group(2))   #hello12
print(result.group(3))   #3

#分組的反向引用
# 注意:反向引用不代表分組,隻是前面分組值的引用
html='<html><h1>helloworld</h1></html>'
pattern=re.compile(r'<(html)><(h1)>(.*)</h1></html>')
result=pattern.match(html)
print(result)
print(result.group())   #<html><h1>helloworld</h1></html>
print(result.group(1))  #html
print(result.group(2))  #h1
print(result.group(3))  #helloworld
print(result.group(4))  # 報錯

# 3.3 span()方法 作用:檢視比對成功的子串的索引範圍
# 支援分組檢視
span_str = '1h2e3lloworld'
pattern = re.compile(r'(\d)h(\d)e(\d)')
result = pattern.match(span_str)
print(result.span())  # (0, 5)
print(result.span(2))  # (2, 3)


# 3.4 search('待比對的字元串'[,起始索引,結束索引])  全局比對,隻比對成功一次
# 如果比對成功,傳回match對象
# 如果開頭不符合比對規則,繼續向下比對
# 直到整個字元串中都沒有找到符合規則的時候,傳回None
search_str = '1h2e3lloworld'
search_str = 'h2e3lloworld'
pattern = re.compile(r'\d')
result = pattern.search(search_str)
print(result) #  <_sre.SRE_Match object; span=(0, 1), match='1'>
print(result.group())


# 3.5 findall()方法   全局比對,和match、search放均不同
# 所有符合條件的子串,全部傳回,傳回的是一個清單,清單中的元素是比對成功的内容
# 清單中元素不是match對象
# 如果沒有符合條件的子串,傳回的是一個空清單
findall_str = '1h2e3lloworld'
findall_str2 = 'helloworld'
pattern = re.compile('\d')
result = pattern.findall(findall_str)
result2 = pattern.findall(findall_str2)
print(result)  # ['1', '2', '3']
print(result2)  # []


# 3.6 finditer()   全局比對  和findall()相似
# 如果比對成功,傳回的是可疊代的對象,可疊代對象中,包含所有比對成功的match對象
finditer_str = '1h2e3lloworld'
pattern = re.compile('\d')
result = pattern.finditer(finditer_str)
# print(result)  # <callable_iterator object at 0x000000000288E710>
for i in result:
    print(i)  # match對象
    print(i.group())


# 3.7 split()  切割方法,傳回清單
# split('待切割的字元串'[,maxsplit])
split_str = 'a,b,c;d e'
pattern = re.compile(r'[,; ]')
result = pattern.split(split_str)
print(result)  # ['a', 'b', 'c', 'd', 'e']

# 可以使用maxsplit指定最大的切割次數
result = pattern.split(split_str,maxsplit=2)
print(result)  # ['a', 'b', 'c;d e']


# 3.8 sub('新的字元串','舊的字元串')   替換方法
# 第一種:直接替換
sub_str = 'hello 123,hello 456'
pattern = re.compile(r'(\w+) (\d+)')
result = pattern.sub('hi world',sub_str)
print(result)  # hi world,hi world


# 第二種:使用函數
# sub('函數名','舊的字元串')
# 對函數的要求:
# 1. 函數必須要有形式參數,參數作用:代表比對到的子串
# 2. 函數必須要有傳回值,傳回值必須是字元串類型,傳回值作用:代表新的字元串
sub_str = 'hello 123,hello 456'
pattern = re.compile(r'(\w+) (\d+)')
def func(m):
    print(m)
    return 'hi ' + m.group(2)
result = pattern.sub(func,sub_str)
print(result)  # hi 123,hi 456



# 3.9 貪婪模式和非貪婪模式
html = '<div>hello</div><div>world</div><div>python</div><div>java</div>'
# 貪婪模式:盡可能多的擷取   .*
pattern = re.compile(r'<div>(.*)</div>')
result = pattern.findall(html)
print(result) # ['hello</div><div>world</div><div>python</div><div>java']

# 非貪婪模式:盡可能少的擷取   .*?
pattern = re.compile(r'<div>(.*?)</div>')
result = pattern.findall(html)
print(result)  # ['hello', 'world', 'python', 'java']


# 爬蟲的萬能表達式:
# .*?(非貪婪模式)  需要配合邊界值使用
# re.compile(r'<邊界>(.*?)</邊界>',re.S)   無敵表達式
# re.S:代表能夠比對到換行
# re.I:代表忽略大小寫


# 3.10 比對中文
# 中文編碼:[\u4e00-\u9fa5]
cn_str = 'hello 你好 world 世界'
pattern = re.compile(r'[\u4e00-\u9fa5]+')
res = pattern.findall(cn_str)
print(res)  # ['你好', '世界']

           

2.貓眼電影資料擷取

需求:

擷取貓眼電影TOP100榜下,所有電影的排名、電影名、主演、上映時間以及評分

#導入子產品
import requests,re
from openpyxl import Workbook

# 執行個體化
wb=Workbook()

ws=wb.active

#增加表頭
ws.append(['排名','電影名','主演','上映時間','評分'])


#前十頁
# https://maoyan.com/board/4?offset=0
# https://maoyan.com/board/4?offset=10
# https://maoyan.com/board/4?offset=20
# https://maoyan.com/board/4?offset=90

#請求頭
headers={
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36',
    'Cookie': '__mta=150426505.1606116724430.1606117565266.1606117568203.9; uuid_n_v=v1; uuid=08EB82C02D5E11EB99C45D5F1D6B3FD73CC5BE51B95B4B94AAA710EBF00F3C1A; _csrf=8fb4ebdaf3ccae31ee526bd29ca8ebe3d23f2aca4ee441202909f5bb492dc01d; Hm_lvt_703e94591e87be68cc8da0da7cbd0be2=1606116724; _lx_utm=utm_source%3Dgoogle%26utm_medium%3Dorganic; _lxsdk_cuid=175f4044e32c8-04430bacb412b9-45410f29-100200-175f4044e32c8; _lxsdk=08EB82C02D5E11EB99C45D5F1D6B3FD73CC5BE51B95B4B94AAA710EBF00F3C1A; __mta=150426505.1606116724430.1606116724430.1606116794282.2; Hm_lpvt_703e94591e87be68cc8da0da7cbd0be2=1606117568; _lxsdk_s=175f4044e33-553-b50-970%7C%7C22'
}

#請求參數
params={}

#制定dd規則
dd_pattern=re.compile(r'<dd>(.*?)</dd>',re.S)

#制定擷取排名規則
num_pattern=re.compile(r'<i class="board-index board-index-\d+">(.*?)</i>')

#制定擷取電影名規則
name_pattern=re.compile(r'<p class="name"><a .*?>(.*?)</a></p>',re.S)

#制定擷取主演規則
star_pattern=re.compile(r'<p class="star">(.*?)</p>',re.S)

#制定上映時間規則
time_pattern=re.compile(r'<p class="releasetime">(.*?)</p>',re.S)

#制定評分規則
score_pattern=re.compile(r'<p class="score"><i class="integer">(.*?)</i><i class="fraction">(.*?)</i></p>',re.S)

for offset in range(0,10):
    params['offset']=offset*10
    #擷取資料
    response=requests.get(url='https://maoyan.com/board/4?requestCode=aef9e9979cb175bc7a3411c975b7304es6gxn',headers=headers,params=params)
    result=response.text
    # print(result)

    # 擷取全部
    dd_list=dd_pattern.findall(result)
    # print(dd_list)
    for i in range(0,10):
        lst=[]
        #擷取排名
        num_list=num_pattern.findall(result)[i]

        #擷取電影名
        name_list=name_pattern.findall(result)[i]

        #擷取主演名
        star_list=star_pattern.findall(result)[i].strip()

        #擷取上映時間
        time_list=time_pattern.findall(result)[i]

        #擷取評分資料
        score_list=score_pattern.findall(result)[i]
        score_list=score_list[0]+score_list[1]
        # lst.append(num_list)
        # lst.append(name_list)
        # lst.append(star_list)
        # lst.append(time_list)
        # lst.append(score_list)
        # ws.append(lst)

        print(num_list,name_list,star_list,time_list,score_list)
# wb.save('貓眼電影TOP100.xlsx')

           

3.股吧資料擷取

#導入子產品
import requests,re
from openpyxl import Workbook

# 股吧網址:https://guba.eastmoney.com/
wb=Workbook()
ws=wb.active
ws.append(['閱讀量','評論','标題','作者','更新時間'])


#請求頭
headers={
    'Cookie': '_adsame_fullscreen_18009=1; st_si=53143075311765; qgqp_b_id=d5a77337368c32115885450aef22d4cd; st_pvi=69749492952227; st_sp=2020-11-23%2023%3A36%3A15; st_inirUrl=https%3A%2F%2Fguba.eastmoney.com%2F; st_sn=36; st_psi=20201123234954591-0-5745969454; st_asi=20201123234954212-117001301773-9755240893-gb_xgbsy_lbqy_qydj-1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest'
}

#請求參數
params={}

#制定規則
gb_pattern=re.compile(r'<ul class="newlist" tracker-eventcode="gb_xgbsy_ lbqy_rmlbdj">(.*?)</ul>',re.S)

#規則2
gb_list1_pattern=re.compile(r'<li.*?>(.*?)</li>',re.S)
# gb_list2_pattern=re.compile(r'<li class="even">(.*?)</li>',re.S)

#制定閱讀,評論,标題,作者,更新時間的規則
cite_pattern=re.compile(r'<cite>(.*?)</cite>',re.S)

#制定标題的規則
title_pattern=re.compile(r'<a .*? title="(.*?)" class="note">.*?</a>',re.S)

#制定作者的規則
author_pattern=re.compile(r'<font>(.*?)</font>',re.S)

#指定更新時間的規則
time_pattern=re.compile(r'<cite class="last">(.*?)</cite>',re.S)

#制定總頁碼規則
page_pattern=re.compile(r'<span class="sumpage">(.*?)</span>')
response=requests.get(url='https://guba.eastmoney.com/default,99_2.html',params=params,headers=headers)
result=response.text

#擷取總頁碼
total_page=page_pattern.findall(result)[0]
print(total_page)

for page in range(1,int(total_page)+1):
    response=requests.get(url=f'https://guba.eastmoney.com/default,99_{page}.html',params=params,headers=headers)
    result=response.text
    # print(result)

    #擷取清單
    gb_list=gb_pattern.findall(result)[0]
    # print(gb_list)

    #擷取li的内容
    gb_list1=gb_list1_pattern.findall(gb_list)
    # print(gb_list1)

    for gb in gb_list1:
        #擷取閱讀,評論的資料
        lst=[]
        cite_list=cite_pattern.findall(gb)
        read_list=cite_list[0].strip()
        comment_list=cite_list[1].strip()

        #擷取标題内容
        title_list=title_pattern.findall(gb)[0]

        #擷取作者資料
        author_list=author_pattern.findall(gb)[0]

        #擷取更新時間的資料
        time_list=time_pattern.findall(gb)[0]

        #儲存資料
        lst.append(read_list)
        lst.append(comment_list)
        lst.append(title_list)
        lst.append(author_list)
        lst.append(time_list)
        print(read_list,comment_list,title_list,author_list,time_list)
        ws.append(lst)
    wb.save('股吧資料.xlsx')