我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南

news2025/5/27 15:05:11

我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南

在这里插入图片描述


一、创建隔离开发环境

1. 使用虚拟环境(推荐venv
# 在项目目录打开终端执行
python -m venv douban_env      # 创建虚拟环境
source douban_env/bin/activate # Linux/macOS激活
douban_env\Scripts\activate   # Windows激活
2. 安装依赖库
pip install requests beautifulsoup4 lxml
3. 生成依赖清单
pip freeze > requirements.txt

二、项目架构设计

douban_top250/
├── config/               # 配置文件
│   └── settings.py
├── core/                 # 核心逻辑
│   ├── spider.py
│   └── storage.py
├── utils/                # 工具函数
│   └── helper.py
├── output/               # 输出目录
├── main.py               # 主入口
└── requirements.txt      # 依赖清单

三、分步实现

步骤1:创建配置文件 config/settings.py
# 请求配置
HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Referer': 'https://movie.douban.com/'
}

# 目标URL配置
BASE_URL = 'https://movie.douban.com/top250'

# 存储配置
OUTPUT_DIR = './output'
CSV_HEADERS = ['标题', '评分', '年份', '国家', '类型', '链接']

# 容错配置
SAFE_MODE = True  # 遇到错误时跳过条目而不是终止
UNKNOWN_PLACEHOLDER = "未知"  # 数据缺失时的占位符
步骤2:编写工具类 utils/helper.py
import random
import time

def random_delay(min=1, max=3):
    """随机延迟防止被封"""
    time.sleep(random.uniform(min, max))

def make_soup(html):
    """创建BeautifulSoup对象"""
    from bs4 import BeautifulSoup
    return BeautifulSoup(html, 'lxml')
步骤3:核心爬虫逻辑 core/spider.py
import requests
from config import settings
from utils.helper import random_delay, make_soup

class DoubanSpider:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update(settings.HEADERS)

    def fetch_page(self, url):
        """获取页面内容"""
        try:
            random_delay()
            response = self.session.get(url)
            response.raise_for_status()  # 自动处理HTTP错误
            return response.text
        except requests.RequestException as e:
            print(f"请求失败: {str(e)}")
            return None

    def parse_page(self, html):
        """改进后的解析方法"""
        soup = make_soup(html)
        movies = []
        
        for item in soup.find_all('div', class_='item'):
            try:
                # 标题与链接
                title = item.find('span', class_='title').text.strip()
                rating = item.find('span', class_='rating_num').text.strip()
                link = item.find('a')['href']
                
                # 详细信息解析(稳健版)
                info_div = item.find('div', class_='bd')
                info_text = info_div.p.get_text(" ", strip=True)  # 用空格替代换行
                
                # 使用正则表达式提取年份/国家/类型
                import re
                pattern = r'(\d{4})[^/]*(.*?)\s+/\s+(.*?)$'
                match = re.search(pattern, info_text)
                
                if match:
                    year = match.group(1).strip()
                    country = match.group(2).strip().replace('/', ' ')  # 处理国家中的斜杠
                    genre = match.group(3).strip()
                else:
                    year = country = genre = "N/A"  # 无法解析时填充默认值
                    
                movies.append({
                    '标题': title,
                    '评分': rating,
                    '年份': year,
                    '国家': country,
                    '类型': genre,
                    '链接': link
                })
                
            except Exception as e:
                print(f"解析条目失败: {str(e)}")
                continue  # 跳过当前条目
                
        return movies

    def get_all_pages(self):
        """处理分页"""
        all_movies = []
        start = 0
        
        while True:
            url = f"{settings.BASE_URL}?start={start}"
            html = self.fetch_page(url)
            if not html:
                break
                
            movies = self.parse_page(html)
            if not movies:
                break
                
            all_movies.extend(movies)
            start += 25
            # 检查是否还有下一页
            if start >= 250:  # Top250最多250条
                break
        
        return all_movies
步骤4:数据存储模块 core/storage.py
import csv
import json
import os
from config import settings

