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

Python实例题: Python 的简单电影信息

目录

Python实例题

题目

代码实现

实现原理

网页请求:

内容解析:

数据存储:

反爬策略:

关键代码解析

1. 网页请求处理

2. 电影列表解析

3. 电影详情解析

4. 爬虫主逻辑

使用说明

安装依赖:

修改配置:

运行爬虫:

查看结果:

注意事项

法律合规:

反爬策略:

网站结构变化:

数据使用限制:

Python实例题

题目

 Python 的简单电影信息

代码实现

import requests
from bs4 import BeautifulSoup
import json
import time
import random
import logging
from fake_useragent import UserAgentclass MovieCrawler:"""电影信息爬虫类"""def __init__(self):"""初始化爬虫"""self.ua = UserAgent()self.headers = {'User-Agent': self.ua.random,'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8','Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6','Connection': 'keep-alive'}self.logger = self._setup_logger()self.movies = []def _setup_logger(self):"""配置日志记录"""logger = logging.getLogger('movie_crawler')logger.setLevel(logging.INFO)# 创建控制台处理器ch = logging.StreamHandler()ch.setLevel(logging.INFO)# 创建日志格式formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')ch.setFormatter(formatter)# 添加处理器到loggerlogger.addHandler(ch)return loggerdef fetch_movie_list(self, url, page_num=1):"""获取电影列表页Args:url: 电影列表页URLpage_num: 页码Returns:页面内容或None"""try:# 构造完整URLfull_url = f"{url}?page={page_num}" if page_num > 1 else url# 更新User-Agentself.headers['User-Agent'] = self.ua.random# 发送请求response = requests.get(full_url, headers=self.headers, timeout=10)# 检查响应状态if response.status_code == 200:self.logger.info(f"成功获取页面: {full_url}")return response.textelse:self.logger.error(f"获取页面失败,状态码: {response.status_code}, URL: {full_url}")return Noneexcept Exception as e:self.logger.error(f"请求发生异常: {str(e)}")return Nonedef parse_movie_list(self, html_content):"""解析电影列表页Args:html_content: 页面HTML内容Returns:电影信息列表"""if not html_content:return []try:soup = BeautifulSoup(html_content, 'html.parser')movie_items = []# 这里需要根据实际网站结构调整选择器# 以下是一个示例选择器,用于演示目的for item in soup.select('.movie-item'):try:title = item.select_one('.title').text.strip()link = item.select_one('a')['href']rating = item.select_one('.rating').text.strip()year = item.select_one('.year').text.strip()movie_items.append({'title': title,'link': link,'rating': rating,'year': year})except (AttributeError, KeyError) as e:self.logger.warning(f"解析电影项时出错: {str(e)}")continueself.logger.info(f"成功解析 {len(movie_items)} 部电影")return movie_itemsexcept Exception as e:self.logger.error(f"解析页面时发生异常: {str(e)}")return []def fetch_movie_detail(self, url):"""获取电影详情页Args:url: 电影详情页URLReturns:页面内容或None"""try:# 更新User-Agentself.headers['User-Agent'] = self.ua.random# 发送请求response = requests.get(url, headers=self.headers, timeout=15)# 检查响应状态if response.status_code == 200:self.logger.info(f"成功获取详情页: {url}")return response.textelse:self.logger.error(f"获取详情页失败,状态码: {response.status_code}, URL: {url}")return Noneexcept Exception as e:self.logger.error(f"请求详情页发生异常: {str(e)}")return Nonedef parse_movie_detail(self, html_content, base_info):"""解析电影详情页Args:html_content: 页面HTML内容base_info: 从列表页获取的基础信息Returns:完整的电影信息"""if not html_content:return base_infotry:soup = BeautifulSoup(html_content, 'html.parser')# 提取详细信息,这里需要根据实际网站结构调整选择器director = soup.select_one('.director').text.strip() if soup.select_one('.director') else '未知'actors = [a.text.strip() for a in soup.select('.actors li')] if soup.select('.actors li') else []genre = [g.text.strip() for g in soup.select('.genre a')] if soup.select('.genre a') else []duration = soup.select_one('.duration').text.strip() if soup.select_one('.duration') else '未知'description = soup.select_one('.description').text.strip() if soup.select_one('.description') else ''# 合并信息movie_info = {**base_info,'director': director,'actors': actors,'genre': genre,'duration': duration,'description': description}return movie_infoexcept Exception as e:self.logger.error(f"解析详情页时发生异常: {str(e)}")return base_infodef crawl(self, base_url, total_pages=1):"""执行爬虫Args:base_url: 电影列表页基础URLtotal_pages: 要爬取的总页数"""self.logger.info(f"开始爬取电影信息,总页数: {total_pages}")for page in range(1, total_pages + 1):self.logger.info(f"正在爬取第 {page} 页...")# 获取电影列表页list_content = self.fetch_movie_list(base_url, page)# 解析电影列表movie_list = self.parse_movie_list(list_content)# 遍历电影列表,获取详情for movie in movie_list:# 构造完整详情页URLdetail_url = movie['link']if not detail_url.startswith('http'):detail_url = base_url + detail_url# 获取电影详情页detail_content = self.fetch_movie_detail(detail_url)# 解析电影详情full_movie_info = self.parse_movie_detail(detail_content, movie)# 添加到结果列表self.movies.append(full_movie_info)self.logger.info(f"成功获取电影: {full_movie_info['title']}")# 随机延时,避免过快请求time.sleep(random.uniform(1, 3))# 页面间延时time.sleep(random.uniform(2, 5))self.logger.info(f"爬取完成,共获取 {len(self.movies)} 部电影信息")def save_to_json(self, filename='movies.json'):"""将爬取的电影信息保存到JSON文件Args:filename: 保存的文件名"""try:with open(filename, 'w', encoding='utf-8') as f:json.dump(self.movies, f, ensure_ascii=False, indent=2)self.logger.info(f"电影信息已保存到 {filename}")except Exception as e:self.logger.error(f"保存文件时发生异常: {str(e)}")# 示例使用
def example_usage():# 注意:这只是一个示例URL,实际上需要替换为真实的电影网站URLbase_url = "https://example.com/movies"# 创建爬虫实例crawler = MovieCrawler()# 执行爬虫,爬取前3页crawler.crawl(base_url, total_pages=3)# 保存结果crawler.save_to_json('movies.json')if __name__ == "__main__":example_usage()    

