Python爬虫基础-正则表达式!

在这里插入图片描述

前言

正则表达式是对字符串的一种逻辑公式,用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则的字符串”,此字符串用来表示对字符串的一种“过滤”逻辑。正在在很多开发语言中都存在,而非python独有。对其知识点进行总结后,会写一个demo。

1.正则表达式

python是自1.5开始引进re模块进行处理正则的。我先把正则的匹配规则总结一下,再总结re模块相应的方法。

1.1匹配规则

语法解释表达式成功匹配对象
一般字符匹配自身相对应的字符abcabc
.匹配除换行符(\n)以外的任意字符a.cabc
\转义字符,可以改变原字符的意思a.ca.c
\d匹配数字:0~9\dabc1abc
\w匹配单词字符,az;AZ;0~9\w\w\woX2
\s匹配空格字符(\t,\n,\r,\f,\v)a\sca c
\D匹配非数字字符\Dabcaabc
\W匹配非单词字符a\Wca c
\S匹配非空格字符\S\Sc1bc
[]字符集,对应位置上可以是字符集里的任意字符a[def]caec
[^]对字符集当中的内容进行取反a[^def]ca2c
[a-z]指定一个范围字符集a[A-Z]caBc
*允许前一个字符可以出现0次或者无限次a*baaab或b
+前一个字符至少出现1次a+baaab或ab
?前一个字符只能出现一次或者不出现a?bab或b
{m}允许前一个字符只能出现m次a{3}baaab
{m,n}允许前一个字符至少出现m次,最多出现n次(如果不写n,则代表至少出现m次)a{3,5}b和a{3,}aaaab和aaaaaab
^匹配字符串的开始,多行内容时匹配每一行的开始^abcabc
$匹配字符串的结尾,多行内容时匹配每一行的结尾abc&abc
\A匹配字符串开始位置,忽略多行模式\Aabcabc
\Z匹配字符串结束位置,忽略多行模式abc\Zabc
\b匹配位于单词开始或结束位置的空字符串hello \bworldhello world
\B匹配不位于单词开始或结束位置的空字符串he\Bllohello
表示左右表达式任意满足一种即可abc
(…)将被括起来的表达式作为一个分组,可以使用索引单独取出(abc)dabcd
(?P…)为该分组起一个名字,可以用索引或名字去除该分组(?Pabc)dabcd
\number引用索引为number中的内容(abc)d\1abcdabc
(?P=name)引用该name分组中的内容(?Pabc)d(?P=id)abcdabc
(?:…)分组的不捕获模式,计算索引时会跳过这个分组(?:a)b©d\1abcdc
(?iLmsux)分组中可以设置模式,iLmsux之中的每个字符代表一个模式(?i)abcAbc
(?#…)注释,#后面的内容会被忽略ab(?#注释)123ab123
(?=…)顺序肯定环视,表示所在位置右侧能够匹配括号内正则a(?=\d)a1最后的结果得到a
(?!…)顺序否定环视,表示所在位置右侧不能匹配括号内正则a(?!\w)a c最后的结果得到a
(?<=…)逆序肯定环视,表示所在位置左侧能够匹配括号内正则1(?<=\w)a1a
(?<!…)逆序否定环视,表示所在位置左侧不能匹配括号内正则1 (?<!\w)a1 a
(?(id/name)yesno)如果前面的索引为id或者名字为name的分组匹配成功则匹配yes区域的表达式,否则匹配no区域的表达式,no可以省略(\d)(?(1)\d

上面表格中(?iLmsux)这里的”i”, “L”, “m”, “s”, “u”, “x”,它们不匹配任何字串,而对应re模块中(re.S|re.S):

I:re.I# 忽略大小写
L:re.L# 字符集本地化,为了支持多语言版本的字符集使用环境
U :re.U# 使用\\w,\\W,\\b,\\B这些元字符时将按照UNICODE定义的属性
M:re.M # 多行模式,改变 ^ 和 $ 的行为
S:re.S  # '.' 的匹配不受限制,包括换行符
X:re.X # 冗余模式,可以忽略正则表达式中的空白和#号的注释

对于一个特殊字符在正则表达式中是不能正常识别的,如果接触过其他语言我们就这到有一个叫做转移字符的东西的存在,在特殊字符前加用反斜杠接口。比如\n换行\\为反斜杠,在这不再累述。下面来介绍一下re这个模块。

1.2.re模块

此模块主要方法如下

re.match()#尝试从字符串的起始位置匹配一个模式(pattern),如果不是起始位置匹配成功的话,match()就返回None
re.search()#函数会在字符串内查找模式匹配,只要找到第一个匹配然后返回,如果字符串没有匹配,则返回None。
re.findall()#遍历匹配,可以获取字符串中所有匹配的字符串,返回一个列表。
re.compile()#编译正则表达式模式,返回一个对象的模式。(可以把那些常用的正则表达式编译成正则表达式对象,这样可以提高一点效率。)
re.sub()#使用re替换string中每一个匹配的子串后返回替换后的字符串。
re.subn()#返回替换次数
re.split()#按照能够匹配的子串将string分割后返回列表。

1.2.1.re.match()

方法: re.match(pattern, string, flags=0)#pattern:正则表达式(或者正则表达式对象)string:要匹配的字符串flags:修饰符

先看一个最简单的用法

import re
content \='Hello 123 4567 wangyanling REDome'
print(len(content))
result \= re.match('^Hello\\s\\d\\d\\d\\s\\d{4}\\s\\w{10}.\*Dome$', content)
print(result)
print(result.group())
print(result.span())

结果:

匹配规则就不在累述,以上需要注意的是

(1)**.group()**表示的是返回正则匹配的结果

(2)**.span()**表示返回正则匹配的范围

使用:

以上我们已经知道re.matcha()的具体方法,那么接下我来看一下具体使用,对此我们要理解以下几种匹配的感念。

1.泛匹配(.*):匹配所有字符

import re
content \='Hello 123 4567 wangyanling REDome'
result \= re.match('^Hello.\*Dome$', content)
print(result)
print(result.group())
print(result.span())

它的结果是和上面的输出结果完全一样的。

2.目标匹配(()):将需要的字符匹配出来

import re
content \='Hello 123 4567 wangyanling REDome'
result \= re.match('^Hello\\s\\d\\d(\\d)\\s\\d{4}\\s\\w{10}.\*Dome$', content)
print(result)
print(result.group(1))
import re
content \='Hello 123 4567 wangyanling REDome'
result \= re.match('^Hello\\s(\\d+)\\s\\d{4}\\s\\w{10}.\*Dome$', content)
print(result)
print(result.group(1))

结果

以上可以看出:

(1)_()_匹配括号内的表达式,也表示一个组
(2)+ 匹配1个或多个的表达式
* 匹配0个或多个的表达式
(3).group(1)—输出第一个带有()的目标

3.贪婪匹配(.*()):匹配尽可能少的的结果

import re
content \='Hello 123 4567 wangyanling REDome'
result \= re.match('^H.\*(\\d+).\*Dome$', content)
print(result)
print(result.group(1))

结果

 **4.贪婪匹配(.\*?()):匹配尽可能多的结果**
import re
content \='Hello 123 4567 wangyanling REDome'
result \= re.match('^H.\*?(\\d+).\*?Dome$', content)
print(result)
print(result.group(1))

结果

以上3,4两个匹配方式请尽量采用非贪婪匹配

**5.其他**

换行:

import re
content \='''Hello 123 4567 
         wangyanling REDome'''

result \= re.match('^H.\*?(\\d+).\*?Dome$', content,re.S)#re.S
print(result.group(1))
result \= re.match('^H.\*?(\\d+).\*?Dome$', content)
print(result.group(1))

结果:

转义字符:

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

结果:

其中re.I使匹配对大小不敏感,re.S匹配包括换行符在内的所有字符,\进行处理转义字符。匹配规则中有详细介绍。

1.2.2.re.search()

方法:

re.search(pattern, string, flags=0)#pattern:正则表达式(或者正则表达式对象)string:要匹配的字符串flags:修饰符
    #re.match()和re.search()用法类似唯一的区别在于re.match()从字符串头开始匹配,若头匹配不成功,则返回None    

对比一下与match()

import re
content \='Hello 123 4567 wangyanling REDome'
result \= re.match('(\\d+)\\s\\d{4}\\s\\w{10}.\*Dome$', content)
print(result)#从开头开始查找,不能匹配返回None
result = re.search('(\\d+)\\s\\d{4}\\s\\w{10}.\*Dome$', content)
print(result)
print(result.group())

结果:

可以看出两个使用基本一致,search从头开始匹配,如果匹配不到就返回none.

1.2.3.re.findall()

方法: re.finditer(pattern, string, flags=0)#pattern:正则表达式(或者正则表达式对象)string:要匹配的字符串flags:修饰符

与re.search()类似区别在于re.findall()搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。找到 RE 匹配的所有子串,并把它们作为一个迭代器返回。

import re

html \= '''
  <div>
  <li><a href="" singer="鲁迅"\>呐喊</a></li>
  <li><a href="#" singer="贾平凹"\>废都</a></li>
  <li class\="active"\><a href="#" singer="路遥"\>平凡世界</a></li>
  <span class\="rightSpan"\>谢谢支持</span>
  </div>
'''
regex\_4='<a.\*?>(.\*?)</a>'
results\=re.findall(regex\_4,html,re.S)
print(results)
for result in results:
    print(result)

结果:

1.2.4.re.compile()

编译正则表达式模式,返回一个对象的模式。

方法: re.compile(pattern,flags=0)#pattern:正则表达式(或者正则表达式对象);flags:修饰符

看一个demo

import re
content \='Hello 123 4567 wangyanling REDome wangyanling 那小子很帅'
rr \= re.compile(r'\\w\*wang\\w\*')
result \=rr.findall(content)
print(result)

结果:

我们可以看出compile 我们可以把它理解为封装了一个公用的正则,类似于方法,然后功用。

1.2.5.其他

re.sub 替换字符

方法: re.sub(pattern, repl, string, count=0, flags=0)#pattern:正则表达式(或者正则表达式对象)repl:替换的字符串string:要匹配的字符串count:要替换的个数flags:修饰符

re.subn 替换次数

方法: re.subn(pattern, repl, string, count=0, flags=0)#pattern:正则表达式(或者正则表达式对象)repl:替换的字符串string:要匹配的字符串count:要替换的个数flags:修饰符

re.split()分隔字符

方法

re.split(pattern, string,\[maxsplit\])#正则表达式(或者正则表达式对象)string:要匹配的字符串;maxsplit:用于指定最大分割次数,不指定将全部分割

2.案例:爬取猫眼信息,写入txt,csv,下载图片

2.1.获取单页面信息

def get\_one\_page(html):
    pattern\= re.compile('<dd>.\*?board-index.\*?>(\\d+)</i>.\*?data-src="(.\*?)".\*?name"><a.\*?>(.\*?)</a>.\*?star">(.\*?)</p>.\*?releasetime'
                         + '.\*?>(.\*?)</p>.\*?score.\*?integer">(.\*?)</i>.\*?>(.\*?)</i>.\*?</dd>',re.S)#这里就用到了我们上述提到的一些知识点,非贪婪匹配,对象匹配,修饰符
    items = re.findall(pattern,html)
    for item in  items:
        yield {
            'rank' :item\[0\],
            'img':  item\[1\],
            'title':item\[2\],
            'actor':item\[3\].strip()\[3:\] if len(item\[3\])>3 else '',  
            'time' :item\[4\].strip()\[5:\] if len(item\[4\])>5 else '',
            'score':item\[5\] + item\[6\]
        }

对于上面的信息我们可以看出是存到一个对象中那么接下来我们应该把它们存到文件当中去。

2.2.保存文件

我写了两种方式保存到txt和csv这些在python都有涉及,不懂得可以去翻看一下。

2.2.1.保存到txt

def write\_txtfile(content):
    with open("Maoyan.txt",'a',encoding='utf-8') as f:
        #要引入json,利用json.dumps()方法将字典序列化,存入中文要把ensure\_ascii编码方式关掉
        f.write(json.dumps(content,ensure\_ascii=False) + "\\n")
        f.close()

结果:

以上看到并非按顺序排列因为我用的是多线程。

2.2.2.保存到csv

def write\_csvRows(content,fieldnames):
    '''写入csv文件内容'''
    with open("Maoyao.csv",'a',encoding='gb18030',newline='') as f:
        #将字段名传给Dictwriter来初始化一个字典写入对象
        writer = csv.DictWriter(f,fieldnames=fieldnames)
        #调用writeheader方法写入字段名
        writer.writerows(content)
        f.close()

结果:

那么还有一部就是我们要把图片下载下来。

2.2.3.下载图片

def download\_img(title,url):
   r\=requests.get(url)
   with open(title+".jpg",'wb') as f:
        f.write(r.content)

2.3.整体代码

这里面又到了多线程在这不在叙述后面会有相关介绍。这个demo仅做一案例,主要是对正则能有个认知。上面写的知识点有不足的地方望大家多多指教。

#抓取猫眼电影TOP100榜
from multiprocessing import Pool
from requests.exceptions import RequestException
import requests
import json
import time
import csv
import re
def get\_one\_page(url):
    '''获取单页源码'''
    try:
        headers \= {
            "User-Agent":"Mozilla/5.0(WindowsNT6.3;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/68.0.3440.106Safari/537.36"
        }
        res \= requests.get(url, headers=headers)
        # 判断响应是否成功,若成功打印响应内容,否则返回None
        if res.status\_code == 200:
            return res.text
        return None
    except RequestException:
        return None
def parse\_one\_page(html):
    '''解析单页源码'''
    pattern \= re.compile('<dd>.\*?board-index.\*?>(\\d+)</i>.\*?data-src="(.\*?)".\*?name"><a.\*?>(.\*?)</a>.\*?star">(.\*?)</p>.\*?releasetime'
                         + '.\*?>(.\*?)</p>.\*?score.\*?integer">(.\*?)</i>.\*?>(.\*?)</i>.\*?</dd>',re.S)
    items \= re.findall(pattern,html)
    #采用遍历的方式提取信息
    for item in  items:
        yield {
            'rank' :item\[0\],
            'img':  item\[1\],
            'title':item\[2\],
            'actor':item\[3\].strip()\[3:\] if len(item\[3\])>3 else '',  #判断是否大于3个字符
            'time' :item\[4\].strip()\[5:\] if len(item\[4\])>5 else '',
            'score':item\[5\] + item\[6\]
        }

def write\_txtfile(content):
    with open("Maoyan.txt",'a',encoding='utf-8') as f:
        #要引入json,利用json.dumps()方法将字典序列化,存入中文要把ensure\_ascii编码方式关掉
        f.write(json.dumps(content,ensure\_ascii=False) + "\\n")
        f.close()
def write\_csvRows(content,fieldnames):
    '''写入csv文件内容'''
    with open("Maoyao.csv",'a',encoding='gb18030',newline='') as f:
        #将字段名传给Dictwriter来初始化一个字典写入对象
        writer = csv.DictWriter(f,fieldnames=fieldnames)
        #调用writeheader方法写入字段名
        #writer.writeheader()            ###这里写入字段的话会造成在抓取多个时重复.
        writer.writerows(content)
        f.close()
def download\_img(title,url):
   r\=requests.get(url)
   with open(title+".jpg",'wb') as f:
        f.write(r.content)
def main(offset):
    fieldnames \= \["rank","img", "title", "actor", "time", "score"\]
    url \= "http://maoyan.com/board/4?offset={0}".format(offset)
    html \= get\_one\_page(url)
    rows \= \[\]
    for item in parse\_one\_page(html):
        #download\_img(item\['rank'\]+item\['title'\],item\['img'\])
        write\_txtfile(item)
        rows.append(item)
    write\_csvRows(rows,fieldnames)

if \_\_name\_\_ == '\_\_main\_\_':
    pool \= Pool()
    #map方法会把每个元素当做函数的参数,创建一个个进程,在进程池中运行.
    pool.map(main,\[i\*10 for i in range(10)\])

如果你是准备学习Python或者正在学习(想通过Python兼职),下面这些你应该能用得上: 包括:Python安装包、Python web开发,Python爬虫,Python数据分析,人工智能、自动化办公等学习教程。带你从零基础系统性的学好Python!在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/909710.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

lvgl白屏问题(LCD长时间白屏)和优化lvgl

开机白屏时间过长 -- 这里我们不考虑是lvgl占的内存太大的问题&#xff0c;这里考虑的是为什么lcd屏幕启动后会有长时间的白屏。 首先我们要了解lvgl的相关操作&#xff0c;主要集中在一个函数中。只有程序执行到了这个函数&#xff0c;lvgl的屏幕才会显现出来 总结来说就是l…

雷池社区版 7.1.0 LTS 发布了

LTS&#xff08;Long Term Support&#xff0c;长期支持版本&#xff09;是软件开发中的一个概念&#xff0c;表示该版本将获得较长时间的支持和更新&#xff0c;通常包含稳定性、性能改进和安全修复&#xff0c;但不包含频繁的新特性更新。 作为最受欢迎的社区waf&#xff0c…

【系统分析师】-案例综合知识大全

1、表示处理流程的工具 图形工具、表格工具和语言工具。 其中常见的图形工具包括程序流程图、IPO 图、盒图、问题分析图、判定树&#xff0c; 表格工具包括判定表&#xff0c; 语言工具包括过程设计语言 2、用例建模过程 识别参与者、合并需求获得用例、细化用例描述和调…

python爬取旅游攻略(1)

参考网址&#xff1a; https://blog.csdn.net/m0_61981943/article/details/131262987 导入相关库&#xff0c;用get请求方式请求网页方式&#xff1a; import requests import parsel import csv import time import random url fhttps://travel.qunar.com/travelbook/list.…

G. Welcome to Join the Online Meeting!【CCPC2024哈尔滨站】

G. Welcome to Join the Online Meeting 思路: 挺简单的BFS思路 图论题写的比较少&#xff0c;算是补题吧 代码: #include <bits/stdc.h> #define endl \n #define int long long #define pb push_back #define pii pair<int,int> const int MOD 1e97; const …

《图像滤波算法综述》

一、引言 在数字图像处理的世界里&#xff0c;滤波是一项关键技术。通过对图像应用滤波算法&#xff0c;可以有效去除噪声、增强图像的细节并显著提升图像质量。本篇内容将为您深入介绍几种常见的图像滤波算法及其原理和应用场景。 二、图像滤波算法的分类 图像滤波算法可以…

RK3568开发板静态IP地址配置

1. 连接SSH MYD-LR3568 开发板设置了静态 eth0:1 192.168.0.10 和 eth1:1 192.168.1.10&#xff0c;在没有串口时调试开发板&#xff0c;可以用工具 SSH 登陆到开发板。 首先需要用一根网线直连电脑和开发板&#xff0c;或者通过路由器连接到开发板&#xff0c;将电脑 IP 手动设…

(蓝桥杯C/C++)——基础算法(上)

目录 一、二分法 1.二分法简介 二分法简介-解题步骤 2.整数二分-简介 整数二分-模板 3.浮点二分-简介 浮点二分-模板 4.二分答案-简介 二分答案-模板​​​​​​​ 二、位运算 1.位运算简介 2.常见的位运算 按位与AND(&) 按位或OR( | ) 按位异或…

【RAG系列】KG-RAG 用最简单的方式将知识图谱引入RAG

目录 前言 一、引入知识图谱的作用 二、引入知识图谱的挑战 三、KG-RAG的理论 query多跳有限性 知识局部密集性 四、KG-RAG的方法 向量入库 向量相似搜索 扩展子图 LLM Rerank LLM response 五、效果比对 六、源码 总结 前言 本文介绍一种比较新颖的RAG范式&am…

6.《双指针篇》---⑥和为S的两个数字(中等但简单)(牛客)

题目传送门 方法一&#xff1a;暴力解法。双循环 方法二&#xff1a;双指针&#xff08;推荐&#xff09; 1.定义一个顺序表&#xff0c;定义左右双指针 2.while循环。判断array[left] array[right] 的值。 3.若等于则将这两个值加入数组。并break 4.若大于则right-- 5.若小于…

【学术论文投稿】Python网络爬虫全攻略:从零到一,打造你的数据收集利器

【IEEE出版 | 中国石油大学&#xff08;华东&#xff09;主办】第六届信息与计算机前沿技术国际学术会议(ICFTIC 2024)_艾思科蓝_学术一站式服务平台 更多学术会议论文投稿请看&#xff1a;https://ais.cn/u/nuyAF3 目录 引言 什么是网络爬虫&#xff1f; Python网络爬虫的…

LWIP通信协议UDP发送、接收源码解析

1.UDP发送函数比较简短&#xff0c;带操作系统和裸机一样。以下是udp_sendto源码解析&#xff1b; 2.LWIP源码UDP接收数据 2.1.UDP带操作系统接收数据&#xff0c;以下是源码解析&#xff1b; 2.2.UDP裸机接收数据&#xff0c;以下是源码解析

3^100的位数判断

3^100的位数判断 问题来源 字节面试&#xff0c;面试官提问&#xff1a;口算估计3^100的位数&#xff0c;或是给出位数估计范围。 解决方案 方法一&#xff1a; 该方法纯口算&#xff0c;可得一个较为准确的一个范围 2 100 < 3 100 < 4 100 2^{100}<3^{100}<…

Vue2进阶之Vue3高级用法

Vue3高级用法 响应式Vue2&#xff1a;Object.definePropertyObject.definePropertythis.$set设置响应式 Vue3&#xff1a;Proxy composition APIVue2 option API和Vue3 compositionAPIreactive和shallowReactivereadonly效果toRefs效果 生命周期main.jsindex.htmlLifeCycle.vue…

大微DW421专为电子雾化器设计的大功率MEMS硅麦咪头芯片

在电子雾化器领域&#xff0c;一款高性能、高稳定性的咪头是实现优质用户体验的关键。大微DW421功率咪头&#xff0c;广泛应用在电子雾化类设备的21W大功率集成硅麦咪头芯片&#xff0c;集成了最新的MEMS硅基膜微机电系统技术&#xff0c;赋予了咪头更高的灵敏度和稳定性&#…

机器人零位、工作空间、坐标系及其变换,以UR5e机器人为例

机器人中的主要坐标系 在机器人中&#xff0c;常用的坐标系包括&#xff1a; 基坐标系&#xff08;Base Frame&#xff09;&#xff1a;固定在机器人基座上的坐标系&#xff0c;用于描述机器人的整体位置和方向&#xff0c;是其他所有坐标系的参考点。 连杆坐标系&#xff08…

「Mac畅玩鸿蒙与硬件24」UI互动应用篇1 - 灯光控制小项目

本篇将带领你实现一个互动性十足的灯光控制小项目&#xff0c;用户可以通过点击按钮来控制灯光的开关。该项目将涉及状态管理、动态图片加载以及按钮交互&#xff0c;是学习鸿蒙应用开发的重要基础。 关键词 UI互动应用状态管理动态图片加载用户交互 一、功能说明 在这个灯光…

vue+websocket实现即时聊天平台

目录 1 什么是websocket 2 实现步骤 2.1 导入依赖 2.2 编写代码 1 什么是websocket WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它主要用于在客户端和服务器之间建立持久的连接&#xff0c;允许实时数据交换。WebSocket 的设计目的是为了提高 Web 应用程序的…

本地跟单软件,精准跟随、实时同步 轻松实现自动跟单 MT4免费EA

指标名称&#xff1a;本地跟单软件 版本&#xff1a;MT4 ver. 2.01&#xff08;EA&#xff09; 我们经常在一些论坛或网站上看到一些朋友提供的观摩账户吧&#xff0c;可以看到别人的账户情况&#xff0c;遇到有实力的交易者&#xff0c;很是羡慕啊。 如果我们自己的账户可以…

基于stm32的智能电子称(开源)

功能演示 基于stm32的智能电子称 简介 这是最近别人让我帮他做的一个毕业设计&#xff0c;总体来说非常简单&#xff0c;半天都不需要就可以实现&#xff0c;我做完之后&#xff0c;打算开源在这里让大家进行学习&#xff0c;我们先看一下他的任务书吧: 主要内容与基本要求&am…