>백엔드 개발 >파이썬 튜토리얼 >크롤러 구문 분석 방법 3: 정규식

크롤러 구문 분석 방법 3: 정규식

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼앞으로
2019-06-05 14:06:043388검색

众多语言都能进行爬虫,但基于python的爬虫显得更加简洁,方便。爬虫也成了python语言中必不可少的一部分。爬虫的解析方式也是多种多样。

上一篇给大家讲解的是爬虫的解析方式二:Beautifulsoup,今天给带给大家的是正则表达式。

크롤러 구문 분석 방법 3: 정규식

正则表达式

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。就是 事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符”,这个“规则字符” 来表达对字符的一种过滤逻辑。

正则并不是python独有的,其他语言也都有正则。

python中的正则,封装了re模块

Python中常用的正则表达式处理函数

re.match函数

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

函数语法:

re.match(pattern, string, flags=0)

函数参数说明:

参数                                                         描述

pattern                                           匹配的正则表达式

string                                              要匹配的字符串。

flags                        标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

匹配成功re.match方法返回一个匹配的对象,否则返回None。

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法                                                              描述

group(num=0)                                      匹配的整个表达式的字符串,group() 可以一次输入多个组号,

                                                              在这种情况下它将返回一个包含那些组所对应值的元组。

groups()                                                返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

import re
print(re.match('www', 'www.baidu.com').span())  # 在起始位置匹配
print(re.match('com', 'www.baidu.com'))         # 不在起始位置匹配

以上实例运行输出结果为:

(0, 3)
None
import re
content = "Cats are smarter than dogs"
result = re.match( r'(.*) are (.*?) .*', content)
print(result.group())
print(result.group(1))
print(result.group(2))

以上实例执行结果如下:

Cats are smarter than dogs
Cats
smarter
result.group()获取匹配的结果
result.span()获去匹配字符串的长度范围

泛匹配

其实相对来说上面的方式并不是非常方便,其实可以将上述的正则规则进行更改

import re
content = "Cats are smarter than dogs"
result = re.match( r'Cats.*dogs$', content)
print(result)
print(result.group())
print(result.span())

匹配目标

如果为了匹配字符串中具体的目标,则需要通过()括起来,例子如下:

import re
content = "Cats are 1234567 smarter than dogs"
result = re.match( r'(.*)\sare\s(\d+)\s(.*?)\s.*', content) #\s匹配空格符 \d+匹配数字
print(result.group())
print(result.group(1))
print(result.group(2))

以下为执行结果:

Cats are smarter than dogs

Cats

1234567

贪婪匹配

先看下面代码:

import re
content = "Cats are 1234567 smarter than dogs"
result = re.match( r'Cats.*(\d+).*dogs', content) 
print(result.group())
print(result.group(1))

 

从结果中可以看出只匹配到了7,并没有匹配到1234567,出现这种情况的原因是前面的.* 给匹配掉了, .*在这里会尽可能的匹配多的内容,也就是我们所说的贪婪匹配,

如果我们想要匹配到1234567则需要将正则表达式改为:

result = re.match( r'Cats.*?(\d+).*dogs', content) 

这样结果就可以匹配到1234567

匹配模式

很多时候匹配的内容是存在换行的问题的,这个时候的就需要用到匹配模式re.S来匹配换行的内容

import re
content = """Cats are 1234567 smarter than dogs
dogs are wangwangwang"""
result = re.match( r'Cats.*(\d+).*wangwangwang', content,re.S) 
print(result.group())
print(result.group(1))

转义

当我们要匹配的内容中存在特殊字符的时候,就需要用到转移符号\,例子如下:

import re
content= "price is $5.00"
result = re.match('price is \$5\.00',content)
print(result.group())

注意:

对上面的一个小结:

尽量使用泛匹配,使用括号得到匹配目标,尽量使用非贪婪模式,有换行符就用re.S

强调re.match是从字符串的起始位置匹配一个模式

re.search方法

re.search 扫描整个字符串并返回第一个成功的匹配。

函数语法:

re.search(pattern, string, flags=0)

函数参数说明:

参数                                           描述

pattern                            匹配的正则表达式

string                              要匹配的字符串。

flags                                标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

匹配成功re.search方法返回一个匹配的对象,否则返回None。

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法                                                               描述

group(num=0)                          匹配的整个表达式的字符串,group() 可以一次输入多个组号,

                                                  在这种情况下它将返回一个包含那些组所对应值的元组。

groups()                                     返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

