Python “爬蟲”出發前的裝備之一正則表達式
1. 正則表達式
正則表達式是一種模板表達式語言
通過定義規則去匹配、查找、替換、分割一個長字符串中特定的子字符信息。
如在一篇文章中查找出所有合法的電子郵箱地址,則可以先用正則表達式定義一個電子郵箱規則,然後再使用這個規則在整個字符串中查找。
爬蟲程序一般都會藉助正則表達式定義的規則在爬出來的內容中做精細化篩檢。
正則表達式有自己獨立於其它計算機語言的語法結構,且大部分計算機編程語言都提供有對正則表達式的支持。如 Java、JavaScript、python……
1.1 正則表達式語法
普通字符匹配規則
普通字符指字母、數字、漢字、下劃線、以及沒有特殊定義的標點符號。正則表達式中的普通字符,在匹配一個字符串的時候,匹配與之相同的一個字符。
如需在 「This is my love」 中匹配 「love」 子字符串,則表達式就是 “love“。
轉義符匹配規則
在正則表達式語法中有很多字符除了其自身意義外,還有語法賦予的特殊意義。如:^、$、?、*……
如在 This is my lo$ve 中匹配出 lo$ve,則表達式不能寫成 lo$ve。默認情況下,正則表達式的語法解析器不會把 $ 其視為其自身含義,而是把它解析成特定的含義(邊界定義)。所以表達式中需使用轉義符 \ 進行轉義。需寫成 lo$ve
另,有些無法輸入的字符也需要通過轉義符進行轉義:
\n | 代表換行符 |
---|---|
\t | 製表符 |
\ | 代表**本身 |
^ ,$,.,(, ) , {****, } , ? , + , * , | ,[, ] | 匹配這些字符本身 |
標準字符集
如果需要在一個字符串中匹配一些具有共同特徵的字符,則可以使用字符集規則,如在一個 Firse 1,Second 2,Three 3……字符串中匹配所有數字或所有空格。
\d | 任意一個數字,****0~9 中的任意一個 |
---|---|
\w | 任意一個字母或數字或下劃線,也就是 AZ,az,0~9,_ 中任意一個 |
\s | 包括空格、製表符、換行符等空白字符的其中任意一個 |
. | 小數點可以匹配任意一個字符 |
Tip: 標準字符集是區分大小寫的
大小寫都能描述特定的字符群體,互為相反關係。如 \d 指任意數字,\D 指除了數字之外的其它字符。
自定義字符集合
用戶可以定義自己的字符集合,用來滿足開發時的特定需要,如在 123456789ABaCbDEcdFG 中查找或匹配奇數和小寫字母。
自定義集合使用 [ ] 來定義。
[ab5@] | 匹配 “a” 或 “b” 或 “5” 或 “@” |
---|---|
[^ abc] | 匹配 a,b,c 之外的任意一個字符 |
[f-k] | 匹配 “f”~”k” 之間的任意一個字母 |
[^A-F0-3] | 匹配 “A”“F”,”0″“3” 之外的任意一個字符 |
正則表達式中的特殊符號,如果被包含於中括號中,則失去特殊意義,但 \ [ ] : ^ – 除外。
比如:[\d.-+],將可以匹配數字,小數點和 + – 符號。(小數點和 + 號失去語法賦予的意義)
修飾匹配次數的特殊符號
{n} | **表達式重複 n次 ** |
---|---|
{m,n} | 表達式至少重複 m 次,最多重複 n 次 |
{m,} | 表達式至少重複 m 次 |
? | 匹配表達式 0 次或者 1 次,相當於 {0,1} |
+ | 表達式至少出現 1 次,相當於 {1,} |
***** | 表達式不出現或出現任意次,相當於 {0,} |
- 貪婪模式:匹配字符越多越好
- 非貪婪模式:匹配字符越少越好,需要在修飾匹配次數的特殊符號後再加上一個 “?” 號
正則表達式的語法相對而言較簡單,可以在使用過程中查閱相關文檔
2. Python 中使用正則表達式
Python 提供有正則表達式模塊,使用時只需要導入即可。
import re
re 模塊中提供了幾個常用方法
- re.match(p,text) 方法:匹配成功則返回一個 Match 匹配對象,匹配不成功則返回一個 None
- re.search(p,text) 方法:在 text 字符串中查找匹配的內容,如果找到則返回第1個匹配的 Match 對象,否則返回None
- re.findall() 方法:在 text 字符串中查找所有匹配的內容。如果找到,返回所有匹配的字符串列表。否則,返回None
- re.sub(p,newstr,oldstr,count=0) 方法:替換匹配的子字符串。返回值是替換之後的字符串
- re.split(p,string,maxsplit=0) 方法: 對字符串進行分割。返回值字符串列表
2.1 re.match 方法
方法原型說明:
import re
re.match(pattern, string, flags=0)
- pattern 正則表達式
- string 要匹配的字符串
- flags 用來控制正則表達式的匹配方式,如是否區分大小寫、多行匹配等
Tip:從字符串起始位置匹配,如果從起始位置匹配不了,就返回 none。
案例一:
import re
m = re.match('www', 'www.baidu.com')
print ("結果: ", m)
print ("起始與終點:", m.span())
print ("起始位置:", m.start())
print ("終點位置:", m.end())
輸出結果:
結果: <re.Match object; span=(0, 3), match='www'>
起始與終點: (0, 3)
起始位置: 0
終點位置: 3
案例二:
import re
line = "You are just the person I want to see"
m = re.match(r'(.*) are (.*?) the', line)
print ("結果:", m)
# groups() 返回匹配的字符列表
for res in m.groups():
print(res)
print("匹配上的完整子字符串",m.group(0))
# 和 groups() 中的結果一致
print("第一個匹配上的字符:",m.group(1))
print("第一個匹配上的字符:",m.group(2))
2.2 re.search 方法
原型說明:
import re
re.search(pattern, string, flags=0)
Tip: re.search 方法的參數語義和 re.match 方法相同
re.match 方法只能從字符串的起始位置進行匹配 ,re.search掃描整個字符串並返回第一個成功的匹配。其它的性質則是一樣的。
案例:
import re
m_match = re.match('baidu', 'www.baidu.com')
m_search = re.search('baidu', 'www.baidu.com')
print ("re.match 輸出結果:",m_match)
print ("re.search 輸出結果:",m_search)
輸出結果
re.match 輸出結果: None
re.search 輸出結果: <re.Match object; span=(4, 9), match='baidu'>
2.3 re.findall 方法
原型說明
import re
re.findall(pattern, string, flags=0)
Tip :re.findall 方法的參數說明和 re.search 相同
- re.search 方法匹配到一個結果後便結束
- re.findall 顧名思義,會找到所有符合規則的匹配項,並以列表類型返回
案例:
import re
#返回 Match 類型
re_match = re.match('[0-9]+', '12345 is the first number, 23456 is the sencond')
#返回 Match 類型
re_search = re.search('[0-9]+', 'The first number is 12345, 23456is the sencond')
# #返回列表類型
re_findall = re.findall('[0-9]+', '12345 is the first number,23456 is the sencond')
print ("re.match:",re_match.group())
print ("re_search",re_search.group())
print ("re_findall:",re_findall)
輸出結果:
re.match: 12345
re_search 12345
re_findall: ['12345', '23456']
2.4 re.sub 方法
方法原型說明:
import re
re.sub(pattern, repl, string, count=0, flags=0)
- pattern是正則表達式
- repl是用於替換的新字符串
- string是即將被替換的舊字符串
- count是要替換的最大數量,默認值為零
import re
p=r'\d+'
text="AB12CD34EF56HK"
replace_text=re.sub(p,' ',text)
print("默認替換所有:",replace_text)
replace_text=re.sub(p,' ',text,count=1)
print("僅替換一次:",replace_text)
replace_text=re.sub(p,' ',text,count=2)
print("僅替換二次:",replace_text)
輸出結果:
默認替換所有: AB CD EF HK
僅替換一次: AB CD34EF56HK
僅替換二次: AB CD EF56HK
2.5 re.split 方法
方法原型說明:
import re
re.split(pattern, string, maxsplit=0, flags=0)
- pattern是正則表達式
- string是要分割的字符串
- maxsplit是最大分割次數。默認值為零,表示分割次數沒有限制
案例:
import re
p = r'\d+'
text = 'AB12CD34EF56GH'
lst = re.split(p, text)
print("默認對整個字符串進行分割:", lst)
lst = re.split(p, text, maxsplit=1)
print("僅分割一次:", lst)
lst = re.split(p, text, maxsplit=2)
print("分割二次:", lst)
輸出結果
默認對整個字符串進行分割: ['AB', 'CD', 'EF', 'GH']
僅分割一次: ['AB', 'CD34EF56GH']
分割二次: ['AB', 'CD', 'EF56GH']
總結
python 提供的 re 模塊中有很多方法可藉助正則表達式方便、快捷地完成字符串的相關操作,對於爬蟲程序來講正則表達式是其不可忽視的一部分。