python爬蟲之正則表達式和re庫的使用
正則表達式
- 啥是正則表達式
- 用來簡潔表達一組字符串的表達式,簡而言之就是找字符串的規律,用簡短的表達式來替代字符串
- 正則表達式 = 具有相應特徵的字符串
如下圖,顯而易見的開頭是P,後面有相同的若干個Y重複
-
正則表達式一般用在哪裏?
- 編譯程序中的語法分析器(上編譯原理的時候學過)
- 查找或替換一組字符串(一看它的能力就知道)
- 表達文本類型的特徵,用於查找病毒或者判斷入侵等
- 總之作用都比較厲害,關鍵還是從字符串出發
-
正則表達式的使用
- 語法——這就比較枯燥,不用記住,常回來看看就行了
操作符 | 說明 | 實例 |
---|---|---|
. | 表示任何單個字符 | |
[ ] | 字符集,對單個字符給出取值範圍 | [abc]表示a、b、c,[a‐z]表示a到z單個字符 |
[^ ] | 非字符集,對單個字符給出排除範圍 | [^abc]表示非a或b或c的單個字符 |
* | 前一個字符0次或無限次擴展 | abc* 表示 ab、abc、abcc、abccc等 |
+ | 表示一個字符1次或者無限次擴展 | abc+表示abc,abcc,abccc |
? | 表示一個字符0次或者是1次擴展 | abc?表示ab,abc |
| | 邏輯或,左右任選一個都可以 | abc|def 表示abc,def |
{m} | 前一個字符擴展m次 | ab{2}c表示abbc |
{m,n} | 前一個字符擴展m至n次(左閉右閉) | ab{1,2}c表示abc,abbc |
^ | 匹配字符串開頭 | ^abc表示以abc爲開頭的字符串 |
$ | 匹配字符串結尾 | abc$表示以abc爲結尾的字符串 |
() | 分組標記,內部只能使用|操作符 | (abc)表示abc,(abc |
\d | 數字,等價於[0-9] | |
\w | 單詞字符,等價於[A-Z a-z 0 - 9_] |
- 常見的經典的正則表達式
還是挺有意思的,雖然以前基本看不懂
正則表達式 | 實際意義 |
---|---|
^ [A‐Za‐z]+$ | 以26個字母開頭和結尾的字符串 |
^ [A‐Za‐z0‐9]+$ | 由26個字母和數字爲開頭和結尾的字符串 |
^‐?\d+$ | 整數形式的字符串(以負號開頭,並且以若干個數字爲結尾) |
^ [0‐9] * [1‐9][0‐9] * $ | |
[1‐9]\d{5} | 中國境內郵政編碼,6位(開頭是以1到9,後接5個數字) |
[\u4e00‐\u9fa5] | 匹配中文字符(這個完全不知道,屬於拓展吧) |
\d{3}‐\d{8}|\d{4}‐\d{7} | 國內的電話號碼 |
(([1‐9]?\d | 1\d{2} |
python的re庫的使用
- 常用的函數說明
兩種調用方式
- re庫函數,加函數名直接調用
match = re.search(r'[1-9]\d{5}',"BIT 100081")
- 調用compile函數,將正則表達式的文本式,編譯成對應的正則表達式
regex = re.compile(r'[1-9]\d{5}')
regex.search("BIT 1000081")
返回的match對象是啥
- 簡單的說,Match對象是上述函數一次匹配的結果
- 屬性
屬性 | 說明 |
---|---|
match.string | 待匹配的文本 |
match.re | 匹配使用的正則表達式 |
match.pos | 搜索文本的開始位置 |
match.endpos | 搜索文本的結束位置 |
- 方法
方法 | 說明 |
---|---|
match.group(0) | 獲取匹配後的字符串 |
match.start() | 匹配字符串在原始字符串的開始位置 |
match.end() | 匹配字符串在原始字符串中的結束位置 |
match.span() | 返回(開始的位置,結束的位置) |
注意:使用match一定判定一下是否匹配到
然後再逐個對re方法進行講解和示例
- re.search(pattern,string,flags)
- 作用:從頭到尾匹配一個正則表達式,返回第一個匹配到的位置
- pattern:用於匹配的正則表達式,注意一定加上“r”區分常規的字符串.。如:r’[1-9]\d{5}’
- string:待匹配的字符串
- flags:正則表達式使用時的控制標記
代碼:
方式一:
import re
match = re.search(r'[1-9]\d{5}',"BIT 100081")
# 注意:正則表達式之前一定要加上r,以示區分
print(type(match))
print("待匹配的字符串",match.string)
print("正則表達式",match.re)
print("匹配字符串的區間:",match.span())
if match:
print("match匹配的group對象:",match.group(0))
方式二
regex = re.compile(r'[1-9]\d{5}')
match1 = regex.search("BIT 1000081")
if match1:
print(match1.group(0))
- re.match(pattern,string,flags)
- 作用:匹配字符串的開頭,看看是不是符合正則表達式
- 返回match對象
參數 | 作用 |
---|---|
pattern | 用於匹配的正則表達式,注意一定加上“r”區分常規的字符串.。如:r’[1-9]\d{5}’ |
string | 待匹配的字符串 |
flags | 正則表達式使用時的控制標記(跟上面一樣,不講了) |
代碼:
import re
# 方式一
match = re.match(r'[1-9]\d{5}',"BIT 100081")
# 注意:正則表達式之前一定要加上r,以示區分
if match:
print("方式1.match匹配的group對象:",match.group(0))
# 方式二
regex = re.compile(r'[1-9]\d{5}')
match1 = regex.match("BIT 1000081")
if match1:
print("方式2.match匹配的group對象:",match1.group(0))
沒有匹配到,因爲開頭都不是符合正則表達式的字符串
- re.findall(pattern,string,flags)
- 作用:匹配完整字符串,將符合正則表達式的結果保存在列表中,並返回
- 包含所有匹配對象的列表
參數 | 作用 |
---|---|
pattern | 用於匹配的正則表達式,注意一定加上“r”區分常規的字符串.。如:r’[1-9]\d{5}’ |
string | 待匹配的字符串 |
flags | 正則表達式使用時的控制標記(跟上面一樣,不講了) |
代碼:
import re
# 方式一
resList = re.findall(r'[1-9]\d{5}',"BIT 100081,shanghai 200237")
# 注意:正則表達式之前一定要加上r,以示區分
print("方式1.findall匹配的group對象:",resList)
# 方式二
regex = re.compile(r'[1-9]\d{5}')
resList2 = regex.findall("BIT 100081,shanghai 200237")
print("方式1.findall匹配的group對象:",resList2)
- re.split(pattern,string,flags)
- 作用:將字符串按照正則表達式匹配結果進行分割,返回列表
參數 | 作用 |
---|---|
pattern | 用於匹配的正則表達式,注意一定加上“r”區分常規的字符串.。如:r’[1-9]\d{5}’ |
string | 待匹配的字符串 |
maxsplit = 0 | 最大分割數,剩餘部分作爲最後一個元素輸出 |
flags | 正則表達式使用時的控制標記(跟上面一樣,不講了) |
代碼
import re
# 方法一
resList = re.split(r'[1-9]\d{5}','BIT 100081 Shanghai 200237 Jiangsu 221100',maxsplit=1)
print(resList)
# 方法二
regex = re.compile(r'[1-9]\d{5}')
resList1 = regex.split('BIT 100081 Shanghai 200237 Jiangsu 221100')
# 沒有對maxsplit進行說明,那就是指所有匹配的都進行分配
print(resList1)
結果:
- re.finditer(pattern,string,flags)
- 作用:搜索字符串,返回一個匹配結果的迭代類型,每個迭代元素是match對象
參數 | 作用 |
---|---|
pattern | 用於匹配的正則表達式,注意一定加上“r”區分常規的字符串.。如:r’[1-9]\d{5}’ |
string | 待匹配的字符串 |
flags | 正則表達式使用時的控制標記(跟上面一樣,不講了) |
import re
# 方法一
for m in re.finditer(r'[1-9]\d{5}','BIT 100081 Shanghai 200237 Jiangsu 221100'):
if m:
print(m.group(0))
print()
# 方法二
regex = re.compile(r'[1-9]\d{5}')
for m in regex.finditer('BIT 100081 Shanghai 200237 Jiangsu 221100'):
if m:
print(m.group(0))
結果
- re.sub(pattern,string,flags)
- 作用:在一個字符串中所有符合正則表達式的字符串替換成別的字符串
- 返回:替換之後的字符串
參數 | 作用 |
---|---|
pattern | 用於匹配的正則表達式,注意一定加上“r”區分常規的字符串.。如:r’[1-9]\d{5}’ |
repl | 替換匹配的字符串的字符串 |
string | 待匹配的字符串 |
count | 匹配的最大的替換次數 |
flags | 正則表達式使用時的控制標記(跟上面一樣,不講了) |
代碼:
import re
# 方法一
resString = re.sub(r'[1-9]\d{5}',"郵編","BIT 100081 Shanghai200237 Jiangsu 221100")
print(resString)
# 方法二
regex = re.compile(r'[1-9]\d{5}')
resString1 = regex.sub("郵編","BIT 100081 Shanghai200237 Jiangsu 221100")
print(resString1)
結果:
基本上都講完了,但是還有一個注意點
- 當匹配帶長度的字符串時,默認匹配最長的字符串,俗稱貪婪匹配,啥意思?看下圖
>>> import re
>>> match = re.search(r'PY.*N','PYANBNCNDN')
>>> match.group(0)
對於待匹配的字符而言,PYANBNCNDN,其中分別有PTAN,PYANBN,PYANBNCN,PYANBNCNDN字符串都是符合匹配的結果的,python默認是返回最長的
- 但是有的時候,我們想用到最短的匹配字符串怎麼辦?
- 加上“?”,正則表達式中表示對應的字符串出現0次或者是1次擴展
match = re.search(r'PY.*?',"PYANBNCNDN")
print(match.group(0))
結果