Python 從零開始爬蟲(四)——強大的正則表達式,re模塊

若是把BeautifulSopu比喻成經過線索一步步接近目標的偵探的話,那麼正則表達式就是牛逼哄哄的「天眼系統」,只要提供一些目標的特徵,不管搜索範圍多大,只要存在那麼一兩個符合特徵的目標,全都會被它直接逮住。html

特性

牛逼王

  • BS的爸爸,我告訴你個祕密,其實BeautifulSoup也是用正則實現的,並且它find_all的參數裏還能接收正則呢
  • 信息精肯定位,BeautifulSoup用的是節點定位,可能會出現多個符合條件的節點(卻沒有目標信息);正則是直接針對目標信息,以字符爲單位匹配,一次篩選出正確結果(前提是寫好正則)
  • 能獲取信息的部分,有時候完整的信息不是你想要的,你只想取它的某一部分,正則能搞定,BS只能先獲取完整信息再分離。
  • 用途大着呢,不要覺得正則只能爬蟲,先後端都少不了正則,你填個信息判斷是否合法這都是正則,總之學到賺到

勸退大王+

這麼強大的方法是否是看到都心動了,不過強大是有代價的,較難上手很難精通這兩根大棒一會兒錘走了很多初學者。當時學的我是這樣的:圖片描述python

  • 抽象&可讀性差。爲了逮住某個目標,你可能要寫一條長長的,看到本身都頭暈的正則表達式,看上去就像亂碼同樣。舉個栗子,若是你要匹配一個ip地址,正則表達式會是這樣正則表達式

    匹配ip地址: ((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)) ——真·亂碼
  • 編寫時出錯率高,新手很難一次寫對,須要不停地修改幾回十幾回才能pass(大腦在顫抖)
  • 難於優化,優化好的正則能提升匹配速度,然而你這新手還想優化,能匹配對就很不錯了(正則暗中偷笑)

若是有足夠的自信和毅力不被正則擊倒,那就來吧。(屁,學正則還不是早晚的事!)後端

re 模塊

python 自帶模塊,直接導入便可。有匹配,替換等方法。
思考了許久後筆者以爲仍是先講表達式(規則)好,由於某些方法的理解是要了解表達式的。
下文的規則是徹底版的,花了好久寫成,分享給讀者,順便當成本身的網上筆記。學習

若是你學正則只是單單用來爬蟲的話,你只要熟悉「字符匹配」,「分組&或&轉義」,「預約字符集」,「數量詞」,「非貪婪模式」和(?:)取消分組,瞭解(或乾脆不學)「邊界匹配」,「特殊構造」就好了。優化

若是你以爲正則是你將來工做的剛需的話,推薦熟悉全部規則。spa

匹配規則(pattern)

