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模塊中的核心函數。

函數 說明
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函數編譯正則表達式並創建出正則表達式對象無疑是更為明智的選擇。

     匹配字符串的幾個方法

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']

常用正則表達式符號

1、數量詞

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']

2、一般字符串

'.'     默認匹配除\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'))

3、邊界匹配

'^'     匹配以什么字符開頭,多行情況下匹配每一行的開頭
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']

4、預定義字符集合

'\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']

5、分組匹配

'(...)' 分組匹配,把某些規則寫成在一個組里,這樣就可以直接對這個進行一些匹配了,舉個例子的話,如果要匹配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里面的第三個參數,還有其他的模式,但是一般也用不到,就這兩種能用到,別的就不記了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM