Python爬虫实战:构建一个高健壮性的图书数据采集器!

㊗️本期内容已收录至专栏《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爬虫实战》👈,一次订阅后,专栏内的所有文章可永久免费阅读,持续更新中。

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

1️⃣ 摘要(Abstract)

本文将带你手把手构建一个稳健的单线程爬虫,目标是攻克 books.toscrape.com 这一电商沙盒站点。我们将抛弃花里胡哨的框架,回归最扎实的 requests + BeautifulSoup 组合,实现从列表页到详情页的数据穿透。
读完本文,你将获得:

  1. 一套可以直接复用于 80% 静态网站的**"生产者-消费者"**式代码模板。
  2. 关于如何优雅处理 404、网络超时及字段缺失的容错机制
  3. 一份格式完美、无乱码的 CSV 数据交付物。

2️⃣ 背景与需求(Why)

为什么要爬?

假设我们是一名书店经营者,我们需要分析市场上的图书定价策略、库存情况以及评分分布。手动复制粘贴 1000 本书的数据简直是噩梦,自动化采集是唯一出路。

目标站点http://books.toscrape.com/
目标字段清单

  • Book Name (书名)
  • Price (价格,需清洗掉货币符号)
  • Rating (评分,星级转换)
  • Availability (库存状态)
  • UPC (产品唯一编码)

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

这里必须严肃三秒钟 😐。作为一名有职业操守的爬虫工程师,我们要遵守"互联网礼仪":

  • Robots.txt :虽然靶场允许所有爬取,但在实战中,请务必先访问 domain/robots.txt 查看站长设定的禁区。
  • 频率控制不要做服务器的"DDoS 攻击者"! 我们在代码中会强制加入 time.sleep,让爬虫像人类一样有阅读间隙。
  • 红线原则:绝对不采集个人隐私数据(手机号、身份证),绝对不尝试绕过登录撞库,涉及付费内容请老实付费。

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

技术选型

这次的目标是静态网页(HTML 源码里就有数据),所以:

  • Selenium/Playwright:太重了,像用牛刀杀鸡,速度慢。
  • Requests + BeautifulSoup (bs4):轻量、极速、精准。这是处理静态 HTML 的黄金搭档。

整体流程图

text 复制代码
[入口 URL] 
    ↓ 
[Fetcher: 获取列表页 HTML] 
    ↓ 
[Parser: 解析提取书籍详情 URL] 
    ↓ 
[Fetcher: 遍历请求详情页] → (加入随机延时)
    ↓ 
[Parser: 清洗提取字段 (Price/Rating/UPC)] 
    ↓ 
[Storage: 写入 CSV 文件]

5️⃣ 环境准备与依赖安装

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

项目结构推荐

text 复制代码
book_spider_pro/
├── main.py           # 入口文件
├── data/             # 数据存储目录
│   └── books_data.csv
└── requirements.txt  # 依赖表

安装依赖

打开终端,执行以下命令(记得用国内源加速哦~):

bash 复制代码
pip install requests beautifulsoup4

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

这一层是爬虫的"嘴",必须要结实,能吃得下各种网络异常。

python 复制代码
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
import random
import time

def get_html(url):
    """
    稳健的网页抓取函数,带重试机制和伪装
    """
    # 伪装成浏览器,这是最基本的礼貌
    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/'
    }
    
    # 建立会话,复用 TCP 连接
    session = requests.Session()
    
    # 设置重试策略:如果遇到 500, 502, 504 错误,重试 3 次
    retry = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)

    try:
        # 随机休眠 1-2 秒,模拟人类阅读
        time.sleep(random.uniform(1, 2))
        
        response = session.get(url, headers=headers, timeout=10)
        response.raise_for_status() # 如果状态码不是 200,直接抛异常
        
        # 处理编码,防止乱码(requests 自动推测有时不准)
        response.encoding = response.apparent_encoding 
        return response.text
        
    except Exception as e:
        print(f"💥 请求失败: {url}, 错误信息: {e}")
        return None

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

这一层是"胃",负责消化 HTML 并吸收营养。我们要处理详情页提取容错

python 复制代码
from bs4 import BeautifulSoup
import re

def parse_book_detail(html_content):
    """
    解析书籍详情页,返回字典
    """
    if not html_content:
        return None
        
    soup = BeautifulSoup(html_content, 'html.parser')
    item = {}
    
    try:
        # 1. 提取书名 (H1 标签)
        item['title'] = soup.select_one('div.product_main h1').text.strip()
        
        # 2. 提取价格 (清洗掉 £ 符号)
        price_raw = soup.select_one('p.price_color').text
        item['price'] = float(price_raw.replace('£', '').replace('Â', '')) # 这里的Â是常见的编码脏字符
        
        # 3. 提取评分 (CSS 类名转换数字)
        # HTML 示例: <p class="star-rating Three">
        star_tag = soup.select_one('p.star-rating')
        star_map = {'One': 1, 'Two': 2, 'Three': 3, 'Four': 4, 'Five': 5}
        # 获取 class 列表中的第二个元素 (即 'Three')
        rating_class = [c for c in star_tag.get('class') if c != 'star-rating'][0]
        item['rating'] = star_map.get(rating_class, 0)
        
        # 4. 提取库存 (文本处理)
        # 示例: "In stock (19 available)"
        availability = soup.select_one('p.instock.availability').text.strip()
        item['stock'] = re.search(r'\d+', availability).group() if re.search(r'\d+', availability) else 0
        
        # 5. 提取 UPC (在表格里)
        item['upc'] = soup.select_one('table.table-striped > tr:nth-of-type(1) > td').text
        
    except AttributeError as e:
        # 容错处理:如果某个字段找不到,不要崩,记录日志并跳过
        print(f"⚠️ 解析字段缺失: {e}")
        return None
        
    return item

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

不做花哨的数据库,先用 CSV 把数据落袋为安。

python 复制代码
import csv
import os

def save_to_csv(data_list, filename="books_data.csv"):
    """
    将字典列表写入 CSV
    """
    if not data_list:
        return

    # 确保 data 目录存在
    os.makedirs("data", exist_ok=True)
    file_path = os.path.join("data", filename)
    
    headers = ['title', 'price', 'rating', 'stock', 'upc']
    
    # newline='' 是为了防止 Windows 下出现空行
    with open(file_path, 'w', newline='', encoding='utf-8-sig') as f:
        writer = csv.DictWriter(f, fieldnames=headers)
        writer.writeheader()
        writer.writerows(data_list)
        
    print(f"🎉 数据已成功保存至: {file_path}, 共 {len(data_list)} 条")

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

把上面的代码串起来,放在 main 块中。

python 复制代码
# ... (上面定义的函数) ...

if __name__ == "__main__":
    base_url = "http://books.toscrape.com/catalogue/page-{}.html"
    all_books_data = []
    
    print("🚀 爬虫启动!目标:Books to Scrape")
    
    # 为了演示,我们只爬取前 2 页 (真实场景可以用 while 循环判断下一页)
    for page in range(1, 3):
        print(f"📄 正在抓取第 {page} 页列表...")
        list_url = base_url.format(page)
        list_html = get_html(list_url)
        
        if list_html:
            soup = BeautifulSoup(list_html, 'html.parser')
            # 获取当前页所有书籍的详情链接
            articles = soup.select('article.product_pod h3 a')
            
            for link in articles:
                # 拼接完整 URL
                detail_url = "http://books.toscrape.com/catalogue/" + link['href']
                print(f"  -> 正在处理详情: {detail_url}")
                
                detail_html = get_html(detail_url)
                book_data = parse_book_detail(detail_html)
                
                if book_data:
                    all_books_data.append(book_data)
    
    # 保存数据
    save_to_csv(all_books_data)
    print("✨ 全部任务搞定!喝杯咖啡去吧!☕")

示例运行输出

text 复制代码
🚀 爬虫启动!目标:Books to Scrape
📄 正在抓取第 1 页列表...
  -> 正在处理详情: http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html
  -> 正在处理详情: http://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html
...
🎉 数据已成功保存至: data/books_data.csv, 共 40 条
✨ 全部任务搞定!喝杯咖啡去吧!☕

生成的 CSV 文件内容预览