class DataStorage:
    @staticmethod
    def save_csv(data, filename='douban_top250.csv'):
        os.makedirs(settings.OUTPUT_DIR, exist_ok=True)
        path = os.path.join(settings.OUTPUT_DIR, filename)
        
        with open(path, 'w', newline='', encoding='utf-8') as f:
            writer = csv.DictWriter(f, fieldnames=settings.CSV_HEADERS)
            writer.writeheader()
            writer.writerows(data)
        print(f"数据已保存至 {path}")

    @staticmethod
    def save_json(data, filename='douban_top250.json'):
        os.makedirs(settings.OUTPUT_DIR, exist_ok=True)
        path = os.path.join(settings.OUTPUT_DIR, filename)
        
        with open(path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        print(f"数据已保存至 {path}")
步骤5:主程序 main.py
from core.spider import DoubanSpider
from core.storage import DataStorage

def main():
    # 检查robots协议
    print("豆瓣 robots.txt 重要条款:")
    print("User-agent: *")
    print("Disallow: /search")  # 实际需查看最新内容
    
    # 执行爬虫
    spider = DoubanSpider()
    movies_data = spider.get_all_pages()
    
    # 存储数据
    if movies_data:
        DataStorage.save_csv(movies_data)
        DataStorage.save_json(movies_data)
    else:
        print("未获取到有效数据")

if __name__ == '__main__':
    main()

四、运行与验证

  1. 在激活的虚拟环境中执行:
python main.py
  1. 检查 output/ 目录生成的 CSV 和 JSON 文件

在这里插入图片描述

五、高级优化建议

  1. 异常处理增强
# 在spider类中添加重试机制
def fetch_page(self, url, retries=3):
    for attempt in range(retries):
        try:
            # ...原有代码...
        except requests.RequestException as e:
            if attempt == retries - 1:
                raise
            print(f"重试中 ({attempt+1}/{retries})...")
            time.sleep(2 ** attempt)  # 指数退避
  1. 请求头轮换
# 在settings.py中添加多个User-Agent
USER_AGENTS = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15',
    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]

# 在helper.py中添加选择函数
def get_random_user_agent():
    return random.choice(settings.USER_AGENTS)
  1. 代理设置(如果需要):
# 在spider初始化时添加
def __init__(self, proxy=None):
    if proxy:
        self.session.proxies = {'http': proxy, 'https': proxy}

六、法律合规检查

  1. 访问 https://www.douban.com/robots.txt 查看协议
  2. 重点条款:
User-agent: *
Disallow: /subject_search
Disallow: /amazon_search
Disallow: /search
Disallow: /group/search
Disallow: /event/search
Disallow: /forum/search
Disallow: /game/search
  1. 合规措施:
  • 限制请求频率(代码中已实现随机延迟)
  • 不绕过反爬机制
  • 仅用于学习用途
  • 不存储敏感信息

通过这个结构化的项目实现,你可以:

  • 保持代码的可维护性
  • 方便后续扩展功能(如添加代理支持)
  • 符合Python最佳实践
  • 有效管理依赖项

下一步可以尝试:

  1. 添加日志记录模块
  2. 实现数据库存储(MySQL/MongoDB)
  3. 使用Scrapy框架重构项目
  4. 部署到服务器定时运行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2386097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Selenium 测试框架 - C#

🚀Selenium C# 自动化测试实战:以百度搜索为例 本文将通过一个简单示例,手把手教你如何使用 Selenium + C# 实现百度搜索自动化测试。适合初学者快速上手,也适合作为企业 UI 自动化测试模板参考。 🧩 一、安装必要 NuGet 包 在 Visual Studio 的 NuGet 管理器中安装以下…

JavaWeb:SpringBoot工作原理详解

一、SpringBoot优点 1.为所有Spring开发者更快的入门 2.开箱即用,提供各种默认配置来简化项目配置 3.内嵌式容器简化Web项目 4.没有冗余代码生成和XML配置的要求 二、SpringBoot 运行原理 2.1. pom.xml spring-boot-dependencies: 核心依赖在父工程中;…

dify_plugin数据库中的表总结

