欢迎光临
我们一直在努力

Python爬虫实战:一键采集dangdang图书畅销榜 Top 500(附 CSV 导出)!

㊙️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~持续更新中!🔥🔥 ㊗️爬虫难度指数:⭐ 🚫声明:数据仅供个人学习数据分析使用,严禁用于商业比价系统或倒卖数据等,一切后果皆由使用者本人承担。公开榜单数据一般允许访问,但请务必遵守“君子协议”。

全文目录:

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

🌟 开篇语

哈喽,各位小伙伴们你们好呀~我是【喵手】。 运营社区: C站 / 掘金 / 腾讯云 / 阿里云 / 华为云 / 51CTO 欢迎大家常来逛逛,一起学习,一起进步~🌟

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

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

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

📣 专栏推广时间:如果你想系统学爬虫,而不是碎片化东拼西凑,欢迎订阅/关注专栏《Python爬虫实战》 订阅后更新会优先推送,按目录学习更高效~

1️⃣ 标题 && 摘要(Abstract)

项目名称:DangdangRankSpider_v1.0 核心工具:Python 3 + Requests + lxml (XPath) + Pandas 产出目标:自动化遍历当当畅销榜(共 25 页,500 本书),提取核心信息并生成 Excel/CSV 报表。

读完这篇文章,你将获得:

  • ⚡️ 解决中文乱码:彻底搞懂 GBK 与 UTF-8 的爱恨情仇,再也不怕爬下来的字全是“锟斤拷”。
  • 🔄 列表页遍历技巧:学会如何优雅地处理分页 URL,实现批量采集。
  • 🧹 数据清洗入门:如何从“(法)圣埃克苏佩里 著”这种复杂的字符串中提取干净的作者名。
  • 2️⃣ 背景与需求(Why)

    为什么要爬?

    畅销榜是图书市场的风向标。对于出版从业者或阅读爱好者来说,分析榜单可以知道现在大家都在看什么书?平均书价是多少?哪个出版社霸榜了?手动统计 500 本书太累,Python 脚本 30 秒就能搞定。

    🎯 目标站点:http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-recent7-0-0-1-1 (近 7 日畅销榜) 📋 目标字段清单:

    • Rank (排名):1, 2, 3…
    • Title (书名):去处多余的“推荐语”
    • Author (作者):需要清洗掉“著”、“编”等杂质
    • Price (价格):当前售价(需转为数字)
    • Discount (折扣):通过原价和售价计算(可选)

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

    • Robots 协议:电商网站通常对爬虫比较敏感。虽然公开榜单数据一般允许访问,但请务必遵守“君子协议”。
    • 频率控制:严禁多线程高并发!当当的反爬策略虽然不如豆瓣严格,但过快的请求依然会导致连接重置或 IP 封禁。我们依旧保持单线程 + 1秒延时。
    • 用途限制:数据仅供个人学习数据分析使用,严禁用于商业比价系统或倒卖数据。

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

    技术栈:

    • Requests:处理 HTTP 请求。
    • lxml (XPath):当当的 HTML 结构甚至比豆瓣还乱(各种嵌套),XPath 的层级定位能力(如 //li/div)在这里非常好用。

    🌊 整体流程: 生成 1-25 页 URL ➔ 请求网页 (注意编码) ➔ 解析列表 (<li>标签循环) ➔ 提取字段 ➔ Pandas 汇总 ➔ Result.csv

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

    Python 版本:3.8+

    依赖安装:

    pip install requests lxml pandas

    实际依赖安装如下:

    📂 项目结构:

    dangdang_spider/
    ├── results/
    │ └── dangdang_top500.csv
    ├── spider.py
    └── requirements.txt

    6️⃣ 核心实现:请求层(Fetcher)—— ⚠️ 乱码重灾区

    当当网的部分老旧页面依然沿用 GBK 或 GB2312 编码,而 requests 默认推测可能是 ISO-8859-1,如果不手动设置,爬下来的中文全是乱码。

    import requests
    import time
    from random import uniform

    def fetch_page(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://bang.dangdang.com/'
    }

    try:
    response = requests.get(url, headers=headers, timeout=10)

    # ⚠️ 关键点:当当网大部分页面是 GBK 编码
    # 如果不放心,可以用 response.apparent_encoding 自动检测
    # 但手动指定通常更稳
    response.encoding = 'gbk'

    if response.status_code == 200:
    return response.text
    else:
    print(f"❌ 状态码异常: {response.status_code}")
    return None

    except Exception as e:
    print(f"💥 请求出错: {e}")
    return None

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

    这里我们需要处理一个列表://ul[@class="bang_list"]/li。每一个 li 都是一本书。

    from lxml import etree
    import re

    def parse_html(html):
    if not html:
    return []

    parser = etree.HTMLParser()
    tree = etree.HTML(html, parser=parser)

    # 更稳:只要包含 bang_list 就行
    items = tree.xpath('//ul[contains(@class,"bang_list_mode")]/li[.//div[@class="name"]/a]')

    # 如果这里还是 0:说明拿到的 html 不是榜单页(风控/跳转/空壳)
    if not items:
    # 帮你快速定位问题:打印页面 title
    title = tree.xpath('//title/text()')
    print("⚠️ 未匹配到榜单列表,页面 title:", title[0].strip() if title else "None")
    return []

    books = []
    for item in items:
    try:
    # 排名
    rank = item.xpath('.//div[contains(@class,"list_num")]/text()')
    rank = rank[0].strip().strip('.') if rank else ""

    # 书名:优先 title,其次 text
    title = item.xpath('.//div[@class="name"]/a/@title')
    if not title:
    title = item.xpath('.//div[@class="name"]/a/text()')
    title = title[0].strip() if title else "未知书名"

    # 作者(第一块 publisher_info)
    author = item.xpath('.//div[contains(@class,"publisher_info")][1]//a[1]/text()')
    author = author[0].strip() if author else "未知作者"

    # 现价
    price_str = item.xpath('.//span[contains(@class,"price_n")]/text()')
    price_str = price_str[0] if price_str else ""
    price = float(re.sub(r"[^\\d.]", "", price_str) or 0)

    # 原价(可无)
    price_r_str = item.xpath('.//span[contains(@class,"price_r")]/text()')
    price_r_str = price_r_str[0] if price_r_str else ""
    price_r = float(re.sub(r"[^\\d.]", "", price_r_str) or 0)

    books.append({
    "Rank": rank,
    "Title": title,
    "Author": author,
    "Price": price,
    "Original_Price": price_r
    })

    except Exception as e:
    print(f"⚠️ 解析单条出错: {e}")
    continue

    return books

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

    import pandas as pd
    import os

    def save_to_csv(data_list):
    df = pd.DataFrame(data_list)

    # 简单的目录检查
    if not os.path.exists('results'):
    os.makedirs('results')

    path = 'results/dangdang_top500.csv'
    # 依然使用 utf-8-sig 防止 Excel 乱码
    df.to_csv(path, index=False, encoding='utf-8-sig')
    print(f"📊 数据已保存,共 {len(df)} 条。路径: {path}")

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

    这里涉及翻页逻辑。当当榜单 URL 规律是 …-recent7-0-0-1-{页码}。

    def main():
    base_url = "http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-recent7-0-0-1-{}"
    all_books = []

    print("🚀 开始抓取当当畅销榜 Top 500…")

    # 榜单共 25 页
    for page in range(1, 26):
    url = base_url.format(page)
    print(f"📄 正在处理第 {page}/25 页…")

    html = fetch_page(url)
    if html:
    data = parse_html(html)
    all_books.extend(data)
    print(f" ✅ 本页提取 {len(data)} 本书")

    # 礼貌延时
    time.sleep(uniform(0.5, 1.5))

    save_to_csv(all_books)
    print("🎉 任务全部完成!")

    if __name__ == "__main__":
    main()

    📊 结果示例 (Console):

    🚀 开始抓取当当畅销榜 Top 500…
    📄 正在处理第 1/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 2/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 3/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 4/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 5/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 6/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 7/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 8/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 9/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 10/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 11/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 12/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 13/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 14/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 15/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 16/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 17/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 18/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 19/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 20/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 21/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 22/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 23/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 24/25 页…
    ✅ 本页提取 20 本书
    📄 正在处理第 25/25 页…
    ✅ 本页提取 20 本书
    📊 数据已保存,共 500 条。路径: results/dangdang_top500.csv
    🎉 任务全部完成!

    实际本地运行结果如下:

    📋 CSV 文件预览:

    RankTitleAuthorPriceOriginal_Price
    1 蛤蟆先生去看心理医生 罗伯特·戴博德 23.90 38.00
    2 三体:全三册 刘慈欣 51.50 93.00
    3 长安的荔枝 马伯庸 29.80 45.00

    实际CSV保存数据展示如下:

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

  • 中文乱码(最常见)

    • 现象:书名全是 `` 或者 锟斤拷。
    • 解决:必须在 requests.get 后执行 response.encoding = 'gbk'。如果 GBK 报错,尝试 gb18030(GBK 的超集)。
  • XPath 提取为空

    • 当当的 HTML 很乱,有时作者栏没有链接 <a>,只有纯文本。
    • 优化 XPath:div[@class="publisher_info"][1]//text() 可以提取该 div 下所有文本,然后再做字符串清洗。
  • 价格提取失败

    • 有些书可能是电子书或缺货,价格标签的 class 可能会变。建议使用 try-except 给价格默认赋值 -1 或 0,方便后续清洗。
  • 1️⃣1️⃣ 进阶优化(可选但加分)

    • 数据清洗 pro 版:现在的作者列可能包含“[日]”、“著”、“译”等字样。可以使用 Pandas 配合正则表达式 re.sub(r'[\\[\\(].*?[\\)\\]]', '', name) 一键清洗掉方括号里的国籍。
    • 多维度分析:拿到 Price 和 Original_Price 后,可以计算一个 Discount_Rate(折扣率),看看前 10 名的书是不是因为打折狠才卖得好?🤔

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

    当当网的爬取难度在于“脏数据”的处理和编码的坑。完成了这个任务,说明你已经具备了处理老旧网站和批量翻页列表的能力。

    下一步挑战:

    • 京东图书:京东的价格通常是 JS 动态加载的(为了防止爬虫比价),requests 抓不到价格。你需要去 Network 面板找那个隐藏的 API 接口,难度瞬间提升一个 Level!🧗‍♂️

    代码写好了,快去试试能抓到什么好书吧!如果有报错,记得看乱码那一部分哦!

    🌟 文末

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

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

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

    专栏 👉 《Python爬虫实战》,我会按照“入门 → 进阶 → 工程化 → 项目落地”的路线持续更新,争取让每一篇都做到:

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

    📣 想系统提升的小伙伴:强烈建议先订阅专栏,再按目录顺序学习,效率会高很多~

    ✅ 互动征集

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

    评论区留言告诉我你的需求,我会优先安排更新 ✅


    ⭐️ 若喜欢我,就请关注我叭~(更新不迷路) ⭐️ 若对你有用,就请点赞支持一下叭~(给我一点点动力) ⭐️ 若有疑问,就请评论留言告诉我叭~(我会补坑 & 更新迭代)


    免责声明:本文仅用于学习与技术研究,请在合法合规、遵守站点规则与 Robots 协议的前提下使用相关技术。严禁将技术用于任何非法用途或侵害他人权益的行为。

    赞(0)
    未经允许不得转载:171主机测评 » Python爬虫实战:一键采集dangdang图书畅销榜 Top 500(附 CSV 导出)!
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址