title price rating stock upc
A Light in the Attic 51.77 3 22 a897fe39b1053632
Tipping the Velvet 53.74 1 20 90fa61229261140a
Soumission 50.10 1 20 6957f44c3847a760

🔟 常见问题与排错(建议收藏)

  1. HTML 抓到空壳?

    • 现象 :返回状态码 200,但 soup.select 什么都找不到。
    • 原因:网站可能是 Vue/React 动态渲染的。
    • 解法 :这时候 requests 不管用了,要上 Selenium 或者直接并在 F12 的 Network 选项卡里找 API 接口(JSON 格式)。
  2. 403 Forbidden / 429 Too Many Requests?

    • 原因:你爬太快了,或者 User-Agent 还是 Python 默认的。
    • 解法 :加长 time.sleep,或者购买代理 IP 池(Proxy Pool),在 requests 中添加 proxies 参数。
  3. 解析报错 AttributeError: 'NoneType' object has no attribute 'text'

    • 原因:选择器没定位到元素(页面结构变了,或者该商品确实没数据)。
    • 解法 :一定要像我在 parse_book_detail 里那样用 try-except 包裹,或者用 if element: 先判断再取值。

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

如果你想让你的爬虫更"专业",可以尝试:

  • 多线程并发 :使用 concurrent.futures.ThreadPoolExecutor,将串行爬取改为并行,速度能提升 5-10 倍(但要注意频率控制!)。
  • 断点续跑:在数据库或 Redis 中记录已经爬过的 URL 的指纹(MD5),下次启动时先比对,跳过已爬取的链接。
  • 日志监控 :使用 Python 的 logging 模块替代 print,将报错信息写入 spider.log,方便夜间无人值守运行时排错。

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

今天我们用不到 100 行代码就攻克了一个标准的电商类网站。复盘一下,我们完成了从请求伪装DOM 解析数据持久化的全过程。

下一步你可以挑战什么?

  • Scrapy 框架:如果你要爬取 10 万+ 的数据,手写 requests 会很累,Scrapy 是工业级的选择。
  • JS 逆向:去挑战一下那些加密了参数的接口,那才是爬虫工程师的"掉发之源"。👴

加油!代码在手,数据我有!如果在运行过程中遇到任何报错,随时把错误截图发给我,我来帮你 Debug!

🌟 文末

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

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

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

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

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

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

✅ 互动征集

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

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


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

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

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


✅ 免责声明

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

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

  • 合法使用: 不得将本项目用于任何违法、违规或侵犯他人权益的行为,包括但不限于网络攻击、诈骗、绕过身份验证、未经授权的数据抓取等。
  • 风险自负: 任何因使用本项目而产生的法律责任、技术风险或经济损失,由使用者自行承担,项目作者不承担任何形式的责任。
  • 禁止滥用: 不得将本项目用于违法牟利、黑产活动或其他不当商业用途。
  • 使用或者参考本项目即视为同意上述条款,即 "谁使用,谁负责" 。如不同意,请立即停止使用并删除本项目。!!!
相关推荐
张3蜂3 小时前
Python venv 详解:为什么要用、怎么用、怎么用好
开发语言·python
老赵全栈实战3 小时前
《从零搭建RAG系统第3天:文档加载+文本向量化+向量存入Milvus》
python
火龙果研究院3 小时前
在CentOS上安装Python 3.13需要从源码编译
开发语言·python·centos
龙山云仓3 小时前
No156:AI中国故事-对话司马迁——史家绝唱与AI记忆:时间叙事与因果之链
大数据·开发语言·人工智能·python·机器学习
niuniudengdeng3 小时前
一种基于高维物理张量与XRF实景复刻的一步闭式解工业级3D打印品生成模型
人工智能·python·数学·算法·3d
overmind4 小时前
oeasy Python 114 在列表指定位置插入insert
开发语言·python
喵手4 小时前
Python爬虫实战:监控型爬虫实战 - 从结构检测到智能告警的完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·csv导出·监控型爬虫实战·从结构哦检测到智能告警
深蓝电商API4 小时前
爬虫中 Cookie 池维护与自动刷新
爬虫·python
蜡笔羊驼4 小时前
LALIC环境安装过程
开发语言·python·深度学习