規則實際上是一個原字符串如r'表達式'/r"表達式",較正式的叫法是模式字符串。最後再說一句,匹配以單個字符爲單位(除括號能把多個字符打包成分組(總體)來匹配


表達式本質是字符串,不要單引(雙引)號裏套單引(雙引)號,會出錯。code

字符匹配

  • 任一字符(空格也算)——就是匹配這個字符,某些字符由於在正則中有特殊用途需前加反斜槓轉義如 [ { . | ( ) ^ * + ? $
  • .——英文句號,匹配除換行符\n外的任意單個字符
  • []——匹配中括號裏的任一字符,與-結合還能表示範圍內的任一字符,中括號內的字符除\外會自動轉義,還有當心多箇中括號嵌套錯誤
  • [^]——中括號最前面加^,與[ ]反義,匹配一個不在中括號裏的字符,也能夠用橫槓-
  • r'[abcd]'#匹配一個a或b或c或d
    r'[0-9]'#匹配一個0至9的數,-的做用域是左右各一個字符
    r'[a-z]'  r'[A-Z]'#分別匹配a到z或A到Z的一個字母
    r'[12-89]'#注意由於是單字符匹配,匹配的是1,2到8的數,9(即1到9的一個數),不是12到89的數
    r'[{.|()^*+?$\\]'#匹配 { . | ( ) ^ * + ? $ \中任一個,\要轉義
    r'[^a-zA-Z]'#匹配一個不是字母的字符

分組&或&轉義

  • ()——括號,表達式分組(第n組,n=1,2,3....99,從左往右數),並造成子表達式
  • (?P<name>)——擁有括號的功能,但能爲該分組再指定一個自定名字
  • (?P=name)——引用分配過名字的分組,但沒有分組功能
  • |——或,左右規則任意匹配一個,從左往右嘗試匹配,一旦成功就跳事後面的規則。|沒被包在括號中間的話它的做用域是整個表達式,被包的話做用域在括號內
  • \——反斜槓,後接功能字有符轉義功能,後接數字(1到99)有引用分組的功能,後接某些字母又有特殊功能
  • r'abc|def|ghi'#匹配abc或def或ghi
    r'ma(?:k|d)e'#匹配make或made
    r'(abc)def\1'#至關於r'(abc)defabc',匹配abcdefabc
    r'(?P<ok>abc)f(?P=ok)'#爲(abc)子組分配了「ok」的名字,而後再引用,匹配abcfabc

預約字符集

  • \d——匹配任一個數字(0~9)
  • \D——匹配一個非數字字符,與\d互補
  • \s——匹配一個空白字符,包括空格,\t,\n,\r,\n,\f,\v
  • \S——匹配一個非空白字符
  • \w——匹配一個單詞字符。unicode下匹配各類語言的單個字符,單個數字,和下橫線。ASCII下匹配單個英文字母,單個數字,和下橫線
  • \W——匹配一個非單詞字符
  • r'\w' #能匹配'物語&ものがたり'中的:物,語,も,の,が,た,り,漢語日語的單字,其餘語言同理

數量詞(接在字符或子組後)

  • {n}——做用於前一個字符或子表達式,匹配它重複n次
  • {min,max}——做用於前一個字符或子表達式,匹配它重複重複多少次min~max次,min和max可只寫一個設置重複下限或上限,但逗號不能省,不寫min時min默認爲0
  • *——星號,做用於前一個字符或子表達式,匹配它零次或屢次
  • +——做用於前一個字符或子表達式,匹配它至少一次
  • ?——做用於前一個字符或子表達式,匹配它零次或一次
  • r'z{3}'#匹配zzz
    r'z{0,3}'#匹配z或zz或zzz
    r'(?:abc){2}'#對子表達式匹配兩次,匹配abcabc,(?:)是一個用法,不分組的意思,詳看後面
    #星號加號問號同理

非貪婪模式

  • 在數量詞後接?,對前面的數量詞開啓非貪婪模式,意思就是在能匹配的前提下儘量少的重複匹配
  • 正則默認開啓貪婪模式
r'<.+>'#默認貪婪,對於'<abc><def>'能匹配到'<abc><def>'整條,由於.貪婪地把尖括號也匹配掉了
r'<.+?>'#非貪婪,對於'<abc><def>'能匹配到'<abc>'和'<def>'

邊界匹配

  • ^——放在表達式的最前面,做用域是表達式,在多行模式中,在每一行匹配字符串開頭(多行模式要手動開啓,不然和\A沒什麼區別)
  • $——放在表達式的最後面,做用域是表達式,在多行模式中,在每一行匹配字符串末尾(多行模式要手動開啓,不然和\Z沒什麼區別)
  • \A——放在表達式的最前面,做用域是表達式,匹配字符串開頭,不能多行匹配
  • \Z——放在表達式的最後面,做用域是表達式,匹配字符串末尾,不能多行匹配
  • \b——不匹配字符,只匹配一個邊界,匹配\w和\W或\W和\w的邊界(單詞字符和非單詞字符的邊界)
  • \B——不匹配字符,只匹配一個邊界,與\b相反,匹配\w和\w或\W和\W的邊界
  • r'^abc|^def'#匹配abc開頭或def開頭,開啓了多行模式時,對字符串'abcd\ndefh'能匹配出abc,def兩個
    r'abc$|def$'#匹配abc結尾或def結尾,開啓了多行模式時,對字符串'0abc\n0def'能匹配出abc,def兩個
    r'\Aabc'#匹配abc開頭,由於不能多行匹配,就算開啓多行模式,對字符串'abcd\nabcd'只能匹配到前面的abc
    #\Z同理
    r'\w\b\W'#匹配「單詞字符+非單詞字符」的結構如'a!','1%'
    #\B同理

特殊構造(不做爲分組,不被findall捕獲)

    • (?:)——取消括號的分組功能,使其不會被findall方法捕獲
    • (?#)——#後寫註釋內容,整個(?#)會被忽略
    • A(?=)——A以後的字符串須要匹配括號裏的表達式A纔會被匹配,必定用在表達式的最後(A是表達式,(?=)內的表達式不會被匹配捕捉,下同)
    • A(?!)——A以後的字符串須要不匹配括號裏的表達式A纔會被匹配,必定用在表達式的最後
    • (?<=)A——A以前的字符串須要匹配括號裏的表達式A纔會被匹配,必定用在表達式的最前,括號內的表達式需固定長度不能使用除{n}外的數量詞
    • (?<!)A——A以前的字符串須要不匹配括號裏的表達式A纔會被匹配,必定用在表達式的最前,括號內的表達式需固定長度不能使用除{n}外的數量詞
    • r'(ab(?=cde))'#匹配後面是bcd的ab
      r'a(?!\d+)'#匹配後面不跟一串數字的a,後括號可用全部數量詞
      r'(?<=abc)de'#匹配前面是abc的de
      r'(?<!\d{3})a'#匹配前面不是三個數字的a,前括號能夠用{n}可是不能用不定量的數量詞
    • (?iLmsux)——放在表達式最前面,爲所在的表達式設置模式,」i」, 「L」, 「m」, 「s」, 「u」, 「x」,它們不匹配任何字串,對應python中re模塊當中的(re.I, re.L, re.M, re.S, re.U, re.X)的6種模式,下面flag參數講
    • r'(?i)abc'#「i」對應re.I,忽略大小寫模式,能匹配Abc,ABC,abc等

    方法&參數

    相比於繁雜的規則,方法則要簡單多了,經常使用的就這幾個:htm

    • re.search(pattern,string,flags=0),返回第一個匹配的match對象(內含匹配字符串的信息)
    • re.findall(pattern,string,flags=0),返回全部匹配分組的字符串組成的列表,沒設置分組至關於整個表達式就是一個分組
    • #若是表達式有多個分組,會返回複雜的列表,所以findall中的表達式一般只有一個分組
    • re.finditer(pattern,string,flags=0),同findall功能,可是返回的是迭代器對象

      re.findall(r'\d+(abc)\d+','1abc1,2abc2')#分組爲(abc),findall只捕捉被數字包起來的abc返回列表['abc','abc']
      re.findall(r'((?:ab){2}\d)\d','abab11,abab22')#整個表達式匹配abab加一個兩位數,(?:)取消了ab的分組,findall只捕捉abab加一個數,返回列表['abab1','abab2']
    • pattern = re.compile(pattern,flags=0),把規則打包返回(如屢次使用該規則),至關與pattern和flag的合體,當成pattern使用可免去設置flags
    • re.sub(pattern,repl,string,count=0,flags)把匹配到的部分用指定字符串repl替換,count設置替換次數,默認爲零替換全部

    參數:

    • pattern:接收模式字符串,即表達式,也能夠接收打包的規則
    • string:接收待匹配字符串,如html文檔
    • flags:模式(標籤),接受如下模式,多個模式用「|」分開如 flags=re.I|re.M

      • re.I = re.IGNORECASE   忽略大小寫
      • re.L = re.LOCALE   支持當前語言,爲了支持多語言版本的字符集使用環境
      • re.U = re.UNICODE   使用w,W,b,B這些元字符時將按照UNICODE定義的屬性
      • re.M = re.MULTILINE   開啓多行模式
      • re.S = re.DOTALL   使.能匹配換行符\n
      • re.X = re.VERBOSE   能夠忽略正則表達式中的空白和#號的註釋,不匹配空格和#註釋
      • re.A  開啓ASCII模式

    match對象方法

    列出經常使用方法,下面的match是對象

    • match.group(id/name)id是分組序號(1~99),name是分組的自定名字,返回指定分組的字符串;不傳參數數是返回整條匹配字符串
    • match.start(id/name),match.end(id/name),match.span(id/name),分別返回指定分組字符串在整個字符串中的開始位置,結束位置,範圍。



    地獄之旅到這就結束了,不只是讀者的,仍是個人,お疲れ
    文章過長,可能存在某些瑕疵和錯誤,歡迎提出
    累成苟,最近並且要忙於學習,又被P大學事件噁心了一下,接下來的產能會降低,估計一個星期多一點更一次
    正則慢慢學就行,正則的使用後面會有實例讓你們熟悉

    相關文章
    相關標籤/搜索