python爬虫学习-day2正则表达式

今天要学会正则表达式。使用菜鸟教程的正则表达式教程,主要使用python正则表达式函数进行学习。

正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a到z之间的字母)和特殊字符(称为”元字符”)。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。

简介

我们很可能使用 ? 和 通配符来查找硬盘上的文件。? 通配符匹配文件名中的 0 个或 1 个字符,而 通配符匹配零个或多个字符。像 “data(\w)?.dat” 这样的模式将查找下列文件:

1
2
3
4
5
data.dat
data1.dat
data2.dat
datax.dat
dataN.dat

使用 字符代替 ? 字符扩大了找到文件的数量,即”data.\.data”。* 即通配符。

1
2
3
4
5
6
data.dat
data1.dat
data2.dat
data12.dat
datax.dat
dataXYZ.dat

简单实例: ^[0-9]+abc$,其含义是:

  1. ^为匹配输入字符串的开始位置
  2. [0-9]+匹配多个数字,[0-9]匹配单个数字,+匹配一个或者多个
  3. abc$匹配字符abc并以abc结尾,$为匹配输入字符串的结束位置。

我们在写用户注册表时,只允许用户名包含字符、数字、下划线和连接字符(-),并设置用户名长度,可以用以下正则表达式设定: ^[a-z0-9_-]{3,15}$

为什么使用正则表达式?

通过使用正则表达式,可以:

  1. 测试字符串内的模式。例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
  2. 替换文本。可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
  3. 基于模式匹配从字符串中提取子字符串。可以查找文档内或输入域内特定的文本。

python正则表达式

re模块使python语言拥有全部的正则表达式功能。

re.match函数

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。函数语法:re.match(pattern, string, flags=0)。

  1. pattern: 匹配的正则表达式
  2. string: 要匹配的字符串
  3. flags: 标志位,用于控制正则表达式的匹配方式

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

  1. group(num=0): 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
  2. groups(): 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

例子:
image.png
其中span()函数span() 返回一个元组包含匹配 (开始,结束) 的位置。

image.png
前面的一个r表示字符串为非转义的原始字符串,让编译器忽略反斜杠,也就是忽略转义字符。但是这个字符串里没有反斜杠,所以这个r可有可无。 (.*) 第一个匹配分组,.*代表匹配除换行符之外的所有字符;(.*?)第二个匹配分组,.*?后面多个问号,代表非贪婪模式,也就是说只匹配符合条件的最少字符;后面的一个.* 没有括号包围,所以不是分组,匹配效果和第一个一样,但是不计入匹配结果中。

re.search函数

re.search 扫描整个字符串并返回第一个成功的匹配。函数语法:re.search(pattern, string, flags=0),参数含义与match函数的相同。

例子:
image.png

re.match与re.search的区别

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

检索与替换

Python 的 re 模块提供了re.sub用于替换字符串中的匹配项。语法:re.sub(pattern, repl, string, count=0, flags=0)。参数:

  1. pattern : 正则中的模式字符串。
  2. repl : 替换的字符串,也可为一个函数。
  3. string : 要被查找替换的原始字符串。
  4. count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。

例子:
image.png

repl参数一个函数

下面例子将字符串中的匹配的数字乘以2:
image.png

记住要加?号,否则没有命名成功为group:
image.png

re.compile函数

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。

语法格式为:re.compile(pattern[, flags])

参数:

  1. pattern : 一个字符串形式的正则表达式
  2. flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
  • re.I 忽略大小写
  • re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
  • re.M 多行模式
  • re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
  • re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
  • re.X 为了增加可读性,忽略空格和 # 后面的注释

re.findall函数

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。语法格式为:findall(string, pos, endpos)

时间关系,其他知识今后再学习

任务

结合requests、re两者的内容爬取 https://movie.douban.com/top250 中的内容,要求抓取名次、影片名称、国家、导演等字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests
import re
import csv

# https://blog.csdn.net/bmjhappy/article/details/80512917 中文字符串匹配
def movie_info(url):
headers = {
'User-Agent':"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
}

res = requests.get(url, headers=headers)
ranks = re.findall(' <em class="">(.*?)</em>',res.text, re.S)
names = re.findall('<span class="title">([\u4e00-\u9fa5]+)</span>',res.text, re.S)
countries = re.findall('&nbsp;/&nbsp;([\u4e00-\u9fa5]+)&nbsp;/&nbsp;', res.text, re.S)
text = re.sub('导演: ',"",res.text) # :中文标点符号
directors = re.findall('<p class="">(.*?)&nbsp;&nbsp;', text, re.S)
scores = re.findall('<span class="rating_num" property="v:average">(.*?)</span>',res.text,re.S)

for rank,name,country,director,score in zip(ranks,names,countries,directors,scores):
writer.writerow([rank,name,country,director,score])


if __name__ == '__main__':

file = open('E:/NLP/movie.csv','w+',encoding='utf-8',newline='')
writer = csv.writer(file)
writer.writerow(['rank','name','country','director','score'])

for i in range(0,250,25):
url = 'https://movie.douban.com/top250?start={}&filter='.format(i)
movie_info(url)

过程中遇到的问题:

  1. 本来是不打算加请求头,但是在查找资料时发现不加请求头可能会被阻止(其实不加好像也可以爬取)
  2. 爬取的数据我使用csv存储
  3. 过程中需要用到中文匹配的知识,一开始没什么头绪,后来查找博客发现使用[\u4e00-\u9fa5]代表中文字符
  4. 一开始只能抓到前20多部电影,后来经群里的同学提示,可以通过for循环来跨页爬取。

内容显示如下:

image.png