数据解析的目的是不拿到页面的全部内容,只拿到部分我们想要的内容内容。
Re解析就是正则解析,效率高准确性高。学习本节内容前需要学会基础的正则表达式。
一、正则匹配规则
1、常用元字符
. 匹配除换行符以外的字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符
2、量词:控制前面的元字符出现的次数
* 重复0次或更多次
+ 重复一次或更多次
? 重复0次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
3、贪婪匹配和非贪婪匹配(重要)
.* 贪婪匹配
.*? 惰性匹配
二、Re模块
re模块中只需要记住以下几种功能就够用了
1、re.findall
匹配字符串中所有的符合正则的内容,返回list
import re
list = re.findall(r"\d+","我的电话号是:10086,小红的电话是100000")
print(list)
#运行结果:['10086', '100000']
2、re.finditer(重点)
和findall差不多,只不过这时返回的是迭代器
因为findall返回列表,当页面上数据较大时,list就会非常大,效率不高。
从迭代器中拿到内容需要.group()
import re
it = re.finditer(r"\d+","我的电话号是:10086,小红的电话是100000")
print(it)
#返回结果:<callable_iterator object at 0x000001914FB0D850>
for i in it:
print(i.group())
#返回结果
# 10086
# 100000
3、re.search
进行匹配,但是如果匹配到了第一个结果,就会返回这个结果。如果匹配不上search返回的是None。
如果拿到了返回的依然是迭代器,使用.group()取到匹配的内容
import re
s = re.search(r"\d+","我的电话号是:10086,小红的电话是100000")
print(s.group())
#返回结果 10086
4、re.match
只能从字符串的开头进行匹配。相当于在正则表达式前面加了一个^
import re
s1 = re.match(r"\d+","我的电话号是:10086,小红的电话是100000")
print(s1.group()) #报错,未找到
s2 = re.match(r"\d+","10086,小红的电话是100000")
print(s2.group()) #返回10086
5、预加载正则表达式(re.compile(r"\d+"))
当后面正则较为复杂的时候,就可以使用预加载,先写规则。
import re
obj = re.compile(r"\d+")
ret = obj.finditer("我的电话号是:10086,小红的电话是100000")
for it in ret:
print(it.group())
6、单独提取正则中的内容
re.S的作用是让.能匹配换行符
obj = re.compile(r"<div class='.*?'><span id='\d'>(?P<hello>.*?)</span></div>", re.S)#re.S的作用是让.能匹配换行符
ret = obj.finditer(s)
for it in ret:
print(it.group("hello"))
# 小米
# 华为
# 三星
# 苹果
三、实战:豆瓣top250
1、需求:
拿到排行榜的电影名称,年份,评价,打分,并使用csvwriter写入到csv文件中
2、思路:
(1)拿到页面源代码 requests
(2)通过re来提取到想要的有效信息 re
import re
import requests
import csv
url = "http://movie.douban.com/top250"
headers ={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"
}
resp = requests.get(url,headers=headers)
page_content = resp.text
#解析数据
obj = re.compile(r'<li>.*?<div class="item".*?<span class="title">(?P<name>.*?)</span>.*?'
r'<p class="">.*?<br>(?P<time>.*?) .*?'
r'<span class="rating_num" property="v:average">(?P<score>.*?)</span>.*?'
r'<span>(?P<judge>.*?)人评价</span>', re.S)
ret = obj.finditer(page_content)
f = open("data.csv",mode="w",encoding="utf-8")
csvwriter = csv.writer(f)
for it in ret:
# print(it.group("name"))
# print(it.group("time").strip())
# print(it.group("score"))
# print(it.group("judge"))
dic = it.groupdict()
dic['time'] = dic['time'].strip()#因为年份后面有空格,单独处理
csvwriter.writerow(dic.values())
resp.close()
结果:
四、实战:屠戮盗版天堂电影信息
1、需求:
想拿到2024必看篇的所有电影下载地址。
2、思路
(1)定位到2024必看篇
(2)从2024必看篇中提取到子页面的链接地址
(3)请求子页面的链接地址,拿到我们想要的下载地址
注:此站点进行了反爬措施,需要添加User-Agent和Cookie。并且编码为gb2312,需要设置。
import requests
import re
url = "https://www.dytt89.com/"
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",
"Cookie":"guardok=VxXtQIYG+FVwAJLu76U/QvRiEyoXdFVFLcCsBijzPzwTF6G1uhyRle6K2pHzz4oYx32wQY0n0W/gv80enczOuA==; __vtins__KSHU1VNqce379XHB=%7B%22sid%22%3A%20%222408df8b-f3ee-5771-b99c-a0b206621ca0%22%2C%20%22vd%22%3A%201%2C%20%22stt%22%3A%200%2C%20%22dr%22%3A%200%2C%20%22expires%22%3A%201722072217375%2C%20%22ct%22%3A%201722070417375%7D; __51uvsct__KSHU1VNqce379XHB=1; __51vcke__KSHU1VNqce379XHB=8133f70d-0abb-5af7-91dc-fbf00581cf6a; __51vuft__KSHU1VNqce379XHB=1722070417377; Hm_lvt_93b4a7c2e07353c3853ac17a86d4c8a4=1722070418; Hm_lpvt_93b4a7c2e07353c3853ac17a86d4c8a4=1722070418; HMACCOUNT=4AF1B6073CA4B2F3; Hm_lvt_8e745928b4c636da693d2c43470f5413=1722070418; Hm_lpvt_8e745928b4c636da693d2c43470f5413=1722070418; Hm_lvt_0113b461c3b631f7a568630be1134d3d=1722070418; Hm_lpvt_0113b461c3b631f7a568630be1134d3d=1722070418"
}
resp = requests.get(url, verify=False,headers=headers)#verify=False去掉安全验证
resp.encoding = "gb2312"
# print(resp.text)
#定位到2024必看
obj1 = re.compile(r'2024必看热片.*?<ul>(.*?)</ul>', re.S)
obj2 = re.compile(r"a href='(?P<href>.*?)'",re.S)
obj3 = re.compile(r'译 名(?P<movie>.*?)<br />.*?WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">', re.S)
result1 = obj1.finditer(resp.text)
for it in result1:
ul = it.group()
#提取子页面链接
result2 = obj2.finditer(ul)
for it2 in result2:
href = "https://www.dytt89.com/"+it2.group("href")
#请求子页面链接
resp2 = requests.get(href, headers=headers,verify=False)
resp2.encoding = "gb2312"
#拿到子页面链接的下载地址
result3 = obj3.finditer(resp2.text)
for it3 in result3:
print(it3.group("movie"))
print(it3.group("download"))
resp2.close()
resp.close()