爬虫学习整理(2)数据解析——正则表达式(re)

什么是正则表达式

通俗理解:按照一定的规则,从某个字符串中匹配出想要的数据。这个规则就是正则表达式。

正则语法
语法含义
.匹配任意字符
[ ]匹配括号中的某一项
\d匹配数字
\D匹配非数字
\s匹配空白
\S匹配非空白
\w匹配a-z、A-Z、数字、下划线
\W匹配非(a-z、A-Z、数字、下划线)
*匹配前一个字符0次或者无限次
+匹配前一个字符1次或无限次
?匹配前一个字符0次或1次
{m}匹配前一个字符m次
{m,n}匹配m-n之间的次数,优先大的次数
*?、 +? 、 ??匹配模式变为非贪婪,尽可能匹配少的次数
^…匹配以…开头
…$匹配以…结尾
()分组,括号内为一组,相当于一个整体
re模块中常用的函数 re.match

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

re.search

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

re.compile

用于编译正则表达式,生成一个正则表达式( Pattern )对象

re.findall

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

re.sub

用来替换字符串。将匹配到的字符串替换为其他字符串。

re.split

使用正则表达式来分割字符串。

分组

在正则表达式中,可以对过滤到的字符串进行分组。分组使用圆括号的方式。

  • group:和group(0)是等价的,返回的是整个满足条件的字符串。

  • groups:返回的是里面的子组。索引从1开始。

  • group(1):返回的是第一个子组,可以传入多个。

使用案例 单字符匹配
import re


# 匹配某个字符串:
text = "abc"
ret = re.match('b',text)
print(ret.group())


# 点(.):匹配任意的字符(除了'\n'):
text = "\nabc"
ret = re.match('.',text)
print(ret.group())


# \d:匹配任意的数字:
text = "aab"
ret = re.match('\d',text)
print(ret.group())


# \D:匹配任意的非数字:
text = "cab"
ret = re.match('\D',text)
print(ret.group())


# \s:匹配的是空白字符(包括:\n,\t,\r和空格):
text = " ab"
ret = re.match('\s',text)
print("="*30)
print(ret.group())
print("="*30)


# \S:非空白字符:
text = "\nab"
ret = re.match('\S',text)
print("="*30)
print(ret.group())
print("="*30)


# \w:匹配的是a-z和A-Z以及数字和下划线:
text = "+bc"
ret = re.match('\w',text)
print("="*30)
print(ret.group())
print("="*30)


# \W:匹配的是和\w相反的:
text = "1bc"
ret = re.match('\W',text)
print("="*30)
print(ret.group())
print("="*30)


# []组合的方式,只要满足中括号中的某一项都算匹配成功:
text = "bc"
ret = re.match('[1b]',text)
print("="*30)
print(ret.group())
print("="*30)

# 使用组合的方式[0-9]\d:
text = "abc"
ret = re.match('[^0-9]',text)
print("="*30)
print(ret.group())
print("="*30)

# 使用组合的方式实现\w:
text = "+bc"
ret = re.match('[^a-zA-Z0-9_]',text)
print("="*30)
print(ret.group())
print("="*30)
多字符匹配
import re


# *:匹配0个或者多个字符:
text = "+abc"
result = re.match('\D*',text)
print(result.group())


# +:匹配1个或者多个字符:
text = "1abc"
result = re.match('\w+',text)
print(result.group())


# ?:匹配前一个字符0个或者1个:
text = "+abc"
result = re.match('\w?',text)
print(result.group())


# {m}:匹配m个字符:
text = "+1abc"
result = re.match('\w{2}',text)
print(result.group())


# {m,n}:匹配m-n之间的个数的字符:
text = "1abc+"
result = re.match('\w{1,3}',text)
print(result.group())
正则表达案例
# 1. 验证手机号码:手机号码的规则是以1开头,第二位可以是34587,后面那9位就可以随意了。
text = "18677889900"
result = re.match("1[34587]\d{9}",text)
print(result.group())


# 2. 验证邮箱:邮箱的规则是邮箱名称是用数字、英文字符、下划线组成的,然后是@符号,后面就是域名了。
text = "hynever@163.com"
result = re.match("\w+@[a-z0-9]+\.[a-z]+",text)
print(result.group())


# 3. 验证URL:URL的规则是前面是http或者https或者是ftp然后再加上一个冒号,再加上一个斜杠,再后面就是可以出现任意非空白字符了。
text = "https://baike.baidu.com/item/Python/407313?fr=aladdin"
result = re.match("(http|https|ftp)://\S+",text)
print(result.group())


# 4. 验证身份证:身份证的规则是,总共有18位,前面17位都是数字,后面一位可以是数字,也可以是小写的x,也可以是大写的X。
text = "36530019870716234x"
result = re.match("\d{17}[\dxX]",text)
print(result.group())
开始/结束/贪婪和非贪婪
import re


# ^:以...开头:
text = "hello world"
result = re.search("world",text)
print(result.group())


# $:以...结尾:
text = "hello world"
result = re.search("hello$",text)
print(result.group())
text = ""
result = re.search("^$",text)
print(result.group())


# 贪婪和非贪婪:
text = "12345"
result = re.search("\d+?",text)
print(result.group())


# 案例1:提取html标签名称:
text = "h1这是标题/h1"
result = re.search(".+?",text)
print(result.group())


# 案例2:验证一个字符是不是0-100之间的数字:
# 0,1,99,100
# 01
text = "101"
result = re.match("0$|[1-9]\d?$|100$",text)
print(result.group())
转义字符和原生字符串
import re


# Python中的转义字符:
raw
text = r"hello\nworld"
print(text)