实现原理

这个简单的电影爬虫基于以下技术实现:

  • 网页请求

    • 使用 requests 库发送 HTTP 请求
    • 随机更换 User-Agent 模拟不同浏览器
    • 设置合理的请求间隔避免被封 IP
  • 内容解析

    • 使用 BeautifulSoup 解析 HTML 内容
    • 通过 CSS 选择器提取所需信息
    • 处理可能的解析异常
  • 数据存储

    • 将爬取的电影信息存储为 JSON 格式
    • 提供清晰的日志记录功能
  • 反爬策略

    • 随机延时请求
    • 动态更换请求头
    • 异常处理和日志记录

关键代码解析

1. 网页请求处理

def fetch_movie_list(self, url, page_num=1):try:full_url = f"{url}?page={page_num}" if page_num > 1 else urlself.headers['User-Agent'] = self.ua.randomresponse = requests.get(full_url, headers=self.headers, timeout=10)if response.status_code == 200:self.logger.info(f"成功获取页面: {full_url}")return response.textelse:self.logger.error(f"获取页面失败,状态码: {response.status_code}, URL: {full_url}")return Noneexcept Exception as e:self.logger.error(f"请求发生异常: {str(e)}")return None

2. 电影列表解析

def parse_movie_list(self, html_content):if not html_content:return []try:soup = BeautifulSoup(html_content, 'html.parser')movie_items = []for item in soup.select('.movie-item'):try:title = item.select_one('.title').text.strip()link = item.select_one('a')['href']rating = item.select_one('.rating').text.strip()year = item.select_one('.year').text.strip()movie_items.append({'title': title,'link': link,'rating': rating,'year': year})except (AttributeError, KeyError) as e:self.logger.warning(f"解析电影项时出错: {str(e)}")continueself.logger.info(f"成功解析 {len(movie_items)} 部电影")return movie_itemsexcept Exception as e:self.logger.error(f"解析页面时发生异常: {str(e)}")return []

3. 电影详情解析

