python進階(爬蟲正則表示式)
一、正則表示式的基本知識:
1、正則表示式是一種高度專業化的程式語言,並不是只在python語言中存在,而python需要插入 re 模組才能使用 正則表示式。
2、正則表示式只能處理字串,用於模糊匹配。
3、正則表示式的區間是閉區間。
二、正則表示式組成:
1、正則表示式由字符集[...]、量詞(* + ?{ })、邊界(^ $)、邏輯( | )、re模組的函式五部分組成。
2、一個字符集(\d \w 這些也屬於字符集,它們不需要用 [ ] 包裹 )不論有多複雜,在沒有量詞的情況下,只代表一個字元
import re
print(re.findall('\d','234da')) ['2', '3', '4', '5']
print(re.findall('\d\d','234da')) ['23', '45'] 相當於兩個字符集
三、字元組([....]):
①一個字元組只能匹配一個字元,它是一個閉區間。
②字符集內特殊意義的字元大都會失去原有的含義,型別轉義字元 \ 。(轉義字元 \ 和 小括號不會失去含義)
④字元組中的範圍可以相連:[0-9a-zA-Z+_-],中間不需要加逗號分隔,也不要用[[0-9][a-z][A-Z]+_-]這種中間套[]的方式。
⑤字元組中元素見得關係是或的關係,例:[^abc] [^a|b|c]
⑥ ^ 如果在[ ]內部的開頭,代表 非 ,若果在正則表示式開頭,代表匹配必須是 行頭。
常見的字元:
(1)直接匹配:
匹配表示式就是字元本身。
import re
print(re.findall('ab','++=_-aabjab_-=jk'))
['ab', 'ab']
(2)通配字元( . ):
能夠匹配除了換行符(\n)以外的所有字元。
import re
print(re.findall('.','+=_-a | \n *')) # 包括 空格
['+', '=', '_', '-', 'a', ' ', '|', ' ', ' ', '*']
(3)轉義字元(\):
①
import re
print('換行符\n換行了') 轉義字元在print語句中的用法。
print('轉義符\\n轉義了') 轉義了 \n
print(r'raw方法將字串\n轉化為元字元!') \n失去意義,字串前加上 r,就會將轉化為無意義的元字元(raw)。
# 換行符可以直接匹配
print(re.findall('\n','jadj \n ajfkfjjjfj'))
print(re.findall('\\n','jadj \n ajfkfjjjfj')
# 需要轉義(一些在正則表示式中有意義的字元 * ? + 等)
print(re.findall('\+','jad + ajfkfjjjfj'))
print(re.findall('[+]','jad + ajfkfjjjfj')) []可以使特殊字元沒有意義。
print(re.findall('\.','jadj . ajfkfjjjfj'))
print(re.findall('[.]','jadj . ajfkfjjjfj'))
print(re.findall('\[\]','jadj . ajfkfjjj[]fj')) 結果: ['[]'],[]在正則中有意義,需要轉義
print(re.findall('\(\)','jadj . ajfkfjjj()fj')) 結果:['()']
換行符
換行了
轉義符\n轉義了
raw方法將字串\n轉化為元字元!
['\n']
['\n']
['+']
['+']
['.']
['.']
②轉義字元(\)匹配方法:
特殊:
print(re.findall('','ajd')) 結果:['', '', '', '']
轉義字元本身匹配 (未解決問題)
print('ajdjca\\cjijfj') # ajdjca\cjijfj
print('ajdjca\cjijfj') # ajdjca\cjijfj
print(re.findall('a\\\c','ajdjca\cjijfj')) 結果:['a\\c']
print(re.findall('a\\c','ajdjca\cjijfj')) 報錯
③常用方法:
④易錯:
1、 字符集元素之間是 或 的關係。
print(re.findall('[^abc]','123adbc'))
print(re.findall('[^(a|b|c)]','123adbc'))
['1', '2', '3', 'd']
['1', '2', '3', 'd']
2、 字元組中的範圍 直接相連
print(re.findall('[0-9a-c]','12zafc'))
print(re.findall('[[0-9][a-c]]','12zafc'))
print(re.findall('[]]]]','12zafc[0]]]]'))
['1', '2', 'a', 'c']
[]
[']]]']
3、字元:
這種字元可以理解為 字符集[...]的簡寫方式,在沒有量詞的情況下
可以巢狀在字元組中。
一個\d或[...]代表一個字元
import re
print(re.findall('[\d]','16hgdh6'))
print(re.findall('\d','16hgdh6'))
print(re.findall('\d\w','16hgdh6'))
['1', '6', '6']
['1', '6', '6']
['16']
4、中文字元:
一個字符集只能匹配一箇中文字元。 \w 也包括中文字元。
四、數量詞:
① 數量詞只增加其前面 一個字符集的次數,如果要重複多個字符集,應當加入分組(),加入分組以後,findall只會列印分組的內容。如下:
② 預設情況是貪婪匹配。
import re
print(re.findall('ab*','abbbbbbbbbbbdddabba')) ['abbbbbbbbbbb', 'abb', 'a'] 預設貪婪匹配,且只增加前面一個字元。
print(re.findall('ab*?','abbbddda')) ['a', 'a'] 數量詞加 ? 改變貪婪匹配
print(re.findall('(ab)*','abababbbddda')) 結果:['ab', '', '', '', '', '', '', ''],注意其實匹配結果是 ababab,
因為findall只打印 分組的內容。其次由於是 * (0 - 無窮),因此空集也會列印。
for i in re.finditer('(ab)*','abababbbddda'): # 遍歷檢視內容。
print(i.group())
五、邊界匹配:
六、邏輯:
邏輯或可以多個使用: abc | mjk | iop
七、re模組正則表示式的函式:
(1)findall用法:
1、 findall 結果是一個 list,finditer結果是一個迭代物件,可以通過for i in 迭代器 print(i.group()) 遍歷。
2、沒有時返回 空列表,可以用於條件語句當中。
3、pattern可以呼叫其他函式。
(2)raw方法:
import re
print(re.findall('\\n','abc\nmk')) # 轉義
print(re.findall('\\\\n','abc\\nmk'))
print(re.findall(r'\\n',r'abc\nmk')) r 的用法
['\n'] # 換行符
['\\n'] # 普通字元 \n
['\\n'] # 普通字元 \n
(2)match()與search()用法:
兩個都只匹配一次,findall匹配多次。
兩個函式在有匹配成功時會返回一個匹配物件,通過 該物件.group()檢視:
import re
str1 = '123abcfdd1234'
print(re.match('[a-z]{5}',str1))
print(re.match('\d+',str1)) <_sre.SRE_Match object; span=(0, 3), match='123'> 可放在if 語句中。
print(re.match('\d+',str1).group()) 123
兩個函式在匹配失敗時會返回None,因此兩個函式常用 if 條件語句當中。
import re
str1 = '123abcf1234'
print(re.match('1234',str1)) # None
print()
if re.match('1234',str1):
pass
else:
print('字串不是以1234開頭')
if re.search('1234',str1):
print('字串包含1234')
答案:
None
字串不是以1234開頭
字串包含1234
# 例子:
2. 判斷以下字元是否全是中文(中文正則模式[\u4E00-\u9FA5])
str='廣東省廣州市';
import re
str1 = '1回家了嗎,'
str2 = '吃飯了嗎hhh'
if re.search('[^\u4E00-\u9FA5]+',str2): # 注意search與match的區別
print('不是全是中文')
else:
print('全是中文!')
(3)re模組中split、finditer、sub、subn用法:
finditer 有分組時 預設可以遍歷(for 迴圈 加上 .group( )) 所有匹配字元,包括分組。
spilt 不包含分割符 ,
import re
pattern1 = re.compile('\d[a-z]\d')
print(re.split(pattern1,'1a2hjfajh5g678787d833333333'))
print(re.split(pattern1,'1a2hjfajh5g678787d833333333',2)) 分割兩次
['', 'hjfajh', '7878', '33333333']
['', 'hjfajh', '78787d833333333']
sub 、subn(比sub多了計數) 類似於 str.replace() 的用法,把 。。 替換為 。。。,它支援分組引用。
八:分組 () 與組的引用:
分組print不僅僅只有findall,search與match同樣具有。
1、利用分組編號列印組資訊:
分組編號預設是從 1 開始的。
(1) match 與search findall 列印 分組。
import re
str1 = '123456789abcfdd1234'
aaa = re.match('(\d+)(\d+)',str1) # 第一個是貪婪匹配
print(aaa.group())
print(aaa.group(0))
print(aaa.group(1)) # 第一組
print(aaa.group(2)) # 第二組
print(re.findall('(\d+)(\d+)',str1)
123456789
123456789
12345678
9
[('12345678', '9'), ('123', '4')]
2、finditer 列印分組:
預設列印所有匹配資訊
3、sub、subn分組引用:
應用:將電話號碼13811119999變成138****9999
十、 利用分組巧妙連結地址:
1、