# 正则表达式中的转义字符:
text = "apple price is $99,range price is $88"
result = re.findall("\$\d+",text)
print(result)


# 原生字符串和正则表达式:
# 正则表达式的字符串解析规则:
# 1. 先把这个字符串放在Python语言层面进行解析。
# 2. 把Python语言层面解析的结果再放到正则表达式层间进行解析。
text = "\cba c"
# result = re.match("\\\\c",text) # \\\\c =(Python语言层面) \\c =(正则表达式层面) \c
result = re.match(r"\\c",text) # \\c =(正则表达式层面) \c
print(result.group())
分组
import re


text = "apple price is $99,orange price is $88"
result = re.search('.+(\$\d+).+(\$\d+)',text)
print(result.groups())

# group()/group(0):匹配整个分组
# group(1):匹配第一个分组
# group(2):匹配第二个分组
# groups():获取所有的分组
re模块中常用函数
import re


# findall:查找所有满足条件的
text = "apple price is $99,orange price is $88"
result = re.findall(r'\$\d+',text)
print(result)

# sub:根据规则替换其他字符串
text = "nihao zhongguo,hello world"
new_text = text.replace(" ","\n")
new_text = re.sub(r' |,','\n',text)
print(new_text)
html = """
div class="job-detail"
    p1. 3年以上相关开发经验 ,全日制统招本科以上学历/p
    p2. 精通一门或多门开发语言(Python,C,Java等),其中至少有一门有3年以上使用经验/p
    p3. 熟练使用ES/mysql/mongodb/redis等数据库;/p
    p4. 熟练使用django、tornado等web框架,具备独立开发 Python/Java 后端开发经验;/p
    p5. 熟悉 Linux / Unix 操作系统nbsp;/p
    p6. 熟悉 TCP/IP,http等网络协议/p
    p福利:/p
    p1、入职购买六险一金(一档医疗+公司全额购买商业险)+开门红+全额年终奖(1年13薪,一般会比一个月高)/p
    p2、入职满一年有2次调薪调级机会/p
    p3、项目稳定、团队稳定性高,团队氛围非常好(汇合员工占招行总员工比例接近50%);/p
    p4、有机会转为招商银行内部员工;/p
    p5、团队每月有自己的活动经费,法定节假日放假安排;/p
    p6、办公环境优良,加班有加班费(全额工资为计算基数,加班不超过晚上10点,平日加班为时薪1.5倍,周末加班为日薪2倍,周末加班也可优先选择调休,管理人性化)。/p
/div
"""
new_html = re.sub(r'.+?',"",html)
print(new_html)


# split:根据规则分割字符串
text = "nihao zhongguo,hello world"
result = re.split(r' |,',text)
print(result)


# compile:编译正则表达式
text = "apple price is 34.56"
# r = re.compile(r"""
# \d+ # 整数部分
# \.? # 小数点
# \d* # 小数部分
# """,re.VERBOSE)
# result = re.search(r,text)
result = re.search(r"""
\d+ # 整数部分
\.? # 小数点
\d* # 小数部分
""",text,re.VERBOSE)
print(result.group())
使用正则表达式爬虫案例(车桌面爬取小姐姐图片)
import requests
import re
import time


headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
}


def get_url1(url):
    resp = requests.get(url=url, headers=headers)
    html1 = resp.text
    urls = re.findall(r"""
    div.*?egeli_pic_li.*?a.*?(http.+?html)
    """, html1, re.VERBOSE | re.DOTALL)
    return urls


def get_pictures_url(url):
    resp = requests.get(url=url, headers=headers)
    html = resp.text
    urls = re.findall(r"""
    div.*?swiper-slide.*?a.*?href.+?(/bizhi.+?html)
    """, html, re.VERBOSE | re.DOTALL)
    return urls


def get_big_pictures_url(url):
    resp = requests.get(url=url, headers=headers)
    html = resp.text
    big_picture_url = re.findall(r"""
    div.*?images_show_zoom.*?href.*?(www.+?/.+?/.+?/)
    """, html, re.VERBOSE | re.DOTALL)
    return big_picture_url


def get_picture_src(url):
    resp = requests.get(url=url, headers=headers)
    html = resp.text
    picture_src = re.findall("""
    div.*?dowm_arc.*?img.*?(http.+?jpg)
    """, html, re.VERBOSE | re.DOTALL)
    return picture_src


def download_picture(url, num1, num2, num3):
    resp = requests.get(url=url, headers=headers)
    if resp.status_code == 200:
        fp = open("./img{}_{}_{}.jpg".format(num1, num2, num3), "wb")
        fp.write(resp.content)
        fp.close()


def main():
    base_url = "https://mm.enterdesk.com/{}.html"
    num1 = 8
    for x in range(8, 10):
        url = base_url.format(x)
        base_url1s = get_url1(url)
        num2 = 1
        for url1 in base_url1s:
            print(url1)
            pictures_url = get_pictures_url(url1)
            num3 = 1
            for picture_url in pictures_url:
                picture_url = "https://mm.enterdesk.com" + picture_url
                print(picture_url)
                big_picture_url = get_big_pictures_url(picture_url)[0]
                big_picture_url = "https://" + big_picture_url
                print(big_picture_url)
                picture_src = get_picture_src(big_picture_url)[0]
                print(picture_src)
                download_picture(picture_src, num1, num2, num3)
                num3 += 1
            num2 += 1
            time.sleep(1)
        num1 += 1
        time.sleep(1)


if __name__ == '__main__':
    main()

最新回复(0)
/jishu00ZVAiKu2QlKd6dxQnJyVMMwU4_2FbYMkb3HVVLw_3D_3D
8