爬蟲必學知識之正則表達式下篇

這是平常學python的第13篇原創文章
php

繼上篇文章說了正則表達式的簡單用法,那今天咱們就繼續說一下正則表達式的複雜的用法。好了,廢話很少說,直接進入正題。
html


正則表達式java

情景:當你想要匹配一個qq號,qq號碼長度爲5-10位,那根據上篇文章的說法,很容易就能夠想到該正則:python

[0-9]{5,10}


這樣是能夠的,可是當你匹配一個長度大於10的號碼時就會出錯,這時就會去該字符串的前10個數字出來,以下:正則表達式

import re
a='221753259265'
r=re.findall('[0-9]{5,10}',a)#明顯當查找的字符串長度大於8位時就會出錯,只會截取前一部分長度
print(r)
# 結果
['2217532592']

這樣的話你就會獲得一個錯誤的qq號碼。c#


這時就須要引入邊界匹配了:微信

  • ^:這個是從左邊開始匹配,規定左邊的首個字符app

  • $:這個是從右邊開始匹配,規定右邊的首個字母python爬蟲

如今再寫個匹配qq號碼的正則函數

r=re.findall('^[0-9]{5,10}$',a)#這個表示從左邊起爲5-10的數字長度,右邊也是同樣
print('第一個匹配結果:',r)
a = '2217532592'
r=re.findall('^[0-9]{5,10}$',a)
print('第二個匹配結果:',r)
# 結果
第一個匹配結果: []
第二個匹配結果: ['2217532592']

這樣就能夠匹配到了,是否是很神奇?


:前面咱們有用 [ ] 來匹配,中括號裏面表示的是或關係,而這裏的組表示的是並關係,而且用小括號括起來 ( )

好比:重複 python 字樣三次

import re
a='pythonpythonpythonjakjpythonpythonsdjjpythonpythonpythonsd'
r=re.findall('(python){3}',a)
print(r)
# 結果
['python', 'python']


這裏的結果不是返回三個python,而是返回這個組,當符合一次就會將此組添加到返回列表中一次。


這個組還挺好用的,再看下這個需求:獲取下列英文中的life和python之間的內容。

a='life is short,i use python'
r=re.findall('life(.*)python',a,re.S)
print(r) # 這樣獲取的就是組內的內容
# 結果
[' is short,i use ']


這個組還經常使用,由於在咱們常常在用正則來解析html元素時,常常須要獲取兩個標籤之間的內容,標籤是肯定的,標籤內容不肯定,就能夠用這個了。以下這個html元素:

<strong><a href="#py2">python進階 </a>
           <a href="#python3">python入門 </a>
       <a href="#vce">vce解決方法 </a>
       <a href="demo06.html#new" target="_blank">百度 </a>
       <a href="mailto: 2217532592@qq.com">反饋意見</a>
       <a href="img/1.jpg">下載圖片 </a>
   </strong>

這樣就能夠用組來獲取a標籤的內容了:<a .*?>(.*?)</a>。?表示非貪婪哦!


re.findall(pattern,string,flags):這個方法的前兩個參數對大家來講都很熟悉了,第一個參數爲正則表達式,第二個參數爲要進行匹配的字符串,而第三個可選參數爲匹配模式,有以下幾種匹配模式:

  • re.I(re.IGNORECASE) :使匹配對大小寫不敏感

  • re.L(re.LOCAL):作本地化識別(locale-aware)匹配

  • re.M(re.MULTILINE):多行匹配,影響 ^ 和 $

  • re.S(re.DOTALL):使 . 匹配包括換行在內的全部字符(這個經常使用)

  • re.U(re.UNICODE):根據Unicode字符集解析字符。這個標誌影響 \w, \W, \b, \B.

  • re.X(re.VERBOSE):該標誌經過給予你更靈活的格式以便你將正則表達式寫得更易於理解


當須要寫多個匹配模式時,能夠用 | 分隔每一個模式

代碼以下:

a='Java12Python89'
r=re.findall('python',a,re.I)
print(r)
a='hsjhj h123jfkksf hajkGH\nkj fjfk'
r=re.findall('.',a,re.I|re.S)
print(r)
# 結果
['Python']
['h', 's', 'j', 'h', 'j', ' ', 'h', '1', '2', '3', 'j', 'f', 'k', 'k', 's', 'f', ' ', 'h', 'a', 'j', 'k', 'G', 'H', '\n', 'k', 'j', ' ', 'f', 'j', 'f', 'k']


正則除了能夠用來檢索字符串,還能夠用來替換字符串,常見的能夠用來替換那些文本中的空格,製表符和回車等,這些都是用一個正則就能夠搞定的了。


python中用這個方法來進行正則替換

re.sub(pattern, repl, string, count=0, flags=0) 

  • pattern :正則表達式

  • repl :替換後的字符串,可爲函數

  • string :要進行替換的字符串

  • count :替換的次數,順序爲 從左往右,默認值爲0,表示無限次。

  • falgs : 匹配模式,和findall()差很少

代碼以下:

import re
a='skjC#ksjfc#jkdsc#'
r=re.sub('c#','gg',a)#返回值是替換後的字符串
print(r)
print(a)
r=re.sub('c#','gg',a,1) # 這個加了替換次數
print(r)
r=re.sub('c#','gg',a,1,re.I) # 加了匹配模式,忽視大小寫
print(r)
# 結果
skjC#ksjfggjkdsgg
skjC#ksjfggjkdsc#
skjggksjfc#jkdsc#


咱們試試第二個參數爲函數的狀況

def convert(value):#他是把對象傳進去這個參數
   print(value)
   #能夠經過group()方法來獲取內容
   return '!!'+value.group()+"!!"
r=re.sub('c#',convert,a,flags=re.I)#接收個參數後,更改後的內容爲他的返回值
print(r)
# 結果
<_sre.SRE_Match object; span=(3, 5), match='C#'>
<_sre.SRE_Match object; span=(9, 11), match='c#'>
<_sre.SRE_Match object; span=(15, 17), match='c#'>
skj!!C#!!ksjf!!c#!!jkds!!c#!!


這個第二個參數爲convert函數,裏面的.group() 方法是獲取匹配後的字符串的值,因此咱們就能夠根據匹配後的字符串來進行相對應的替換內容,好比這個簡單的小需求:

把字符串中的數字大於50的改成99,小於的就改成11。

a='ds+45sd78asd12568asd45asd74ew+9ddf12sd45'
def func(value):
   if int(value.group())>50:
       return '99'
   else:
       return '11'

r=re.sub('\d{1,2}',func,a)
print(r)
# 結果
ds+11sd99asd119911asd11asd99ew+11ddf11sd11


另談兩個函數

  • re.match(pattern,string,flags) :這個是從字符串的首個字母開始匹配,若首個字母不符合,就會返回None, 反之返回一個 Match對象。而他只會匹配第一個結果,不會返回全部符合結果的內容。參數內容與findall()方法同樣。

  • re.search(pattern,string,flags) :這個與match方法差很少,不過不是從首字符開始匹配,也是隻返回一個正確的匹配內容。


代碼:

import re
a='pythonphpjavacphp'
r=re.match('php',a)#這個一開始沒有就返回None
print(r)
r=re.search('php',a)#這個搜索到以後就返回一個對象
#返回的對象能夠經過group()方法來獲取他的內容
print(r)
# 獲取匹配內容
print(r.group())
# 結果
None
<_sre.SRE_Match object; span=(6, 9), match='php'>
php


這兩個函數返回的內容的幾個屬性:

  • group() :獲取匹配的內容

  • statr() :獲取到匹配字符的起始位置

  • end() :獲取匹配到字符的結束位置

  • span() :獲取匹配到字符的起始和結束位置,元組形式返回。


前面提到組的概念,試下這兩個方法的組的用法:

import re
#獲取life和python之間的內容
a='life is short,i use python'
r=re.search('life(.*)python',a,re.S)#用小括號的就是一組
print(r.group(1))#這個下標1就是對應的中間部分

#也能夠獲取中間的兩部分
a='javawoshipythonjunephp'
r=re.search('java(.*)python(.*)php',a)#兩個小括號就是分紅了兩組
print(r.group(1),r.group(2))#分別打印第一第二組
print(r.groups())#這個獲取全部分組信息
# 結果
is short,i use
woshi june
('woshi', 'june')

上面的代碼註釋已經很清楚了,還有個group()方法是獲取整個正則匹配的內容,不按分組。match()方法也同樣,就不演示了。


最後一個問題:怎樣拆分含有多種分隔符的字符串?

好比:kfs;hsji'fhsikf*bhsfk=jsf/shj。要將不屬於字母的都去掉,你是否是會想到用字符串的循環,而後再一個一個分割出來?我告訴你,學了正則以後,不再用這麼麻煩了。re庫裏面有個split()方法,以下:


re.split(pattern, string, maxsplit=0),參數看名字應該就能知道。直接一行代碼進行分割:

a = 'kfs;hsjifhsikf*bhsfk=jsf/shj'
r = re.split('[;*=/]', a)
print(r)
# 結果
['kfs', 'hsjifhsikf', 'bhsfk', 'jsf', 'shj']

是否是很完美?因此說正則必須得學!


END

這個正則複雜點的已經說完了,還有些進階的,不過暫時沒有用到,就不打算說了,須要的能夠去百度看看哈!


留個小練習證實本身正則學得好怎麼樣:

1.kevintian126@126.com 

2. 1136667341@qq.com 

3. meiya@cn-meiya.com 

4. wq901200@hotmail.com 

5. meiyahr@163.com

6. meiyuan@0757info.com 

7. chingpeplo@sina.com 

8. tony@erene.com.com

9. melodylu@buynow.com


用正則把上面的@與com之間的內容匹配出來,能夠把你的答案寫在留言區上,過兩天在留言區公佈答案哈!


上述文章若有錯誤歡迎在留言區指出,若是這篇文章對你有用,點個贊,轉個發如何?


MORE
延伸閱讀

◐◑爬蟲必學知識之正則表達式上篇

◐◑ python爬蟲經常使用庫之requests詳解

◐◑ python使用requests+re簡單入門爬蟲





平常學python

代碼不止bug,還有美和樂趣

本文分享自微信公衆號 - 平常學python(daily_learn)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索