Python逆向爬虫之正则表达式

字符串是我们在编程的时候很常用的一种数据类型,检查会在字符串里面查找一些内容,对于比较简单的查找,字符串里面就有一些内置的方法可以处理,对于比较复杂的字符串查找,或者是有一些内容经常变化的字符串里面查找,那么字符串内置的查找方法已经不好使了,满足不了我们的要求,这个时候就得用正则表达式了,正则表达式就是用来匹配一些比较复杂的字符串。

正则表达式在线练习工具:

一、正则表达式

符号

解释

示例

说明

元字符

.

匹配任意字符

b.t

可以匹配bat / but / b#t / b1t等

\w

匹配字母/数字/下划线

b\wt

可以匹配bat / b1t / b_t等 但不能匹配b#t

\s

匹配空白字符(包括\r、\n、\t等)

love\syou

可以匹配love you

\d

匹配数字

\d\d

可以匹配01 / 23 / 99等

\b

匹配单词的边界

\bThe\b

^

匹配字符串的开始

^The

可以匹配The开头的字符串

$

匹配字符串的结束

.exe$

可以匹配.exe结尾的字符串

\W

匹配非字母/数字/下划线

b\Wt

可以匹配b#t / b@t等 但不能匹配but / b1t / b_t等

\S

匹配非空白字符

love\Syou

可以匹配love#you等 但不能匹配love you

\D

匹配非数字

\d\D

可以匹配9a / 3# / 0F等

\B

匹配非单词边界

\Bio\B

[]

匹配来自字符集的任意单一字符

[aeiou]

可以匹配任一元音字母字符

[^]

匹配不在字符集中的任意单一字符

[^aeiou]

可以匹配任一非元音字母字符

*

匹配0次或多次

\w*

+

匹配1次或多次

\w+

?

匹配0次或1次

\w?

匹配N次

\w

匹配至少M次

\w

匹配至少M次至多N次

\w

|

分支

foo|bar

可以匹配foo或者bar

