Python爬虫实战:从零构建书籍价格情报数据库(附CSV导出 + SQLite持久化存储)!

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~

㊙️本期爬虫难度指数:⭐⭐⭐

🉐福利: 一次订阅后,专栏内的所有文章可永久免费看,持续更新中,保底1000+(篇)硬核实战内容。

全文目录:

    • [🌟 开篇语](#🌟 开篇语)
    • [🌟 开篇语](#🌟 开篇语)
      • [1️⃣ 摘要(Abstract)](#1️⃣ 摘要(Abstract))
      • [2️⃣ 背景与需求(Why)](#2️⃣ 背景与需求(Why))
      • [3️⃣ 合规与注意事项(必写)](#3️⃣ 合规与注意事项(必写))
      • [4️⃣ 技术选型与整体流程(What/How)](#4️⃣ 技术选型与整体流程(What/How))
      • [5️⃣ 环境准备与依赖安装(可复现)](#5️⃣ 环境准备与依赖安装(可复现))
      • [6️⃣ 核心实现:请求层(Fetcher)](#6️⃣ 核心实现:请求层(Fetcher))
      • [7️⃣ 核心实现:解析层(Parser)](#7️⃣ 核心实现:解析层(Parser))
      • [8️⃣ 数据存储与导出(Storage)](#8️⃣ 数据存储与导出(Storage))
      • [9️⃣ 运行方式与结果展示(必写)](#9️⃣ 运行方式与结果展示(必写))
      • [🔟 常见问题与排错(强烈建议写)](#🔟 常见问题与排错(强烈建议写))
      • [1️⃣1️⃣ 进阶优化(可选但加分)](#1️⃣1️⃣ 进阶优化(可选但加分))
      • [1️⃣2️⃣ 总结与延伸阅读](#1️⃣2️⃣ 总结与延伸阅读)
    • [🌟 文末](#🌟 文末)
      • [✅ 专栏持续更新中|建议收藏 + 订阅](#✅ 专栏持续更新中|建议收藏 + 订阅)
      • [✅ 互动征集](#✅ 互动征集)
      • [✅ 免责声明](#✅ 免责声明)

🌟 开篇语

哈喽,各位小伙伴们你们好呀~我是【喵手】。

运营社区: C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO

欢迎大家常来逛逛,一起学习,一起进步~🌟

我长期专注 Python 爬虫工程化实战 ,主理专栏 《Python爬虫实战》:从采集策略反爬对抗 ,从数据清洗分布式调度 ,持续输出可复用的方法论与可落地案例。内容主打一个"能跑、能用、能扩展 ",让数据价值真正做到------抓得到、洗得净、用得上

📌 专栏食用指南(建议收藏)

  • ✅ 入门基础:环境搭建 / 请求与解析 / 数据落库
  • ✅ 进阶提升:登录鉴权 / 动态渲染 / 反爬对抗
  • ✅ 工程实战:异步并发 / 分布式调度 / 监控与容错
  • ✅ 项目落地:数据治理 / 可视化分析 / 场景化应用

📣 专栏推广时间 :如果你想系统学爬虫,而不是碎片化东拼西凑,欢迎订阅专栏👉《Python爬虫实战》👈,一次订阅后,专栏内的所有文章可永久免费阅读,持续更新中。

💕订阅后更新会优先推送,按目录学习更高效💯~

🌟 开篇语

哈喽,各位小伙伴们你们好呀~我是【喵手】。

运营社区: C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO

欢迎大家常来逛逛,一起学习,一起进步~🌟

我长期专注 Python 爬虫工程化实战 ,主理专栏 《Python爬虫实战》:从采集策略反爬对抗 ,从数据清洗分布式调度 ,持续输出可复用的方法论与可落地案例。内容主打一个"能跑、能用、能扩展 ",让数据价值真正做到------抓得到、洗得净、用得上

📌 专栏食用指南(建议收藏)

  • ✅ 入门基础:环境搭建 / 请求与解析 / 数据落库
  • ✅ 进阶提升:登录鉴权 / 动态渲染 / 反爬对抗
  • ✅ 工程实战:异步并发 / 分布式调度 / 监控与容错
  • ✅ 项目落地:数据治理 / 可视化分析 / 场景化应用

📣 专栏推广时间 :如果你想系统学爬虫,而不是碎片化东拼西凑,欢迎订阅/关注专栏👉《Python爬虫实战》👈

💕订阅后更新会优先推送,按目录学习更高效💯~

1️⃣ 摘要(Abstract)

一句话概述: 本项目使用 Python 的 requestsBeautifulSoup 库,针对图书沙盒网站构建高效爬虫,将书籍的标题、价格、评分及库存状态结构化提取并持久化存储。

读完本文你将获得:

  • 🎯 掌握从 HTTP 请求到数据清洗(ETL)的完整爬虫链路。
  • 🛠️ 学会使用 CSS 选择器精准提取复杂的 HTML 字段。
  • 📦 拥有一份可直接运行、具备基本容错能力的工程级代码模板。

2️⃣ 背景与需求(Why)

在信息爆炸时代,数据即资产。作为一名数据爱好者,手动复制粘贴不仅低效,更无法进行规模化分析。我们需要自动化手段来获取竞争对手的定价数据或行业趋势。

本次行动目标:

  • 目标站点: http://books.toscrape.com/ (一个安全的练习靶场)

  • 核心需求: 遍历图书列表,抓取详情。

  • 目标字段清单:

    1. title (书名 - 文本)
    2. price (价格 - 浮点数)
    3. rating (评分 - 转换后的数字 1-5)
    4. availability (库存状态 - 布尔值或文本)
    5. detail_url (详情页链接 - URL)

3️⃣ 合规与注意事项(必写)

做爬虫,**"讲武德"**是第一条军规。🛡️

  • Robots 协议: 在开工前,先查看 robots.txt。虽然靶场网站允许抓取,但在真实实战中,必须尊重 User-agent: * Disallow: / 的声明。
  • 频率控制(Rate Limiting): 这一条至关重要!切勿使用攻击式的并发请求(如 100 线程/秒),这会导致对方服务器宕机(DoS),甚至招致 IP 封禁。我们会设置合理的 time.sleep
  • 数据伦理: 本项目仅抓取公开数据,绝不触碰用户隐私(PII),也不涉及绕过付费墙或破解登录验证。做一名合法的"数据采集者",而不是"黑客"。

4️⃣ 技术选型与整体流程(What/How)

选型分析:

目标网站是典型的静态 HTML 网站(服务端渲染)。页面源代码中包含了我们所需的所有数据,不需要执行 JavaScript。

  • 方案: Python + Requests (发送请求) + BeautifulSoup4 (解析 HTML)。
  • 为什么不用 Scrapy? 对于单页面结构简单、量级较小(<1000页)的任务,Scrapy 显得过于重型,配置繁琐。
  • 为什么不用 Selenium/Playwright? 既然是静态页面,用浏览器自动化工具会极大降低抓取速度,属于"杀鸡用牛刀"。
  1. Fetcher(采集): 伪装浏览器发送 GET 请求。
  2. Parser(解析): 定位 DOM 节点,提取脏数据。
  3. Cleaner(清洗): 去除货币符号,将 "Three" 转为数字 3。
  4. Storage(存储): 写入 CSV 文件。

5️⃣ 环境准备与依赖安装(可复现)

确保你的 Python 版本 >= 3.8(人生苦短,请用新版本)。

项目目录结构推荐:

text 复制代码
project_root/
│
├── data/               # 存放抓取结果
├── src/                # 源代码目录
│   └── main.py         # 入口文件
├── requirements.txt    # 依赖清单
└── README.md

依赖安装:

打开终端(Terminal),执行以下命令来武装你的环境:

bash 复制代码
pip install requests beautifulsoup4 pandas

6️⃣ 核心实现:请求层(Fetcher)

在网络的世界里,我们需要给自己穿上一层"伪装衣"。

python 复制代码
import requests
from requests.exceptions import RequestException
import time
import random

def fetch_page(url):
    """
    通用请求函数,包含基本的反爬伪装和错误处理
    """
    # 伪装成正常的 Chrome 浏览器
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
        'Referer': 'http://books.toscrape.com/'
    }
    
    try:
        # timeout 是必须的!防止网络卡死导致程序无限挂起
        response = requests.get(url, headers=headers, timeout=10)
        
        # 检查 HTTP 状态码,如果是 4xx 或 5xx 直接抛出异常
        response.raise_for_status()
        
        # 显式设置编码,防止中文乱码(虽然这里是英文站,但养成好习惯)
        response.encoding = response.apparent_encoding
        
        return response.text
        
    except RequestException as e:
        print(f"💥 请求失败: {url} | 错误信息: {e}")
        return None

    # 简单的随机延时,模拟人类阅读间隔
    finally:
        time.sleep(random.uniform(0.5, 1.5)) 

7️⃣ 核心实现:解析层(Parser)

这是爬虫的大脑。我们需要从杂乱的 HTML 中"手术刀"般地切出我们需要的数据。这里我们使用 CSS Selector,它比 XPath 写起来更简洁。

python 复制代码
from bs4 import BeautifulSoup

def parse_html(html_content):
    """
    解析 HTML 并提取书籍列表信息
    """
    if not html_content:
        return []

    soup = BeautifulSoup(html_content, 'html.parser')
    books_data = []
    
    # 找到所有的书籍卡片容器
    articles = soup.select('article.product_pod')
    
    for article in articles:
        try:
            # 1. 提取标题 (Title)
            title_tag = article.select_one('h3 > a')
            title = title_tag['title'] if title_tag else "Unknown Title"
            
            # 2. 提取价格 (Price)
            price_text = article.select_one('p.price_color').text
            # 清洗数据:去掉英镑符号 '£'
            price = float(price_text.replace('£', ''))
            
            # 3. 提取评分 (Rating)
            # class 属性通常是列表,如 ['star-rating', 'Three']
            star_class = article.select_one('p.star_rating')['class']
            rating_map = {'One': 1, 'Two': 2, 'Three': 3, 'Four': 4, 'Five': 5}
            # 找到对应的数字文本
            rating_text = [x for x in star_class if x in rating_map]
            rating = rating_map.get(rating_text[0], 0) if rating_text else 0
            
            # 4. 提取状态 (Availability)
            avail_text = article.select_one('p.instock.availability').text.strip()
            is_in_stock = True if 'In stock' in avail_text else False

            data = {
                'title': title,
                'price': price,
                'rating': rating,
                'in_stock': is_in_stock
            }
            books_data.append(data)
            
        except AttributeError as e:
            # 容错处理:某个字段缺失不应导致整个程序崩溃
            print(f"⚠️ 解析单条数据出错: {e}")
            continue
            
    return books_data

8️⃣ 数据存储与导出(Storage)

既然是做数据分析,CSV 是最通用的格式。为了方便,我们直接使用神器 Pandas

python 复制代码
import pandas as pd
import os

def save_to_csv(data_list, filename="books_data.csv"):
    """
    将字典列表保存为 CSV 文件
    """
    if not data_list:
        print("📭 没有数据需要保存。")
        return

    # 转换为 DataFrame
    df = pd.DataFrame(data_list)
    
    # 确保目录存在
    os.makedirs('data', exist_ok=True)
    filepath = os.path.join('data', filename)
    
    # 导出
    df.to_csv(filepath, index=False, encoding='utf-8-sig')
    print(f"💾 数据已成功保存至: {filepath} | 共 {len(df)} 条记录")

9️⃣ 运行方式与结果展示(必写)

这是我们将所有积木拼在一起的时刻!🧩

主程序入口 (main.py):

python 复制代码
# 将上面的 fetch_page, parse_html, save_to_csv 整合
def main():
    base_url = "http://books.toscrape.com/catalogue/page-{}.html"
    all_books = []
    
    print("🚀 爬虫启动...")
    
    # 演示抓取前 3 页
    for page in range(1, 4):
        print(f"📡 正在抓取第 {page} 页...")
        url = base_url.format(page)
        html = fetch_page(url)
        
        if html:
            books = parse_html(html)
            all_books.extend(books)
            print(f"   ✅ 第 {page} 页解析完成,获取 {len(books)} 本书。")
    
    # 存储结果
    save_to_csv(all_books, filename="scraped_books_v1.csv")
    
    # 展示前 3 条结果
    print("\n📊 结果预览:")
    for book in all_books[:3]:
        print(book)

if __name__ == "__main__":
    main()

控制台输出示例:

text 复制代码
🚀 爬虫启动...
📡 正在抓取第 1 页...
   ✅ 第 1 页解析完成,获取 20 本书。
...
💾 数据已成功保存至: data/scraped_books_v1.csv | 共 60 条记录

📊 结果预览:
{'title': 'A Light in the Attic', 'price': 51.77, 'rating': 3, 'in_stock': True}
{'title': 'Tipping the Velvet', 'price': 53.74, 'rating': 1, 'in_stock': True}
{'title': 'Soumission', 'price': 50.1, 'rating': 1, 'in_stock': True}

🔟 常见问题与排错(强烈建议写)

老司机翻车现场指南:

  1. 40Forbidden / 429 Too Many Requests:

    • 原因: 没加 User-Agent 头(裸奔),或者爬太快了。
    • 解法: 检查 headers 是否完整;增大 time.sleep()` 的时间;如果是 IP 封禁,需要上代理池(Proxy Pool)。
  2. HTML 抓取到空壳(Body 里没数据):

    • *原因 网站是 Vue/React 动态渲染的,数据在 JS 里。
    • *解法 打开浏览器开发者工具(F12)-> Network -> XHR/Fetch,找真实的 API 接口。如果 API 加密严重,改用 Selenium/Playwright。
  3. 解析报错 AttributeError: 'eType' object has no attribute 'text':

    • 原因: CSS 选择器失效了,或者由于广告/缺货导致页面结构变了。
    • 解法: 必须加 try-exceptif tag: 判断(参考代码第 7 节的容错处理)。

1️⃣1️⃣ 进阶优化(可选但加分)

如果你想让你的爬虫更"专业":

  • 多线程并发: 使用 concurrent.futures.ThreadPoolExecutor。对于 I/O 密集型任务(网络请求),可以将速度提升 5-10 倍。
  • 断点续跑: 在数据库或 Redis 中记录已经抓取过的 URL Hash。程序重启时,跳过已抓取的页面。
  • 日志系统: 别再用 print 调试了!引入 Python 的 logging 模块,将报错信息写入 scraper.log 文件。

1️⃣2️⃣ 总结与延伸阅读

今天我们成功构建了一个针对静态网站的 ETL 爬虫。虽然简单,但它涵盖了爬虫最核心的四步:请求、解析、清洗、入库。你现在拥有了一个可以扩展的基础框架。

下一步挑战:

  • 试试抓取 JavaScript 动态渲染 的网站(如雪球网、SPA 电商)。
  • 学习 Scrapy 框架,体验中间件和管道的强大。
  • 研究 反爬虫对抗(JS 逆向、验证码识别),那是爬虫领域的深水区。🌊

🌟 文末

好啦~以上就是本期的全部内容啦!如果你在实践过程中遇到任何疑问,欢迎在评论区留言交流,我看到都会尽量回复~咱们下期见!

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦~
三连就是对我写作道路上最好的鼓励与支持! ❤️🔥

✅ 专栏持续更新中|建议收藏 + 订阅

墙裂推荐订阅专栏 👉 《Python爬虫实战》,本专栏秉承着以"入门 → 进阶 → 工程化 → 项目落地"的路线持续更新,争取让每一期内容都做到:

✅ 讲得清楚(原理)|✅ 跑得起来(代码)|✅ 用得上(场景)|✅ 扛得住(工程化)

📣 想系统提升的小伙伴 :强烈建议先订阅专栏 《Python爬虫实战》,再按目录大纲顺序学习,效率十倍上升~

✅ 互动征集

想让我把【某站点/某反爬/某验证码/某分布式方案】等写成某期实战?

评论区留言告诉我你的需求,我会优先安排实现(更新)哒~


⭐️ 若喜欢我,就请关注我叭~(更新不迷路)

⭐️ 若对你有用,就请点赞支持一下叭~(给我一点点动力)

⭐️ 若有疑问,就请评论留言告诉我叭~(我会补坑 & 更新迭代)


✅ 免责声明

本文爬虫思路、相关技术和代码仅用于学习参考,对阅读本文后的进行爬虫行为的用户本作者不承担任何法律责任。

使用或者参考本项目即表示您已阅读并同意以下条款:

  • 合法使用: 不得将本项目用于任何违法、违规或侵犯他人权益的行为,包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。
  • 风险自负: 任何因使用本项目而产生的法律责任、技术风险或经济损失,由使用者自行承担,项目作者不承担任何形式的责任。
  • 禁止滥用: 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。
  • 使用或者参考本项目即视为同意上述条款,即 "谁使用,谁负责" 。如不同意,请立即停止使用并删除本项目。!!!
相关推荐
勾股导航2 小时前
蚁群优化算法
人工智能·pytorch·python
小锋java12342 小时前
分享一套【优质Python源码】基于Python的Django学生就业管理系统
python
一个处女座的程序猿O(∩_∩)O2 小时前
Python字典详解
开发语言·python
List<String> error_P2 小时前
蓝桥杯基础知识点:模拟-数位操作类题目
python·算法·蓝桥杯
夕除2 小时前
js--22
前端·javascript·python
有点心急10213 小时前
Python 入门
服务器·数据库·python
henry1010103 小时前
Python从入门到精通学习路径(AI生成)
python
ValhallaCoder3 小时前
hot100-贪心
数据结构·python·算法·贪心算法