def parse_movie_detail(self, html_content, base_info):if not html_content:return base_infotry:soup = BeautifulSoup(html_content, 'html.parser')director = soup.select_one('.director').text.strip() if soup.select_one('.director') else '未知'actors = [a.text.strip() for a in soup.select('.actors li')] if soup.select('.actors li') else []genre = [g.text.strip() for g in soup.select('.genre a')] if soup.select('.genre a') else []duration = soup.select_one('.duration').text.strip() if soup.select_one('.duration') else '未知'description = soup.select_one('.description').text.strip() if soup.select_one('.description') else ''movie_info = {**base_info,'director': director,'actors': actors,'genre': genre,'duration': duration,'description': description}return movie_infoexcept Exception as e:self.logger.error(f"解析详情页时发生异常: {str(e)}")return base_info

4. 爬虫主逻辑

def crawl(self, base_url, total_pages=1):self.logger.info(f"开始爬取电影信息,总页数: {total_pages}")for page in range(1, total_pages + 1):self.logger.info(f"正在爬取第 {page} 页...")# 获取电影列表页list_content = self.fetch_movie_list(base_url, page)# 解析电影列表movie_list = self.parse_movie_list(list_content)# 遍历电影列表,获取详情for movie in movie_list:# 构造完整详情页URLdetail_url = movie['link']if not detail_url.startswith('http'):detail_url = base_url + detail_url# 获取电影详情页detail_content = self.fetch_movie_detail(detail_url)# 解析电影详情full_movie_info = self.parse_movie_detail(detail_content, movie)# 添加到结果列表self.movies.append(full_movie_info)self.logger.info(f"成功获取电影: {full_movie_info['title']}")# 随机延时,避免过快请求time.sleep(random.uniform(1, 3))# 页面间延时time.sleep(random.uniform(2, 5))self.logger.info(f"爬取完成,共获取 {len(self.movies)} 部电影信息")

使用说明

  • 安装依赖

pip install requests beautifulsoup4 fake-useragent
  • 修改配置

    • 在代码中替换base_url为实际的电影网站 URL,并根据目标网站的 HTML 结构调整解析部分的 CSS 选择器。

  • 运行爬虫

python movie_crawler.py
  • 查看结果

    • 爬取的电影信息会保存到movies.json文件中。

注意事项

  • 法律合规

    • 此程序仅用于演示爬虫技术,请勿用于非法获取受版权保护的内容
    • 爬取网站前请查看其 robots.txt 文件和使用条款
    • 遵守相关国家和地区的法律法规
  • 反爬策略

    • 控制爬取速度,避免对目标网站造成压力
    • 添加合理的延时和请求头信息
    • 考虑使用代理 IP 池
  • 网站结构变化

    • 网站结构可能随时变化,需要相应调整解析代码
    • 建议添加适当的错误处理和重试机制
  • 数据使用限制

    • 爬取的数据仅供个人学习研究使用,不可用于商业用途
    • 尊重原网站的版权和数据使用政策

相关文章:

Python实例题: Python 的简单电影信息

目录 Python实例题 题目 代码实现 实现原理 网页请求: 内容解析: 数据存储: 反爬策略: 关键代码解析 1. 网页请求处理 2. 电影列表解析 3. 电影详情解析 4. 爬虫主逻辑 使用说明 安装依赖: 修改配置&a…...

MyBatis 的动态 SQL

1. 动态 SQL 的定义 动态 SQL 是 MyBatis 的核心特性之一,它允许开发者根据运行时条件动态生成 SQL 语句。通过特殊的 XML 标签或注解语法,实现 SQL 的灵活拼接,避免在 Java 代码中手动拼接 SQL 字符串的复杂性和安全风险。 2. 核心作用 条…...

Redis中的setIfAbsent方法和execute

Redis中的setIfAbsent方法 Redis中的setIfAbsent方法是一种原子操作,它的作用是只有在指定的键不存在时才会设置值。这个方法在并发环境下非常有用,因为它可以避免多个客户端同时尝试设置相同键而导致的冲突。 代码示例 在Java中使用setIfAbsent方法通…...

高考数学易错考点02 | 临阵磨枪

文章目录 前言解析几何立体几何排列组合概率导数及应用前言 本篇内容下载于网络,网络上的都是以 WORD 版本呈现,缺字缺图很不完整,没法使用,我只是做了补充和完善。有空准备进行第二次完善,添加问题解释的链接。 ##平面向量 40.向量 0 ⃗ \vec{0} 0 与数 0 0 0 有区别…...

国产高性能pSRAM选型指南:CSS6404LS-LI 64Mb QSPI伪静态存储器

