python爬蟲之正則表達式

字符串是咱們在編程的時候很經常使用的一種數據類型,檢查會在字符串裏面查找一些內容,對於比較簡單的查找,字符串裏面就有一些內置的方法能夠處理,對於比較複雜的字符串查找,或者是有一些內容常常變化的字符串裏面查找,那麼字符串內置的查找方法已經很差使了,知足不了咱們的要求,這個時候就得用正則表達式了,正則表達式就是用來匹配一些比較複雜的字符串。python

 關於正則表達式的相關知識,你們能夠閱讀一篇很是有名的博客叫《正則表達式30分鐘入門教程》,讀完這篇文章後你就能夠看懂下面的表格,這是咱們對正則表達式中的一些基本符號進行的扼要總結。正則表達式

符號 解釋 示例 說明
. 匹配任意字符 b.t 能夠匹配bat / but / b#t / b1t等
\w 匹配字母/數字/下劃線 b\wt 能夠匹配bat / b1t / b_t等
但不能匹配b#t
\s 匹配空白字符(包括\r、\n、\t等) love\syou 能夠匹配love you
\d 匹配數字 \d\d 能夠匹配01 / 23 / 99等
\b 匹配單詞的邊界 \bThe\b  
^ 匹配字符串的開始 ^The 能夠匹配The開頭的字符串
$ 匹配字符串的結束 .exe$ 能夠匹配.exe結尾的字符串
\W 匹配非字母/數字/下劃線 b\Wt 能夠匹配b#t / b@t等
但不能匹配but / b1t / b_t等
\S 匹配非空白字符 love\Syou 能夠匹配love#you等
但不能匹配love you
\D 匹配非數字 \d\D 能夠匹配9a / 3# / 0F等
\B 匹配非單詞邊界 \Bio\B  
[] 匹配來自字符集的任意單一字符 [aeiou] 能夠匹配任一元音字母字符
[^] 匹配不在字符集中的任意單一字符 [^aeiou] 能夠匹配任一非元音字母字符
* 匹配0次或屢次 \w*  
+ 匹配1次或屢次 \w+  
? 匹配0次或1次 \w?  
{N} 匹配N次 \w{3}  
{M,} 匹配至少M次 \w{3,}  
{M,N} 匹配至少M次至多N次 \w{3,6}  
| 分支 foo|bar 能夠匹配foo或者bar
(?#) 註釋    
(exp) 匹配exp並捕獲到自動命名的組中    
(?<name>exp) 匹配exp並捕獲到名爲name的組中    
(?:exp) 匹配exp可是不捕獲匹配的文本    
(?=exp) 匹配exp前面的位置 \b\w+(?=ing) 能夠匹配I'm dancing中的danc
(?<=exp) 匹配exp後面的位置 (?<=\bdanc)\w+\b 能夠匹配I love dancing and reading中的第一個ing
(?!exp) 匹配後面不是exp的位置    
(?<!exp) 匹配前面不是exp的位置    
*? 重複任意次,但儘量少重複 a.*b
a.*?b
將正則表達式應用於aabab,前者會匹配整個字符串aabab,後者會匹配aab和ab兩個字符串
+? 重複1次或屢次,但儘量少重複    
?? 重複0次或1次,但儘量少重複    
{M,N}? 重複M到N次,但儘量少重複    
{M,}? 重複M次以上,但儘量少重複    

**說明:**若是須要匹配的字符是正則表達式中的特殊字符,那麼可使用\進行轉義處理,例如想匹配小數點能夠寫成\.就能夠了,由於直接寫.會匹配任意字符;同理,想匹配圓括號必須寫成和,不然圓括號被視爲正則表達式中的分組。編程

 

     在python中,若是使用正則表達式的話,須要導入re模塊,re模塊是一個內置模塊,直接import就可使用,下面是re模塊中的核心函數。json

函數 說明
compile(pattern, flags=0) 編譯正則表達式返回正則表達式對象
match(pattern, string, flags=0) 用正則表達式匹配字符串 成功返回匹配對象 不然返回None
search(pattern, string, flags=0) 搜索字符串中第一次出現正則表達式的模式 成功返回匹配對象 不然返回None
split(pattern, string, maxsplit=0, flags=0) 用正則表達式指定的模式分隔符拆分字符串 返回列表
sub(pattern, repl, string, count=0, flags=0) 用指定的字符串替換原字符串中與正則表達式匹配的模式 能夠用count指定替換的次數
fullmatch(pattern, string, flags=0) match函數的徹底匹配(從字符串開頭到結尾)版本
findall(pattern, string, flags=0) 查找字符串全部與正則表達式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0) 查找字符串全部與正則表達式匹配的模式 返回一個迭代器
purge() 清除隱式編譯的正則表達式的緩存
re.I / re.IGNORECASE 忽略大小寫匹配標記
re.M / re.MULTILINE 多行匹配標記

