《零基礎入門學習Python》筆記 第060講:論一隻爬蟲的自我修養8:正則表達式4
有了前面幾節課的準備,我們這一次終於可以真刀真槍的干一場大的了,但是呢,在進行實戰之前,我們還要講講正則表達式的實用方法和擴展語法,然後再來實戰,大家多把持一會啊。
我們先來翻一下文檔:
首先,我們要舉的例子是講得最多的search() 方法,search() 方法既有模塊級別的,就是直接調用re.search() 來實現,另外,編譯後的正則表達式模式對像也同樣擁有search() 方法,我問問大家,它們之間有區別嗎?
如果你的回答僅僅是模塊級別的search() 方法比模式級別的search() 方法要多一個正則表達式的參數,那你肯定沒有去翻文檔。
re.search(pattern,string,flags = 0)掃描字符串以查找正則表達式模式產生匹配項的第一個位置,然後返回相應的match對象。None如果字符串中沒有位置與模式匹配,則返回;否則返回false。請注意,這不同於在字符串中的某個點找到零長度匹配。
這是模塊級別的search() 方法,大家注意它的參數,它有一個flags 參數, flags 參數就我們上節課講得編譯標誌位,作為一個模塊級別的,它沒辦法複印,它直接在這裡使用它的標誌位就可以了。
pattern 是正則表達式的模式
string 是要搜索的字符串
我們再來看一下如果是編譯後的模式對象,它的search() 方法又有哪些參數:
regex.search(字符串 [,pos [,endpos ]])掃描字符串以查找此正則表達式產生匹配項的第一個位置,然後返回相應的match對象。None如果字符串中沒有位置與模式匹配,則返回;否則返回false。請注意,這不同於在字符串中的某個點找到零長度匹配。可選的第二個參數pos在開始搜索的字符串中給出一個索引;默認為0。這並不完全等同於切片字符串。該'^'模式字符在字符串的真正開始,並在僅僅一個換行符後的位置相匹配,但不一定,其中搜索是啟動索引。可選參數endpos限制將搜索字符串的距離;就像字符串是endpos字符長一樣,因此僅搜索從pos到的字符endpos - 1進行匹配。如果endpos小於pos,則不會找到匹配項;否則,如果rx是已編譯的正則表達式對象,rx.search(string, 0, 50)則等效於rx.search(string[:50], 0)。
前面的pattern, 模式對象的參數,就不需要了。
string 第一個參數就是待搜索的字符串
後面有兩個可選參數是我們模塊級別的search() 方法沒有的,它分別代表需要搜索的起始位置(pos)和結束位置(endpos)
你就可以像
rx.search(string, 0, 50) 或者 rx.search(string[:50], 0) 这样子去匹配它的搜索位置了。
還有一點可能被忽略的就是,search() 方法並不會立刻返回你所需要的字符串,取而代之,它是返回一個匹配對象。我們來舉個例子:
例如:group()方法:
我們就把匹配的內容打印出來了。首先是一個空格,然後是\w+ ,就是任何字符,這裡就是love,然後又是一個空格,然後又是\w+,這裡就是Python。
說到這個group()方法,值的一提的是,如果正則表達式中存在著子組,子組會將匹配的內容進行捕獲,通過這個group()方法中設置序號,可以提取到對應的子組(序號從1開始) 捕獲的字符串。例如:
除了 group()方法之外,它還有start()方法 、end()方法、 span() 方法,分別返回它匹配的開始位置、結束位置、範圍。
match.start([ 組 ])match.end([ 組 ])返回組匹配的子字符串的開始和結束的索引; 組默認為零(表示整個匹配的子字符串)。返回-1如果組存在,但無助於比賽。對於匹配對象米,和一組克這並有助於匹配,則子組由匹配克(相當於m.group(g))是m.string [m.start(g):m.end(g)]請注意,如果group匹配一個空字符串,m.start(group)則等於。例如,after之後,為1,為2,並且均為2,並引發異常。m.end(group)m = re.search('b(c?)', 'cba')m.start(0)m.end(0)m.start(1)m.end(1)m.start(2)IndexError從電子郵件地址中刪除remove_this的示例:>>>電子郵件=“ tony@tiremove_thisger.net” >>> m = re.search(“ remove_this”,電子郵件) >>>電子郵件[:m.start()] +電子郵件[m.end():] 'tony@tiger.net'match.span([ 組 ])對於匹配m,返回2元組(m.start(group), m.end(group))。請注意,如果組沒有為比賽做出貢獻,則為(-1, -1)。組默認為零,即整個匹配。
接下來講講findall() 方法:
re.findall(pattern,string,flags = 0)返回所有非重疊的匹配模式的字符串,如字符串列表。該字符串被掃描的左到右,而比賽的順序返回找到。如果模式中存在一個或多個組,則返回一個組列表;否則,返回一個列表。如果模式包含多個組,則這將是一個元組列表。空匹配項將包括在結果中,除非它們碰到另一個匹配項的開頭。
有人可能會覺得,findall() 方法很容易,不就是找到所有匹配的內容,然後把它們組織成列表的形式返回嗎。
沒錯,這是在正則表達式裡沒有子組的情況下所做的事,如果正則表達式裡包含了子組,那麼,findall() 會變得很聰明。
我們來舉個例子吧,上貼吧爬圖:
例如我們想下載這個頁面的所有圖片:https://tieba.baidu.com/p/4863860271
我們先來踩點,看到圖片格式的標籤:

我們就來直接寫代碼啦:
首先,我們寫下下面的代碼,來爬取圖片地址:
打印的結果為:
很顯然,這不是我們需要的地址,我們需要的只是後面的部分。我們接下來要解決的問題就是如何將裡面的地址提取出來,不少人聽到這裡,可能就已經開始動手了。但是,別急,我這裡有更好的方法。
只需要把圖片地址用小括號括起來,即將:
p = r'<img class =“ BDE_Image” src =“ [^”] + \。jpg“'替換p = r'<img class =” BDE_Image“ src =”([^“] + \。jpg) “',
大家再來看一下運行後的結果:
是不是很興奮,是不是很驚訝,先別急,我先把代碼敲完,再給大家講解。
運行結果,就是很多美眉圖片出現在桌面了(前提是這個程序在桌面運行,圖片自動下載到程序所在文件夾。)
接下來就來解決大家的困惑了:為什麼加個小括號會如此方便呢?
這是因為在findall() 方法中,如果給出的正則表達式是包含著子組的話,那麼就會把子組的內容單獨給返回回來。然而,如果存在多個子組,那麼它還會將匹配的內容組合成元組的形式再返回。
我們還是舉個例子:
因為有時候findall() 如果使用的不好,很多同學就會感覺很疑惑,很迷茫……
初代碼如下:
運行結果如下:
得到的結果讓我們很迷茫,為什麼會這樣呢?這明顯不是我們想要的結果,這是因為我們在正則表達式裡面使用了3 個子組,所以,findall() 會自作聰明的把我們的結果做了分類,然後用元組的形式返回給我們。
那有沒有解決的方法呢?
要解決這個問題,我們可以讓子組不捕獲內容。
讓子組不捕獲內容,擴展語法就是非捕獲組:

所以我們的初代碼修改如下:
運行得到的結果也是我們想要的ip 地址了,如下:
接下來我們又回到文檔:
另外還有一些使用的方法,例如:
finditer() ,是將結果返回一個迭代器,方便以迭代方式獲取數據。
sub() ,是實現替換的操作。
(?=...):前向肯定斷言。
(?!...):前向否定斷言。
(?<=...):後向肯定斷言。
(?<!...):後向肯定斷言。
這些都是非常有用的,但是呢,這些內容有點多了,如果說全部都講正則表達式的話,那我們就是喧賓奪主了,我們主要講的是網絡爬蟲哦。
0 留言:
發佈留言