1. 程式人生 > >爬蟲第三課:正則表示式

爬蟲第三課:正則表示式

  • Regular expression 正則表示式

正則表示式可以非常簡潔的表達一組很長字串的特徵,所以把正則表達說成一行勝千言。
可以把一組字串的特徵或特點表達出來。
比如說有一組字串:
無窮多個以L開頭後面有一個或無窮多個H字串。
‘LH’
‘LHH’
‘LHHH’

‘LHHHHHHH…’
正則表示式: LH+

‘PY’開頭,後續存在不多於10個字元,後續字元不能是‘P’或‘H’
這樣的字元有很多,但是如果我們列舉的話會很麻煩,所以可以用正則表示式來表示這組字串的特點:PY[^PY]{0,10}

所以可以總結來說正則表示式是通用的字串的表達框架,簡潔表達一組字串的表示式,針對字串表達“簡潔”和“特徵”思想的工具,判斷某字串的特徵歸屬。

  • 正則表示式語法
操作符 說明 例項
. 表示任何單個字元
[] 字符集,對單個字元給出取值範圍 [a,b,c]表示a,b,c,[a-z]表示a到z單個字母
[^ ] 非字符集,對單個字元給出排除範圍 [^abc] 表示非a或b或c的單個字元
* 前一個字元0次或無限次擴充套件 abc*表示ab,abc,abcc,abccc等
+ 前一個字元1次或無限次擴充套件 abc+表示abc,abcc,abccc等
? 前一個字元1次或1次擴充套件 abc?表示ab,abc
| 左右表示式任意一個 abc|def表示abc或def
{m} 擴充套件前一個字母m次 ab{2}c表示abbc
{m,n} 擴充套件前一個字母m次至n次 ab{1,2}c表示 abc、abbc
\d 數字,等價於[0-9]
\w 單詞字元 等價於[A-Za-z0-9]
  • 如何用正則表示式提取資料
    工具:re
    正則表示式需要使用re模組中的findall函式。模組就是封裝了許多相似功能函式的包,使用模組中的函式時需要先呼叫這個模組(import + 模組名),然後才能使用裡面的函式。
import re 
data='a1b88888a2b000000a3b00323' 
result1=re.findall('a(.*?)b',data,re.S)     #提取a、b之間的數字
result2=re.findall('b(.*?)a2',data,re.S)   #提取數字88888
#執行結果:
result1=['1','2','3']
result2=['88888']

Findall函式第一個引數是提取的規則,括號內的是我們提取的內容,正則表示式根據括號前後的字元來定位提取資料的位置,括號所在位置代表我們所要提取的資訊所在的位置然後用“(.*?)”代替。第二個引數是提取的物件,第三個引數的作用是可以換行匹配,正則表示式中,“.”的作用是匹配除“\n”以外的任何字元,也就是說,它是在一行中進行匹配。如果不使用re.S引數,則只在每一行內進行匹配,如果一行沒有,就換下一行重新開始,不會跨行。而使用re.S引數以後,正則表示式會將這個字串作為一個整體,將“\n”當做一個普通的字元加入到這個字串中,在整體中進行匹配。
上面的例子是一次提取一個元素,那麼我來看一下如何一次提取兩個元素:

import re 
data='a1b1c---a2b2c---a3b3c---' #提取a、b、c之間的數字
result=re.findall('a(.*?)b(.*?)c',data)
print(result)

#結果
[('1', '1'), ('2', '2'), ('3', '3')]

上面就是一次提取兩個元素,這兩個元素放到一個元組裡,因為被提取的字串中有三個部分的字串滿足了所寫正則表示式的條件,所以一共被提取出了三個元組,最後這三個元組被放到一個列表裡。

找到感覺了沒有,那麼看看怎麼爬取貓眼電影裡的內容吧。
資料在哪提取?
資料在網頁原始碼中提取
在這裡插入圖片描述
比如網頁中可以看到這些電影的資訊,比如排名,電影名,主演,上映時間,和評分。但我們並不是在我們看到的這個頁面提取資料,因為這個頁面只能看到但是我們得不到,我們能到的是這樣網頁的原始碼(爬蟲的第二步),我們是在網頁原始碼中提取資料。
右擊網頁,點選檢視網頁原始碼就可以看到下面的這個頁面。
在這裡插入圖片描述
首先我們先將看到的原始碼複製下來(寫爬蟲的時候不需要複製,這裡複製是為了演示正則表示式)

Str=‘
<p class="name"><a href="/films/1215919" title="印度合夥人" data-act="boarditem-click" data-val="{movieId:1215919}">印度合夥人</a></p>
<p class="name"><a href="/films/123" title="龍貓" data-act="boarditem-click" data-val="{movieId:123}">龍貓</a></p>’
Data=re.findall(‘<p class="name">< a href="/films/1215919" title="印度合夥人" data-act="boarditem-click" data-val="{movieId:1215919}">(.*?)</a></p>’,str,re.S)
#結果
['印度合夥人']

上面正則表示式存在的問題是,它只能提取‘印度合夥人’這一個電影的名字,如果網頁中還有其他電影的名字,則提取不出來,因為上面寫的提取規則只適用於那一個電影名字。
如果提取物件是下面的樣子:

Str=“
<p class="name"><a href="/films/1215919" title="印度合夥人" data-act="boarditem-click" data-val="{movieId:1215919}">印度合夥人</a></p>
<p class="name"><a href="/films/123" title="龍貓" data-act="boarditem-click" data-val="{movieId:123}">龍貓</a></p>”
Data=re.findall(‘<p class="name"><a .*?>(.*?) </a></p>’,str,re.S)
print(Data)

#執行結果
['印度合夥人',‘龍貓’]_

這樣就可以將兩個電影名都提取出來,因為寫的提取規則這個兩個電影都適合,“.?”代表任意字元,如果在提取規則裡只寫“.?”而兩邊沒有加括號,則代表在這個位置的字元是什麼都可以,不影響我們要匹配的資訊。

那麼下面我們要一次性提取所有電影的名字和演員的資訊

import re 
data='<p class="name"><a href="/films/1215919" title="印度合夥人" data-act="boarditem-click" data-val="{movieId:1215919}">印度合夥人</a></p><p class="star">主演:阿克謝·庫瑪爾,拉迪卡·艾普特,索娜姆·卡普爾<p class="name"><a href="/films/123" title="龍貓" data-act="boarditem-click" data-val="{movieId:123}">龍貓</a></p><p class="star">主演:帕特·卡洛爾,蒂姆·達利,麗婭·薩隆加</p>'
result=re.findall('title="(.*?)".*?主演:(.*?)<',data,re.S)
print(result)
#執行結果:
[('印度合夥人', '阿克謝·庫瑪爾,拉迪卡·艾普特,索娜姆·卡普爾'), ('龍貓', '帕特·卡洛爾,蒂姆·達利,麗婭·薩隆加')]

這就是正則表示式,下篇文章是關於貓眼電影的爬蟲案例,會有完整的程式碼。