import re
content = "extra things hello 123455 world_this is a Re Extra things"
result = re.search("hello.*?(\d+).*?Re",content)
print(result.group())
print(result.group(1)

其实这个时候我们就不需要在写^以及$,因为search是扫描整个字符串

注意:所以为了匹配方便,我们会更多的用search,不用match,match必须匹配头部,所以很多时候不是特别方

re.match与re.search的区别

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

html = &#39;&#39;&#39;<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>&#39;&#39;&#39;
import re
 
result = re.search(&#39;<li.*?active.*?singer="(.*?)">(.*?)</a>&#39;,html,re.S)
print(result.group(1), result.group(2))

观察到

    节点里面有许多
  • 节点,其中
  • 节点有的包含节点,有的不包含节点,节点还有一些相应的属性,超链接和歌手名。

    首先我们尝试提取class为active的

  • 节点内部的超链接包含的歌手名和歌名。

    所以我们需要提取第三个

  • 节点下的节点的singer属性和文本。

    所以正则表达式可以以

  • 开头,然后接下来寻找一个标志符active,中间的部分可以用.*?来匹配,然后接下来我们要提取singer这个属性值,所以还需要写入singer="(.*?)",我们需要提取的部分用小括号括起来,以便于用group()方法提取出来,它的两侧边界是双引号,然后接下来还需要匹配节点的文本,那么它的左边界是>,右边界是,所以我们指定一下左右边界,然后目标内容依然用(.*?)来匹配,所以最后的正则表达式就变成了
  • (.*?)',然后我们再调用search()方法,它便会搜索整个HTML文本,找到符合正则表达式的第一个内容返回。

    另外由于代码有换行,所以这里第三个参数需要传入re.S

    注意:在上面两次匹配中,search()方法的第三个参数我们都加了re.S,使得.*?可以匹配换行,所以含有换行的

  • 节点被匹配到了,如果我们将其去掉,只会匹配到不换行的的内容

    re.findall

    搜索整个字符串然后返回匹配正则表达式的所有内容

    html = &#39;&#39;&#39;<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>&#39;&#39;&#39;
    import re
    results = re.findall(&#39;<li.*?href="/(.*?)".*?singer="(.*?)">(.*?)</a>&#39;, html, re.S)
    for result in results:
        print(result)
        print(result[0], result[1], result[2])

    运行结果:

    ('2.mp3', '任贤齐', '沧海一声笑')

    2.mp3 任贤齐 沧海一声笑

    ('3.mp3', '齐秦', '往事随风')

    3.mp3 齐秦 往事随风

    ('4.mp3', 'beyond', '光辉岁月')

    4.mp3 beyond 光辉岁月

    ('5.mp3', '陈慧琳', '记事本')

    5.mp3 陈慧琳 记事本

    ('6.mp3', '邓丽君', '但愿人长久')

    6.mp3 邓丽君 但愿人长久

    results = re.findall(&#39;<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>&#39;,html,re.S)
    for result in results:
        #print(result)
        print(result[0], result[1], result[2])

    运行结果:

     一路上有你 

    沧海一声笑

    往事随风

    光辉岁月

    记事本

    但愿人长久

    \s*? 这种用法其实就是为了解决有的有换行,有的没有换行的问题

    ()? 这种用法是因为html中有的有a标签,有的没有的,?表示匹配一个或0个,正好可以用于匹配

    检索和替换

    Python 的re模块提供了re.sub用于替换字符串中的匹配项。

    语法:

    re.sub(pattern, repl, string, count=0)

    参数:

    pattern : 正则中的模式字符串。

    repl : 替换的字符串,也可为一个函数。

    string : 要被查找替换的原始字符串。

    count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

    import re
    phone = "2004-959-559 # 这是一个电话号码"
    # 删除注释
    num = re.sub(r&#39;#.*$&#39;, "", phone)
    print ("电话号码 : ", num)
     
    # 移除非数字的内容
    num = re.sub(r&#39;\D&#39;, "", phone)
    print ("电话号码 : ", num)

    在这里我们只需要在第一个参数传入\D来匹配所有的数字,然后第二个参数“”是替换成的字符串,要去掉的话就可以赋值为空,第三个参数phone就是原字符串。


    re.compile

    将正则表达式编译成正则表达式对象,方便复用该正则表达式

    import re
    content= "hello world fan"
     
    pattern =re.compile("hello.*fan",re.S)
     
    result1 = re.match(pattern,content)
    result2 = re.search(pattern,content)
    result3 = re.sub(pattern, &#39;&#39;, content)
    print(result1, result2, result3)

    compile()还可以传入修饰符,例如re.S等修饰符,这样在search()、findall()等方法中就不需要额外传了。所以compile()方法可以说是给正则表达式做了一层封装,以便于我们更好地复用。

    正则表达式修饰符 - 可选标志

    正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:

    修饰符                                               描述

    re.I                                     使匹配对大小写不敏感

    re.L                                    做本地化识别(locale-aware)匹配

    re.M                                   多行匹配,影响 ^ 和 $

    re.S                                    使 . 匹配包括换行在内的所有字符

    re.U                                    根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.

    re.X                                    该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。


    正则表达式模式

    模式字符串使用特殊的语法来表示一个正则表达式:

    字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。

    多数字母和数字前加一个反斜杠时会拥有不同的含义。

    标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。

    反斜杠本身需要使用反斜杠转义。

    由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 \\t )匹配相应的特殊字符。

    下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。

    模式                                                                描述

    ^                                                          匹配字符串的开头

    $                                                                                                ~                   문자열의 끝과 일치합니다. #🎜🎜 ##.#. 행 변경을 제외한 모든 문자와 일치하며, Re.Dotall 표시를 지정하면 행 변경을 포함하는 모든 문자와 일치할 수 있습니다.

    [...]                                                                                                                                                                      #[^.]에 없는 문자: A, B 이외의 문자와 일치, 다.

    re*                                                                                                                                      #🎜🎜 ###1개 이상의 표현식을 Re+일치합니다.

    re?                                                                      dy way

    re{n}

    re{n, } 에게 "

    re{n, m}                                                                                       ‐                                                으로                                 일치 대상                                                 ​​​​정규식에는 세 가지 선택적 플래그(i, m 또는 x)가 포함됩니다. 괄호 안의 영역에만 영향을 미칩니다.

    (?-imx)                                                                 i, m 또는 x 선택적 플래그를 끄는 정규식입니다. 괄호 안의 영역에만 영향을 미칩니다.

    (?: 재)                                                                               >                                    옵션 플래그

    (?-imx: re)                                                      > ~        양수 구분 기호를 전달합니다. ...으로 표시되는 포함된 정규 표현식이 성공하면 현재 위치가 성공적으로 일치합니다.

                                                                                      를 사용하여 -                     ‐ ‐ ‐‐‐‐ 정규 표현식의 현재 위치가 일치하면 성공합니다. 하지만 포함된 표현식을 시도해도 매칭 엔진이 전혀 개선되지 않습니다.

    PART分 모드의 나머지 부분도 정의의 오른쪽 부분을 정의해야 합니다.向(?! Re) 정의가 앞으로 부정됩니다. 양수 구분 기호와는 반대로, 포함된 표현식이 문자열

    (?> re)                                                                                                                                                            을 사용하려면

    (?> re--------) ???? d 디지털이 아닌 모든 것과 일치

    일치하는 문자열

    의 끝부터 시작 z 일치하는 문자열. 행의 변경이 있는 경우 변경 전의 끝 문자열만 일치시킵니다. c

    z                                                          마지막 매치가 완료된 위치와 일치합니다.

    b                                                                                                                                                단어 경계, 즉 단어와 공백 사이의 위치와 일치합니다. Er 예를 들어, 'ERB'는 "NEVER"의 'er'와 일치할 수 있지만, "VERB"의 'er'와 일치할 수는 없습니다.

    B                                                                                       비단어 경계와 일치합니다. 'erB'는 "동사"의 'er'와 일치하지만 "never"에서는 일치하지 않습니다.

    n, t 등은 개행 문자와 일치합니다. 탭 문자와 일치합니다. 잠깐만요

    1...9                                                                                                                                              1을 사용하여 n번째 그룹의 내용과 일치시킵니다.

    10                                                                                               ~                            일치하는 경우 n번째 그룹의 콘텐츠와 일치합니다. 그렇지 않으면 8진 문자 코드의 표현을 참조합니다.


    정규 표현식의 예

    #🎜 🎜 #문자 매칭

    🎜🎜#python                                "python"과 일치합니다.#🎜 🎜## 🎜🎜#

    캐릭터 클래스

    인스턴스 # 🎜🎜#                  > #

    rub[ye]                           "ruby" 또는 " Rube "와 일치 #### 🎜🎜#[aeiou] 괄호 안의 문자 숙성#🎜🎜 ## 🎜🎜#[0-9] 일치 어떤 숫자라도. [0123456789][a-z]                            소문자와 일치

    [A-Z]                         대문자와 일치 [a-zA-Z0- 9]                        모든 문자 및 숫자와 일치 [^aeiou]                                                                                                                 숫자를 제외한 문자와 일치

    # 🎜🎜#

    #🎜🎜 #

    특수 문자 클래스

    예 #🎜 🎜#                                              'n'을 제외한 모든 단일 문자와 일치합니다. 'n'을 포함한 모든 문자를 일치시키려면 '[.n]'과 같은 패턴을 사용하십시오.

    d                                                                               숫자 문자와 일치합니다. [0-9]와 동일합니다.

    D                                                                                               숫자가 아닌 문자와 일치합니다. [^0-9]와 동일합니다.

    s                                                                                                            공백, 탭, 양식 피드 등을 포함한 모든 공백 문자와 일치합니다. [fnrtv]와 동일합니다.

    S                                                                                           흰색이 아닌 모든 것과 일치 공백 문자. [^ fnrtv]와 동일합니다.

    w                                                                                                                        밑줄을 포함한 모든 단어 문자를 일치시킵니다. '[A-Za-z0-9_]'와 동일합니다.
    W 단어가 아닌 모든 문자와 일치합니다. '[^A-Za-z0-9_]'와 동일합니다.

위 내용은 크롤러 구문 분석 방법 3: 정규식의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제