天天看點

python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

目錄

正規表達式:re子產品

元字元

正規表達式如何比對任意字元:re.S

貪婪比對和非貪婪比對

1.貪婪比對

2.非貪婪比對

正規表達式的分組

貓眼電影TOP100資訊提取

1.需求分析

2.代碼分析 

3.編寫程式

正規表達式:re子產品

re子產品有兩種方式實作正則比對

方式一:

lists=re.findall("he","hello world")

方式二:

pattern=re.complie("he")

lists=pattern.findall("hello world")

這兩種方法都可以正則比對字元,隻是第二種方式提前定義了正規表達式,可以複用,是以推薦使用第二種方式

元字元

正規表達式常用的元字元如下:

. 比對任意一個字元,除了\n
* 比對0個或多個的字元串
+ 比對1個或多個的字元串
比對0個或1個,為非貪婪方式
[a, b , c] 比對 ‘a’ 或 ‘b’ 或 ‘c’
\s 比對 任何 空白字元, 相當于[\t\n\r\f]
\S 比對 任何 非空白字元, 相當于[^\t\n\r\f]

正規表達式如何比對任意字元:re.S

通常來說,如果我們要比對任意字元,可以這樣寫(方式一):

pattern=re.complie("[\s\S]")

lists=pattern.findall("hello\nworld")

這樣寫可以比對到\n,看下面這種寫法,這個寫法并不會比對\n這個換行符。一個頁面有非常多的換行符,是以這麼寫時不合理的。

pattern=re.complie(".*")

lists=pattern.findall("hello\nworld")

那麼我們可以使用re.S,如下,re.S代表允許'. '比對'\n'(方式二,推薦):

pattern=re.complie(".*",re.S)

lists=pattern.findall("hello\nworld")

貪婪比對和非貪婪比對

1.貪婪比對

在整個表達式比對成功的情況下,盡可能的多比對*或 + 或 ?。

表達方式:.* 或 .+ 或 .?

2.非貪婪比對

在整個表達式比對成功的情況下,盡可能的少比對* 或 + 或 ?。

表達方式:.*? 或 .?? 或 .+?

貪婪比對和非貪婪比對到底有什麼含義能,看下面的例子:

編寫這麼一段代碼,我們預期的結果是得到幾個集合,集合裡有兩個對象,<div><p>今天天氣不錯</p></div>和<div><p>太陽很舒服</p></div>

import re

str="""
<div><p>今天天氣不錯</p></div>
<div><p>太陽很舒服</p></div>
"""

pattern=re.compile("<div><p>.*</p></div>",re.S)
lists=pattern.findall(str)

print(lists)
           

但是結果卻成了一個對象,這是因為在貪婪比對模式下,由于‘.’會比對任意字元(它會認為</p></div>也是任意字元),是以它會比對到最後一個以‘</p></div>’結尾的字元串。

python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

再看下面的一段代碼,稍一看似乎沒什麼差別,眼睛尖的是能發現差別的,在.*後面加了一個?号,剛才說了這是非貪婪表達式方式,而非貪婪比對的比對模式是比對最近的以</p></div>結尾的字元串(僅在這個案例中),這樣的比對模式正好符合我們的預期結果。

import re

str="""
<div><p>今天天氣不錯</p></div>
<div><p>太陽很舒服</p></div>
"""

pattern=re.compile("<div><p>.*?</p></div>",re.S)
lists=pattern.findall(str)

print(lists)
           

結果:

python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

總結:在正規表達式中,絕大數情況會使用非貪婪比對,非常好了解,我們需要的内容是一個裝滿了成功比對的對象集合,而不是一個連在一起的對象集合(而且在多數情況下傳回的結果總是會與你預想的結果有差別)。

正規表達式的分組

還是上面那個案例,我們剛才得到的結果如下圖,我們僅需要<div></div>中間的内容該如何處理,這就需要用的正規表達式分組。

正規表達式分組是指在完整的的模式中定義子模式,将每個用圓括号中的子模式作為結果提取出來

python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

實際運用非常簡單,還是上面的代碼,我們隻需要在.*?包在括号裡即可,如下: 

import re

str="""
<div><p>今天天氣不錯</p></div>
<div><p>太陽很舒服</p></div>
"""

pattern=re.compile('<div><p>(.*?)</p></div>',re.S)
lists=pattern.findall(str)
           
python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

做完上面的案例後,我們在具體來聊一下正規表達式的分組,請看下面3個案例:

import re


str='A B C D'
pattern2=re.compile("\w+\s+\w+")
lists2=pattern2.findall(str)

pattern3=re.compile("(\w+)\s+\w+")
lists3=pattern3.findall(str)

pattern4=re.compile("(\w+)\s+(\w+)")
lists4=pattern4.findall(str)

print(lists2)
print(lists3)
print(lists4)
           
python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