一、芯片基础特性 核心参数 容量 :64Mb(8M 8bit)电压 :单电源供电 2.7-3.6V (兼容3.3V系统)接口 :Quad-SPI(QPI/SPI)同步模式封装 : SOP-8L (150mil) &#…...

Go 中 `json.NewEncoder/Decoder` 与 `json.Marshal/Unmarshal` 的区别与实践

Go 中 json.NewEncoder/Decoder 与 json.Marshal/Unmarshal 的区别与实践(HTTP 示例) 在 Go 中处理 JSON 有两种主要方式:使用 json.Marshal/Unmarshal 和使用 json.NewEncoder/Decoder。它们都能完成 JSON 的序列化与反序列化,但…...

UE5 2D角色PaperZD插件动画状态机学习笔记

UE5 2D角色PaperZD插件动画状态机学习笔记 0.安装PaperZD插件 这是插件下载安装地址 https://www.fab.com/zh-cn/listings/6664e3b5-e376-47aa-a0dd-f7bbbd5b93c0 1.右键创建PaperZD 动画序列 2.添加动画序列 3,右键创建PaperZD AnimBP (动画蓝图&am…...

Ubuntu 16.04 密码找回

同事整理的供参考: 进入GRUB菜单 重启系统,在启动过程中长按Shift键(或Esc键)进入GRUB引导菜单。 若未显示GRUB菜单,可尝试在启动时连续按多次Shift/Esc键。 在GRUB菜单中选择默认的Ubuntu启动项(第一…...

【论文阅读】DanceGRPO: Unleashing GRPO on Visual Generation

DanceGRPO: Unleashing GRPO on Visual Generation 原文摘要 研究背景与问题 生成模型的突破:扩散模型和整流流等生成模型在视觉内容生成领域取得了显著进展。核心挑战:如何让模型的输出更好地符合人类偏好仍是一个关键问题。现有方法的局限性&#xff1…...

CentOS在vmware局域网内搭建DHCP服务器【踩坑记录】

1. 重新设置环境 配置dhcp服务踩了不少坑,这里重头搭建记录一下: 1.1 centos 网卡还原 如果之前搭了乱七八糟的环境,导致NAT模式也没法上网,这里重新还原 我们需要在NAT模式下联网,下载DHCP服务 先把centos的网卡还…...

AI炼丹日志-28 - Audiblez 将你的电子书epub转换为音频mp3 做有声书

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 大模型与Java双线更新中! 目前《大语言模型实战》已连载至第22篇,探索 MCP 自动操作 FigmaCursor 实…...

图像处理篇---face_recognition库实现人脸检测

以下是使用face_recognition库实现人脸检测的详细步骤、实例代码及解释: 一、环境准备 1. 安装依赖库 pip install face_recognition opencv-python # 核心库 pip install matplotlib # 用于显示图像(可选)2. 依赖说明 face_recognitio…...

74. 搜索二维矩阵 (力扣)

给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。…...

8088单板机C语言sprintf()格式化串口输出---Prj04

#include "tiny_stdarg.h" // 使用自定义可变参数实现#define ADR_273 0x0200 #define ADR_244 0x0400 #define LED_PORT 0x800 #define PC16550_THR 0x1f0 #define PC16550_LSR 0x1f5 / //基本的IO操作函数 / char str[]"Hello World! 20250531 Ve…...

板凳-------Mysql cookbook学习 (九)

第4章:表管理 4.0 引言 MySQL :: 员工样例数据库 :: 3 安装 https://dev.mysql.com/doc/employee/en/employees-installation.html Employees 数据库与几种不同的 存储引擎,默认情况下启用 InnoDB 引擎。编…...

深入解析 Flask 命令行工具与 flask run命令的使用

Flask 是一个轻量级的 Python Web 应用框架,其内置的命令行工具(CLI)基于 Click 库,提供了方便的命令行接口,用于管理和运行 Flask 应用程序。本文将详细介绍 Flask 命令行工具的功能,以及如何使用 flask r…...

第6篇:中间件 SQL 重写与语义分析引擎实现原理

6.1 章节导读 SQL 是数据库中间件的“输入语言”。 在一个真正强大的中间件系统中,SQL 语句的执行通常不再是“原封不动”地传递给数据库,而是需要先经过: 语义分析:解析 SQL 的结构和含义。 SQL 重写:根据中间件逻辑…...

基于SpringBoot的“嗨玩旅游”网站设计与实现(源码+定制+开发)嗨玩旅游平台开发:景点展示与个性化推荐系统(SpringBoot)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...

python版若依框架开发:python版若依部署

python版若依框架开发 从0起步,扬帆起航。 python版若依部署文章目录 python版若依框架开发1.源码2.概述3.部署1.源码 https://gitee.com/insistence2022/RuoYi-Vue-FastAPI 请诸君移步上述链接,即可对python版若依项目进行初步了解。 2.概述 若依框架本身基于java,可以快…...

React进阶:状态管理选择题

React进阶:状态管理选择题 引言 随着React应用复杂度增加,选择合适的状态管理方案成为我们面临的关键决策。 状态管理本质上是解决"谁来存储数据"以及"如何更新和分发这些数据"的问题。在React生态中,随着应用规模扩大…...

h5的aliplayer-min.js 加密视频会走到debugger

h5的aliplayer-min.js 如果 https://g.alicdn.com/apsara-media-box/imp-web-player/2.19.0/aliplayer-min.js走加密视频的话会有debugger 更换aliplayer-min.js版本解决了 https://g.alicdn.com/apsara-media-box/imp-web-player/2.25.1/aliplayer-min.js 对应css&#xff1a…...

第5篇《中间件负载均衡与连接池管理机制设计》

5.1 章节导读 在数据库中间件中,如何高效地管理数据库连接与请求调度至关重要。 本节围绕两个核心模块展开: 连接池管理:提升连接复用能力,避免频繁建立/断开连接。 负载均衡策略:合理调度 SQL 请求,提升…...

DashBoard安装使用

DashBoard安装使用 一、实验目的 1、掌握dashboard 的安装部署 2、熟悉图像化部署任务:产生pod---定义服务--验证访问 二、实验内容: 1、配置步骤 1.1、Helm安装 离线安装(适用于内网/离线环境) # 根据系统架构选择版本&am…...

极客大挑战 2019 EasySQL 1(万能账号密码,SQL注入,HackBar)

题目 做法 启动靶机,打开给出的网址 随便输点东西进去,测试一下 输入1、1’、1"判断SQL语句闭合方式 输入以上两个都是以下结果 但是,输入1’时,出现的是另外结果 输入1,1"时,SQL语句没有…...

C# CallerMemberName特性

当你在一个方法运用了CallerMemberName特性,编译器会自动将调用该方法的方法或属性的名称作为该参数的默认值,可应用于MVVM框架。 代码: using System.ComponentModel; using System.Runtime.CompilerServices;public class Person : INoti…...

采用 Docker GPU 部署的 Ubuntu 或者 windows 桌面环境

# 国内下载不了 docker pull gezp/ubuntu-desktop:24.04-cu12.6.2# 阿里云镜像 docker pull registry.cn-hongkong.aliyuncs.com/gezp/ubuntu-desktop:24.04-cu12.6.2# create container with nomachine docker run -d --restarton-failure --name myubuntu --shm-size1024m -e…...

关于面试找工作的总结(四)

不同情况下收到offer后的处理方法 1.不会去的,只是面试练手2.还有疑问,考虑中3.offer/职位不满足期望的4.已确认,但又收到更好的5.还想挽回之前的offer6.确认,准备入职7.还想拖一下的1.不会去的,只是面试练手 HR您好,非常荣幸收到贵司的offer,非常感谢一直以来您的帮助,…...

分布式拜占庭容错算法——实现工作量证明(PoW)算法详解

Java 实现工作量证明(PoW)算法详解 一、PoW 核心原理 #mermaid-svg-AAj0Pvst1PVcVy5v {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-AAj0Pvst1PVcVy5v .error-icon{fill:#552222;}#mermaid…...

深度解析Mysql中MVCC的工作机制

MVCC,多版本并发控制 定义:维护一个数据的多个版本,使读写操作没有冲突,依赖于:隐藏字段,undo log日志,readView MVCC会为每条版本记录保存三个隐藏字段 DB_TRX_ID: 记录最近插入或修改该记录的事务IDDB_R…...

MP4文件声音与视频分离

最近学习PR剪辑 要添加视频文件和音频文件 但是直接给MP4文件 得到的是一个整体 不管怎么切分 都是无法得到单独的整体 这就需要将视频文件和音频文件分离 我推荐使用ffmpeg工具进行分离 迅雷链接:https://pan.xunlei.com/s/VORu5x64jjL-gXFd_VTpYjRPA1?pwd8wec#…...