**說明:**上面提到的re模塊中的這些函數,實際開發中也能夠用正則表達式對象的方法替代對這些函數的使用,若是一個正則表達式須要重複的使用,那麼先經過compile函數編譯正則表達式並建立出正則表達式對象無疑是更爲明智的選擇。sublime-text

     匹配字符串的幾個方法緩存

import re
s='chenshifeng is a good boy'
print(re.match('chen',s))
#match方法接收3個參數,第一個是匹配的規則,也就是正則表達式,第二個是要查找的字符串,
#第三個參數不是必填的,用於控制正則表達式的匹配方式,看下面正則表達式的匹配模式。是從字符串的第一個單詞中匹配字符串,若是匹配到返回一個對象,若是匹配不到,則返回None
#>>> <_sre.SRE_Match object; span=(0, 4), match='chen'>
print(re.search('feng',s))
#search方法的參數和match同樣,和match方法不同的是,match是從字符串裏面的第一個單詞裏面找,而search方法則是從字符串的整個內容裏面找,若是找到了就返回第一個,找不到就返回None
#>>> <_sre.SRE_Match object; span=(7, 11), match='feng'>
print(re.findall('feng',s))
#findall方法的參數上面的match、search同樣,和他們不同的是,findall會返回全部一個list,把全部匹配到的字符串,放到這個list裏面,若是找不到的話,就返回一個空的list
#>>> ['feng']
print(re.sub('chen','Chen',s))
#sub方法和字符串的replace方法同樣,是用來替換字符串的,把匹配到的值替換成一個新的字符串,接收3個參數,第一個是正則表達式,第二個是要替換成什麼,第三個就是要查找的字符串,會返回一個新的字符串,若是匹配不到的話,返回原來的字符串
#>>> Chenshifeng is a good boy
print(re.split('is',s))
#split 方法和字符串的split方法同樣,是用來分割字符的,按照匹配到的字符串進行分割,返回的是一個list,若是匹配不到的話,那返回的list中仍是原來的字符串
#>>> ['chenshifeng ', ' a good boy']

經常使用正則表達式符號

一、數量詞xss

import re

str1="87alalsdkj34878273\nalkjsldkjfalsdjalksd2klajlfkasjlkdf"

#"*" 匹配0次或者屢次前面出現的正則表達式
print(re.findall("al*",str1))   #等價於al|a
#結果:['al', 'al', 'al', 'al', 'al', 'a', 'a']

# 「+」匹配前面出現的正則表達式一次或者屢次
print(re.findall("al+",str1)) #等價於「al」
#結果['al', 'al', 'al', 'al', 'al'],

# 「?」匹配0次或者一次前面出現的正則表達式
print(re.findall("al?",str1))
#結果:['al', 'al', 'al', 'al', 'al', 'a', 'a']

# {n}匹配前出現的正則表達式n次
print(re.findall("[0-9]{2}",str1))
#結果:['87', '34', '87', '82', '73']

# {n,m}匹配前出現的正則表達式n到m次
print(re.findall("[0-9]{2,3}",str1))  #二者都滿知足時,值去最大的匹配
#結果:['87', '348', '782', '73']

二、通常字符串函數