先看第一組正規表達式:re.compile("\w+\s+\w+"),我們知道\w比對任意字母和數字,+号比對一個或多個,我們定義的str='A B C D',按照比對規則,\w+将比對一串連續的字元,而這裡的字元用空格隔開了,是以隻會比對一個字元。\s+比對任何空白字元,最後的\w+比對一個字元。那麼總結下來就是這樣的比對規則:字元 空格 字元。結果也是如此。

再看第二組正規表達式:re.compile("(\w+)\s+\w+"),與第一組的差別在與第一個\w+加了括号,從結果上差別就是隻比對到了一個字元。我們在上面的案例中講了正規表達式的分組,這裡的括号就是給\w+做分組,然它成為子模式。在子模式下隻取出子模式的比對内容作為結果,這裡的\w+的比對結果是A,是以輸出A。

第三組:re.compile("(\w+)\s+(\w+)")。第三組有兩個括号,代表有兩個子模式。兩個子模式會以元組的方式輸出。

總結:

1.正規表達式的分組是通過加()來實作的

2.如果隻想取比對結果的某一段内容,為這一段内容的比對模式加上()

3.有兩個()将會以元組的方式進行輸出

貓眼電影TOP100資訊提取

1.需求分析

貓眼電影TOP100榜單URL:https://maoyan.com/board/4?offset=0

頁面詳情如下,我們要提取的資訊有電影名稱、主演、上移時間和評分。

因為是top100,每頁顯示10個,總計10頁。分析URL得到第一頁為https://maoyan.com/board/4?offset=0,第二頁為https://maoyan.com/board/4?offset=10。

是以頁碼格式為offset=(page-1)*10

python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

2.代碼分析 

提取資訊的關鍵在與寫對正規表達式,如圖所示,我們要提取的資訊有劃紅線的部分。

python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取

經過整理後得出的資訊如下,我們要以這一串内容寫一段正規表達式。首先我們将需要提取的字元打上分組符号()。要注意的是電影名有兩處顯示,我們選擇title裡的;評分是分為兩段顯示的,我們都要打上标記。切忌不要把他寫成一行,目前這一段格式包含了\n換行符,并且每一個位置都是精确的,不易改動。

<div class="movie-item-info">
        <p class="name"><a href="/films/1203" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  title="霸王别姬" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
        <p class="star">
                主演:張國榮,張豐毅,鞏俐
        </p>
<p class="releasetime">上映時間:1993-07-26</p>    </div>
    <div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">5</i>
           

打完之後如下,現在這一段正規表達式僅可以比對霸王别姬這一段内容,我們要想辦法讓他比對所有。 

<div class="movie-item-info">
        <p class="name"><a href="/films/1203" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  title="(.*?)" data-act="boarditem-click" data-val="{movieId:1203}">霸王别姬</a></p>
        <p class="star">
                (.*?)
        </p>
<p class="releasetime">(.*?)</p>    </div>
    <div class="movie-item-number score-num">
<p class="score"><i class="integer">(.*?)</i><i class="fraction">(.*?)</i>
           

我們将多餘的部分用.*?代替。得到如下格式。剛才說了,因為有換行符的存在,是以在換行出也要打上.*?

<div class="movie-item-info">
        .*?title="(.*?)".*?
        <p class="star">
                (.*?)
        </p>.*?
<p class="releasetime">(.*?)</p>.*?
<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>
           

最終經過整理後,得到下面内容。這裡不要留白行,擠壓成一段字元串。

<div class="board-item-main">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p>.*?<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>
           

3.編寫程式

1.定義一個類

2.初始化類,定義url,headers,正則比對表達式

3.定義方法:get_html()用于擷取頁面,注意轉碼

4.定義方法:run(),作為類的入口函數,提示輸出頁面。顯示結果需要進一步處理,去除空格符

from urllib import request
import re

class Maoyan_spider(object):

    def __init__(self):
        self.url="https://maoyan.com/board/4?offset={}"
        self.headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"}
        self.pattern=re.compile('<div class="board-item-main">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)'
                   '</p>.*?<i class="integer">(.*?)</i><i class="fraction">(.*?)</i>',re.S)

    #擷取頁面
    def get_html(self,url):
        req = request.Request(url=url, headers=self.headers)
        rep = request.urlopen(req)
        html = rep.read().decode("utf-8")
        return html

    #入口函數
    def run(self):
        page=(int)(input("請輸入頁碼數:"))
        #計算頁面
        offset=(page-1)*10
        #拼接url
        url=self.url.format(offset)
        html=self.get_html(url)
        lists=self.pattern.findall(html)
        for i in lists:
            print("電影名:" + i[0].strip())
            print(i[1].strip())
            print(i[2].strip())
            print("評分:" + i[3] + i[4])


if __name__ == "__main__":
    maoyan=Maoyan_spider()
    maoyan.run()
           

 最終效果如下:

python正規表達式re子產品入門,貪婪比對和非貪婪比對,案例:貓眼電影TOP100資訊提取