(?#)

注释

(exp)

匹配exp并捕获到自动命名的组中

(?exp)

匹配exp并捕获到名为name的组中

(?:exp)

匹配exp但是不捕获匹配的文本

(?=exp)

匹配exp前面的位置

\b\w+(?=ing)

可以匹配I'm dancing中的danc

(?<=exp)

匹配exp后面的位置

(?<=\bdanc)\w+\b

可以匹配I love dancing and reading中的第一个ing

(?!exp)

匹配后面不是exp的位置

(?<!exp)

匹配前面不是exp的位置

*?

重复任意次,但尽可能少重复

a.b a.?b

将正则表达式应用于aabab,前者会匹配整个字符串aabab,后者会匹配aab和ab两个字符串

+?

重复1次或多次,但尽可能少重复

??

重复0次或1次,但尽可能少重复

{M,N}?

重复M到N次,但尽可能少重复

{M,}?

重复M次以上,但尽可能少重复

说明:如果需要匹配的字符是正则表达式中的特殊字符,那么可以使用\进行转义处理。

二、进行逐个详解

2.1 匹配多种可能

#'run' or 'ran'
res = re.search(r'r[au]n','dog runs to cat')
print(res)
>>> <re.Match object; span=(4, 7), match='run'> 

res = re.search(r'r[au]n','dog rans to cat')
print(res)
>>> <re.Match object; span=(4, 7), match='ran'>

#continue 匹配更多种可能
res = re.search(r'r[A-Z]n','dog rans to cat')
print(res)
>>> None

res = re.search(r'r[a-z]n','dog rans to cat')
print(res)
>>> <re.Match object; span=(4, 7), match='ran'>

res = re.search(r'r[0-9]n','dog rans to cat')
print(res)
>>>None

res = re.search(r'r[0-9a-z]n','dog rans to cat')
print(res)
>>> <re.Match object; span=(4, 7), match='ran'>

2.2 匹配数字 \d and \D

# \d : decimal digit 数字的
res = re.search(r'r\dn','run r9n')
print(res)
>>> <re.Match object; span=(4, 7), match='r9n'>

# \D : any non-decimal digit 任何不是数字的
res = re.search(r'r\Dn','run r9n')
print(res)
>>> <re.Match object; span=(0, 3), match='run'>

2.3 匹配空白 \s and \S

# \s : any white space [\t \n \r \f \v]
res = re.search(r'r\sn','r\nn r9n')
print(res)
>>> <re.Match object; span=(0, 3), match='r\nn'>

# \S : 和\s相反,any non-white space
res = re.search(r'r\Sn','r\nn r9n')
print(res)
>>> <re.Match object; span=(4, 7), match='r9n'>

2.4 匹配所有的字母和数字以及"_" \w and \W

# \w : [a-zA-Z0-9_]
res = re.search(r'r\wn','r\nn r9n')
print(res)
>>> <re.Match object; span=(4, 7), match='r9n'>

# \W : opposite to \w 即与\w相反
res = re.search(r'r\Wn','r\nn r9n')
print(res)
>>> <re.Match object; span=(0, 3), match='r\nn'>

2.5 匹配空白字符 \b and \B

# \b : (only at the start or end of the word)
res = re.search(r'\bruns\b','dog runs to cat')
print(res)
>>> <re.Match object; span=(4, 8), match='runs'>
res = re.search(r'\bruns\b','dogrunsto cat')
print(res)
>>> None

# \B : ( but not at the start or end of the word)
res = re.search(r'\Bruns\B','dog runs to cat')
print(res)
>>> None
res = re.search(r'\Bruns\B','dogrunsto cat')
print(res)
>>> <re.Match object; span=(5, 11), match=' runs '>

2.6 匹配特殊字符 任意字符 \ and .

# \\ : 匹配 \
res = re.search(r'runs\\','dog runs\ to cat')
print(res)
>>> <re.Match object; span=(4, 9), match='runs\\'>

# . : 匹配 anything (except \n)
res = re.search(r'r.ns','dog r;ns to cat')
print(res)
>>> <re.Match object; span=(4, 8), match='r;ns'>
>res = re.search(r'r.ns','dog r\nns to cat')
print(res)
>>> None

2.7 匹配句尾句首 $ and ^

# ^ : 匹配line beginning
res = re.search(r'^runs','dog runs to cat')
print(res)
>>> None
res = re.search(r'^dog','dog runs to cat')
print(res)
>>> <re.Match object; span=(0, 3), match='dog'>

# $ : 匹配line ending
res = re.search(r'runs$','dog runs to cat')
print(res)
>>> None
res = re.search(r'cat$','dog runs to cat')
print(res)
>>> <re.Match object; span=(12, 15), match='cat'>

2.8 是否匹配 ?

# ? : may or may nt occur
res = re.search(r'r(u)?ns','dog runs to cat')
print(res)
>>> <re.Match object; span=(4, 8), match='runs'>

res = re.search(r'r(u)?ns','dog rns to cat')
print(res)
>>><re.Match object; span=(4, 7), match='rns'>

2.9 多行匹配 re.M

# 匹配代码后面加上re.M
string = """ 123.
dog runs to cat.
You run to dog.
"""
res = re.search(r'^You',string)
print(res)
>>> None

res = re.search(r'^You',string,re.M)
print(res)
>>> <re.Match object; span=(10, 13), match='run'>

2.10 匹配零次或多次 *

# * : occur 0 or more times
res = re.search(r'ab*','a')
print(res)
>>> <re.Match object; span=(0, 1), match='a'>

res = re.search(r'ab*','abbbbbbbbbb')
print(res)
>>> <re.Match object; span=(0, 11), match='abbbbbbbbbb'>

2.11 匹配一次或多次 +

# + :occur 1 or more times
res = re.search(r'ab+','a')
print(res)
>>> None

res = re.search(r'ab+','abbbbbbbbbb')
print(res)
>>> <re.Match object; span=(0, 11), match='abbbbbbbbbb'>

2.12 可选次数匹配

# {n, m} : occur n to m times
res = re.search(r'ab{1,10}','a')
print(res)
>>> None

res = re.search(r'ab{1,10}','abbbbbbbbbb')
print(res)
>>> <re.Match object; span=(0, 11), match='abbbbbbbbbb'>

2.13 寻找所有匹配 findall

# re.findall()
res = re.findall(r'r[ua]n','run ran ren')
print(res)
>>> ['run', 'ran']

# 另一种写法
res = re.findall(r'(run|ran)','run ran ren')
print(res)
>>> ['run', 'ran']

2.14 替换匹配内容 sub

# re.sub(   ,replace,   )
res = re.sub(r'runs','catches','dog runs to cat')
print(res)
>>> dog catches to cat

2.15 分裂内容 split

# re.sub(   ,replace,   )
res = re.sub(r'runs','catches','dog runs to cat')
print(res)
>>> dog catches to cat

2.16 包装正则表达式 compile

# re. compile()
compile_re = re.compile(r'r[ua]n')
res = compile_re.findall('run ran ren')
print(res)
>>> ['run', 'ran']


compile_re = re.compile(r'(?P<name>r[ua]n?)')
res = compile_re.finditer('run ran ren')
for i in res:
    print(i.groupdict())

2.17 re.S

注意:不使用re.S时,则只在每一行内进行匹配,如果存在一行没有,就换下一行重新开始,使用re.S 参数以后,正则表达式会将这个字符串看做整体,在整体中进行匹配,一般在爬虫项目中会经常用到。

import re
a = """sdfkhellolsdlfsdfiooefo:877898989

worldafdsf"""
b = re.findall('hello(.*?)world',a)
c = re.findall('hello(.*?)world',a,re.S)
print ('b is ' , b)
print ('c is ' , c)

三、Python 爬取豆瓣电影排行榜

import re
import requests

def main():

    head = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
    }

    baseurl = "https://movie.douban.com/top250?start="

    res = requests.get(url=baseurl, headers=head)

    connect = res.text

    obj = re.compile(
        r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)</span>.*?<p class="">.*?<br>(?P<year>.*?) .*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>.*?<span>(?P<num>.*?)人评价</span>', re.S)

    result = obj.finditer(connect)

    for it in result:
        print(it.groupdict())

if __name__ == '__main__':

    main()