'.'     默認匹配除\n以外的任意一個字符
print(re.findall(r'b.','besttest is good'))
'[....]',字符集合,
>>> ['be']
>>> ['st', 'st', 's', 'st']
'\'   轉譯符,前面的* + ?這樣的字符都有特殊含義了,若是你想就想找它的話,那就得轉譯了
意思就是說若是你想讓特殊字符失去之前的含義,那麼就得給它前面加上\
print(re.findall(r'\?','besttest is best????'))
>>> ['?', '?', '?', '?']
'|'     匹配|左或|右的字符
print(re.findall(r'best|is','besttest is best'))
>>> ['best', 'is', 'best']
'[]' 字符集合,某些字符的集合,匹配的時候是這個集合裏面的任意一個就行
print(re.findall(r'be[stacj]','besttest is best bejson'))
>>>['bes', 'bes', 'bej']
在[]裏面若是用^的話表明取反,也就是不包括的這些字符串的
print(re.findall(r'be[^stac]','besttest is best bejson'))

三、邊界匹配atom

'^'     匹配以什麼字符開頭,多行狀況下匹配每一行的開頭
print(re.findall(r'^b','besttest is good'))
>>> ['b']
print(re.findall(r'^b','besttest is good\nbest',re.M))#多行模式
>>> ['b','b']
'$'     匹配以什麼字符結尾,多行狀況下匹配每一行的結尾
print(re.findall(r'd$','besttest is good'))
>>> ['d']
print(re.findall(r'd$','besttest is good\nbest is good',re.M<span style="line-height:1.5;">))#多行模式</span> >>>['d','d']
'\A' 僅以什麼字符開頭,和^不一樣的是它不能用多行模式
print(re.findall(r'\Ab','besttest is good'))
>>> ['b']
'\Z' 僅以什麼字符結尾,和$不一樣的是它不能用多行模式
print(re.findall(r'd\Z','besttest is good'))
>>> ['d']

四、預約義字符集合spa

'\d'  匹配數字0-9
print(re.findall(r'\d+','sdf2342312sdfs'))
>>> ['2342312']
'\D'    匹配非數字
print(re.findall(r'\D','sdf2342312sdfs'))
>>>['sdf', 'sdfs']
'\w'    匹配[A-Za-z0-9],也就是全部的字母和數字
print(re.findall(r'\w','sdf234%^2312sdfs&'))
>>>['sdf234', '2312sdfs']
'\W' 匹配不是[A-Za-z0-9],也就是否是字母和數字
print(re.findall(r'\W','sdf234%^2312sdfs&'))
>>>['%', '^', '&']
'\s' 匹配空白字符、\t、\n、\r,空格
print(re.findall('\s','axss\n\tsdf\t\r\t'))
>>> ['\n', '\t', '\t', '\r', '\t']
'\S'匹配空白字符,不是\t、\n、\r,空格
print(re.findall('\s','axss\n\tsdf\t\r\t'))
>>>['\n', '\t', '\t', '\r', '\t']

五、分組匹配

'(...)' 分組匹配,把某些規則寫成在一個組裏,這樣就能夠直接對這個進行一些匹配了,舉個例子的話,若是要匹配ip地址的話
ip地址是相似這樣的192.168.5.1,每一位都是1位或者3位的數字而後後面有個點正常寫的話,得這麼寫
print(re.findall(r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}',"192.168.1.3"))
>>> ['192.168.1.3']
這樣寫的話,有點麻煩了,經過上面的咱們能夠發現規律,除了第一個後面的全都是'.\d{1,3}',寫重複的代碼就是低級的,這樣的話就能夠用分組了
就把'.\d{1,3}'當作一個總體,而後讓他們出現3次就ok了,能夠改爲下面這樣的
print(re.search(r'\d{1,3}(.\d{1,3}){3}',"192.168.1.3").group())這個是用search方法的,結果和上面的同樣的
>>> 192.168.1.3
print(re.findall(r'\d{1,3}(.\d{1,3}){3}',"192.168.1.3"))我們繼續用findall方法,發現結果是下面的
>>> ['.3']
爲啥會這樣呢,用match方法和search方法都是正常的,findall方法這裏有個坑,就是若是findall方法裏面有分組的話,那結果就只是分組裏面的內容
,若是想讓結果正確的話就在分組最前面寫上'?:',一個問號和一個冒號就行了,啓用「不捕捉模式」
print(re.findall(r'\d{1,3}(?:.\d{1,3}){3}',"192.168.1.3"))
這麼寫結果就對了

正則表達式匹配模式

 正則匹配模式是用在match、search、findall裏面的第三個參數,還有其餘的模式,可是通常也用不到,就這兩種能用到,別的就不記了

相關文章
相關標籤/搜索