当前位置: 首页 > news >正文

爬虫基础入门之爬取豆瓣电影Top250-Re正则的使用

网址:豆瓣电影 Top 250

本案例所需要的模块
requests (用于发送HTTP请求)re (用于字符串匹配和操作)

确定需要爬取的数据 :

  1. 电影的名称
  2. 电影的年份
  3. 电影的评分
  4. 电影评论人数

一. 发送请求 模拟浏览器向服务器发送请求

准备工作 -分析页面:
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>.*?)&nbsp.*?'
                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>.*?)&nbsp.*?'
                    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())

相关文章:

  • 另外一个用于测试内存屏障差异的 C 语言示例程序(自己测试)
  • springboot集成jackson-dataformat-xml实现发送XML请求和XML响应参数处理
  • docker离线安装记录
  • 人工智能基础知识笔记一:核函数
  • 使用 BFS 解决 最短路问题
  • springboot005学生心理咨询评估系统(源码+数据库+文档)
  • Xinference和ollama有什么区别
  • 【CSS】HTML元素布局基础总结
  • 沁恒CH32V307RCT6烧写hex文件时报错“设置芯片型号失败”
  • IP---网络类型
  • 基于 MySQL 递归 CTE 实现表,父级id与子级id拼接
  • 零信任应用侧理性选择并期许未来
  • 捷 C++ 课程学习笔记:STL 应用与复杂度分析
  • 【react】基础教程
  • 【Linux-网络】从逻辑寻址到物理传输:解构IP协议与ARP协议的跨层协作
  • 求解动态完全未知的连续时间非线性系统的优化控制的全局自适应动态规划算法
  • KubeSphere平台安装
  • 面试八股文--数据库基础知识总结(1)
  • 应无所住而生其心:心灵的自在与解脱
  • 深入理解IP子网掩码子网划分{作用} 以及 不同网段之间的ping的原理 以及子网掩码的区域划分
  • 马上评|去年维修竣工的鼓楼,今年就“瀑布式落瓦”
  • 离休干部周惠梅逝世,曾从事多年地下革命工作
  • “敌人已经够多了”,菲总统马科斯:愿与杜特尔特家族和解
  • “十五五”规划编制工作开展网络征求意见活动
  • 黄仁勋的新逻辑:从“卖铲人”到“全球AI基建运营商”
  • 4月22城新房价格上涨:上海一二手房价环比均上涨,核心城市土地热带动市场热度提升