一.正規表達式文法和re子產品
1.正規表達式的含義
正規表達式,又稱規則表達式,通常被用來檢索,替換那些符合某個模式(規則的文本)
通過正規表達式,從文本字元串中擷取我們想要的特定部分(’ 過濾 ')
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')