1. 程式人生 > >【Python3 爬蟲學習筆記】基本庫的使用 10—— 正則表示式 3

【Python3 爬蟲學習筆記】基本庫的使用 10—— 正則表示式 3

3.search()

mathch()方法是從字串的開頭開始匹配的,一旦開頭不匹配,那麼整個匹配就失敗了。因為match()方法在使用時需要考慮到開頭的內容,這在匹配時並不方便。它更適合用來檢測某個字串是否符合某個正則表示式的規則。
search()方法在匹配時會掃描整個字串,然後返回第一個成功匹配的結果。也就是說,正則表示式可以是字串的一部分,在匹配時,search()方法會依次掃描字串,知道找到第一個符合規則的字串,然後返回匹配內容,如果搜尋完了還沒有找到,就返回None。

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.search('Hello.*?(\d+).*?Demo',content) print(result)

執行結果:

<_sre.SRE_Match object; span=(13, 53), match='Hello 1234567 World_This is a Regex Demo'>

這裡有一段待匹配的HTML文字,接下來寫幾個正則表示式例項來實現相應資訊的提取:

html = ''' <div id="songs-list">
<h2 class="title">經典老歌</h2>
<p class="introduction">
經典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2">一路上有你</li>
<li data-view="7">
<a href="/2.mp3" singer="任賢齊">滄海一聲笑</a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齊秦">往事隨風</a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond">光輝歲月</a></li>
<li data-view="5"><a href="/5.mp3" singer="陳慧琳">記事本</a></li>
<li data-view="5">
<a href="/6.mp3" singer="鄧麗君">但願人長久</a>
</li>
</ul>
</div>'''

可以觀察到,ul節點裡有很多li節點,其中li節點中有的包含a節點,有的不包含a節點,a節點還有一些相應的屬性——超連結和歌手名。
首先,我們嘗試提取class為active的li節點內部的超連結包含的歌手名和歌名,此時需要提取第三個li節點下a節點的singer屬性和文字。
此時正則表示式可以以li開頭,然後尋找一個標誌符active,中間的部分可用.*?來匹配。接下來,要提取singer這個屬性值,所以還需要寫入singer="(.星?)",這裡需要提取的部分用小括號括起來,以便用group()方法提取出來,它的兩側邊界是雙引號。然後還需要匹配a節點的文字,其中它的左邊界是>,右邊界是</ a>。然後目標內容易依然用(.星?)來匹配,所以最後的正則表示式就變成了:

<li.*?active.*?singer="(.*?)">(.*?)</a>

另外,由於程式碼有換行,所以這裡第三個引數需要傳入re.S。整個匹配程式碼如下:

import re

result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
    print(result.group(1), result.group(2))

由於需要獲取的歌手和歌名都已經用小括號包圍,所以可以用group()方法獲取。
執行結果:

齊秦 往事如風

可以看到,這正是class為active的li節點內部的超連結包含的歌手名和歌名。
如果正則表示式不加active(也就是匹配不帶class為active的節點內容),改動程式碼如下:

import re

result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
    print(result.group(1), result.group(2))

結果變為:

任賢齊 滄海一聲笑

把active標籤去掉後,從字串開頭開始搜尋,此時符合條件的節點就變成了第二個li節點,後面的就不再匹配,所以執行結果就變成第二個li節點中的內容。
注意,在上面的兩次匹配中,search()方法的第三個引數都加了re.S,這使得.*?可以匹配換行,所以含有換行的li節點被匹配到了。如果去掉re.S,便會得到:

beyond 光輝歲月

可以看到,結果變成了第四個li節點的內容。這是因為第二個和第三個li節點都包含了換行符,去掉re.S之後,.*?已經不能匹配換行符,所以正則表示式不會匹配到第二個和第三個li節點,而第四個li節點中不包含換行符,所以成功匹配。