本文使用dify-plugin-daemon v0.1.0版本,主要对dify_plugin数据库中的数据表进行了总结。 一.agent_strategy_installations 源码位置:dify-plugin-daemon\internal\types\models\agent.go type AgentStrategyInstallation struct {ModelTenantID …

HarmonyOS学习——UIAbility组件(上)

UIAbility组件概述 应用程序有几种界面交互形式 UIAbility:应用程序的入口 概述 UIAbility组件是一种包含UI的应用组件,主要用于和用户交互。 UIAbility的设计理念: 原生支持应用组件级的跨端迁移和多端协同。 支持多设备和多窗口形态。…

【Linux】磁盘空间不足

错误提示: no space left on device 经典版(block占用) 模拟 dd if/dev/zero of/var/log/nginx.log bs1M count2000排查 #1. df -h 查看哪里空间不足,哪个分区#2. du -sh详细查看目录所占空间 du -sh /* 排查占用空间大的目录 du -sh /var/* du…

持续更新 ,GPT-4o 风格提示词案例大全!附使用方式

本文汇集了各类4o风格提示词的精选案例,从基础指令到复杂任务,从创意写作到专业领域,为您提供全方位的参考和灵感。我们将持续更新这份案例集,确保您始终能够获取最新、最有效的提示词技巧。 让我们一起探索如何通过精心设计的提…

QStandardItemModel的函数和信号介绍

前言 Qt版本:6.8.0 QStandardItem函数介绍 函数 部分函数有不同的重载来适应不同的模型,例如appendrow 构造函数与析构函数 1. QStandardItemModel(QObject *parent nullptr) 说明:创建一个空的模型(0行0列)。参数: parent&…

Python 内存管理机制详解:从分配到回收的全流程剖析

在 Python 编程中,开发者无需像 C/C 那样手动分配和释放内存,但这并不意味着内存管理与我们无关。了解 Python 内存管理机制,能帮助我们编写出更高效、稳定的代码。接下来,我们将深入剖析 Python 内存管理的各个环节,并…

【报错】Error attempting to get column ‘created_time‘ from result set.解决方法

postman报错以下内容 {"code": "500","msg": "查询失败:Error attempting to get column created_time from result set. Cause: java.sql.SQLFeatureNotSupportedException\n; null; nested exception is java.sql.SQLFeatur…

Google 推出 Flow —— AI 电影制作新平台

这周, Google I/O 2025 大会上发布了一些重磅 AI 公告。 他们推出了全新的图像模型 Imagen 4,还发布了升级版视频生成器 Veo 3、升级版 Gemini Pro 模型,以及一系列其他令人印象深刻的更新。 但将所有这些生成式媒体工具整合在一起的,是他们称为 Flow 的平台。 什么是 F…

跨链风云:打破区块链孤岛,实现价值自由流转

嘿,各位技术爱好者们!今天我们来聊一个区块链领域非常火热且至关重要的话题——跨链技术。你可能听说过,比如想把在波场(Tron)链上的USDT转移到以太坊(Ethereum)网络上,这个过程就涉…

鸿蒙开发:了解$$运算符

前言 本文基于Api13 有这样一个需求,一个Text组件,一个TextInput组件,要求Text组件同步展示TextInput组件里的内容,也就是TextInput组件输入什么内容,就要在Text组件里展示什么内容,这个需求如何实现呢&…

基于CEEMDAN-Transformer-BiLSTM的多特征风速气候预测的完整实现方案及PyTorch源码解析

基于CEEMDAN-Transformer-BiLSTM的多特征风速气候预测的完整实现方案及PyTorch源码解析 一、模型架构设计 1.1 整体框架 该模型采用三级架构设计(图1): CEEMDAN分解层:对非平稳风速序列进行自适应分解多模态特征融合模块&#…

基于TypeScript的全栈待办事项应用Demo

Demo地址:git clone https://gitcode.com/rmbnetlife/todo-app.git Todo List 应用 这是一个基于TypeScript的全栈待办事项应用,前端使用React,后端使用Node.js和Express。 项目概述 这个Todo List应用允许用户: 查看所有待办…

国际荐酒师(香港)协会亮相新西兰葡萄酒巡展深度参与赵凤仪大师班

国际荐酒师(香港)协会率团亮相2025新西兰葡萄酒巡展 深度参与赵凤仪MW“百年百碧祺”大师班 广州/上海/青岛,2025年5月12-16日——国际荐酒师(香港)协会(IRWA)近日率专业代表团出席“纯净独特&…

【深度学习】2. 从梯度推导到优化策略:反向传播与 SGD, Mini SGD

反向传播算法详解 1. 前向传播与输出层误差定义 假设我们考虑一个典型的前馈神经网络,其最后一层为 softmax 分类器,损失函数为交叉熵。 前向传播过程 对于某一隐藏层神经元 j j j: 输入: x i x_i xi​ 权重: w j…

工业软件国产化:构建自主创新生态,赋能制造强国建设

随着全球产业环境的变化和技术的发展,建立自主可控的工业体系成为我国工业转型升级、走新型工业化道路、推动国家制造业竞争水平提升的重要抓手。 市场倒逼与政策护航,国产化进程双轮驱动 据中商产业研究院预测,2025年中国工业软件市场规模…

UART、RS232、RS485基础知识

一、UART串口通信介绍 UART是一种采用异步串行、全双工通信方式的通用异步收发传输器功能。 硬件电路: •简单双向串口通信有两根通信线(发送端TX和接收端RX) •TX与RX要交叉连接 •当只需单向的数据传输时,可以只接一根通信线…

AI重塑数据治理的底层逻辑

AI重塑数据治理的底层逻辑 人治模式:一个必然失败的商业逻辑智治模式:重新定义数据治理的商业模式结语 上个月,一位老友约我喝茶。他是某知名互联网公司的数据总监,聊天时满脸愁容。 “润总,我们公司数据治理团队有50多…

基于 AI 实现阿里云的智能财务管家

新钛云服已累计为您分享844篇技术干货 为了解决传统账单处理中人工查询效率低下、响应速度慢及易出错等问题,同时顺应AI技术发展趋势,提升服务智能化水平。随着业务规模扩大和账单数据复杂度增加,人工处理已难以满足高效管理需求。我们想到通…