爬虫基础入门之爬取豆瓣电影Top250-Re正则的使用
网址:豆瓣电影 Top 250
requests (用于发送HTTP请求) | re (用于字符串匹配和操作) |
确定需要爬取的数据 :
- 电影的名称
- 电影的年份
- 电影的评分
- 电影评论人数
一. 发送请求 模拟浏览器向服务器发送请求
准备工作 -分析页面:
F12 or 右击点击检查 查看页面源代码 目的是确定数据是否为静态数据
Ctrl + F 快捷键打开搜索框 将我们所需要爬取的数据输入
发现数据都在前端的页面当中 即拿到页面的源代码 从中提取数据
接着复制浏览器的URL地址 在pycharm里面构建请求
# 导包
import requests
import re
url = 'https://movie.douban.com/top250'
# 构建请求体
# user-agent 即UA 为浏览器的基本信息 爬虫程序就是伪装成浏览器从网页拿数据
headers = {
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0',
}
resp = requests.get(url=url, headers=headers)
print(resp.text.encode('gbk', 'ignore').decode('gbk'))
我这里会出现一个编码的问题 查找资料之后 需要先用 GBK 编码,加个 ignore 丢弃错误的字符,然后再解码
之后在拿到的网页源代码中 老样子Ctrl+F 检查爬取的数据是否存在
二. 解析数据 提取数据
OK 接着我们需要从页面源代码中提取出我们想要的数据
分析页面的结构
ex = re.compile(r'<div class="hd">.*?<span class="title">(?P<name>.*?)</span>',re.S)
# 不需要的内容通过.*?过掉 给需要取出的内容 取值为name 类似字典
result = ex.findall(text)
# findall返回的是一个列表
# finditer 返回的是一个迭代器 后续需要通过for循环取出
# re.search() 返回的是match对象 需要.group拿数据 只能拿到匹配到的第一个数据
# re.match() 从头开始匹配 类似^
# 预加载正则表达式 后续可重复使用该正则
# re.complie(r'正则')
继续编写正则 想象这是一篇文章 不需要的通过.*?过滤出去 用(.*?)保留下来
后续通过类似 键值对取值取出
我们通过迭代器的方式 提取
ex = re.compile(r'<div class="hd">.*?<span class="title">(?P<name>.*?)'
r'</span>.*?<p class="">.*?<br>(?P<year>.*?) .*?'
r'<span class="rating_num" property="v:average">(?P<judge>.*?)</span>.*?'
r'<span>(?P<num>.*?)人评价</span>.*?'
r'<p class="quote"><span class="inq">(?P<intro>.*?)。</span></p>',re.S)
result = ex.finditer(text)
for i in result:
# 通过.group取数据
# 检验拿到的数据
print(i.group('name'))
# 去除前面的空格
print(i.group('year').strip())
print(i.group('judge'))
print(i.group('num'))
三.保存数据 存储为 csv excel 文件
接着我们保存爬取的数据 需要用到csv模块
# 导包
import csv
f = open('movie.csv','w',encoding='utf-8',newline='')
# newline 解决空行的问题
csv_writer = csv.writer(f)
# 写入表头
csv_writer.writerow(['电影名','年份','评分','评价人数'])
for i in result:
# 将数据存储为字典格式
dit = i.groupdict()
# 处理年份前的空格
dit['year'] = dit['year'].strip()
#将值写入csv文件
csv_writer.writerow(dit.values())
# 与with open 不同的是 open需要手动关闭
f.close()
另外一种保存数据的方式 pandas 个人觉得pandas方便很多
以下是实现代码
# 导包
import pandas as pd
# 定义一个空列表 后面将dit字典数据存储进去
lis = []
for i in result:
dit = i.groupdict()
# 处理年份前的空格
dit['year'] = dit['year'].strip()
# 只需要改这两行代码
lis.append(dit)
pd.DataFrame(lis).to_excel('movie1.xlsx',index=False)
运行结果如下 如果在excel 中打开此文件 会乱码 需要将编码格式写为 utf-8-sig
多页采取的话 需要分析一下 请求的url地址 之后构建个for循环去遍历
分析二三页的地址 可得 start参数间隔25
其实是为了学习正则而采用正则去提取数据 只有在特定的情况下才使用正则 一般使用其它的方法
以下是本次案例的所有代码 供学习交流使用
import requests
import re
import csv
f = open('movie.csv', 'w', encoding='utf-8-sig',newline='')
csv_writer = csv.writer(f)
csv_writer.writerow(['电影名', '年份', '评分', '评价人数'])
for page in range(0, 250, 25):
url = f'https://movie.douban.com/top250?start={page}&filter='
headers = {
'user-agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0',
}
resp = requests.get(url=url, headers=headers)
text = resp.text.encode('gbk', 'ignore').decode('gbk')
ex = re.compile(r'<div class="hd">.*?<span class="title">(?P<name>.*?)'
r'</span>.*?<p class="">.*?<br>(?P<year>.*?) .*?'
r'<span class="rating_num" property="v:average">(?P<judge>.*?)</span>.*?'
r'<span>(?P<num>.*?)人评价</span>.*?'
, re.S)
result = ex.finditer(text)
for i in result:
dit = i.groupdict()
# 处理年份前的空格
dit['year'] = dit['year'].strip()
csv_writer.writerow(dit.values())