我的第一个Python爬虫程序 爬豆瓣图书top 250列表

这篇笔记📒记录我的第一个Python爬虫程序,我们要抓取豆瓣读书 Top 250这个页面,想要的结果就是豆瓣图书top250 表格文件,包含书名、作者、出版社、评分等信息

要抓取的页面截图

脚本执行后的结果,生成一个CSV文件

我们要写一个网页抓取脚本,使用Python的seleniumBeautifulSoup来从豆瓣读书Top 250页面提取书籍信息(如书名、出版信息、评分和简介),然后将这些数据保存到一个CSV文件中。分为以下几个主要部分:

  1. 导入库:加载必要的工具
  2. 设置浏览器:配置一个自动化浏览器来访问网页
  3. 定义函数:
    • get_books(): 从网页提取书籍数据
    • save_to_csv(): 将数据保存到CSV文件
  4. 主函数main(): 控制整个流程,循环抓取所有页面。
1. 导入库
python 复制代码
import csv
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup
  • import csv: 导入Python内置的csv模块,用于读写CSV文件
  • import time: 导入time模块,提供时间相关的功能,比如让程序暂停几秒钟
  • from selenium import webdriver: 导入selenium库的webdriver模块,用于控制浏览器(比如Chrome).selenium是一个自动化测试工具,这里用来模拟浏览器访问网页。
  • from selenium.webdriver.chrome.service import Service: 导入Service类,用于管理Chrome浏览器的驱动程序。
  • from selenium.webdriver.chrome.options import Options: 导入Options类,用于设置浏览器的选项(比如无界面模式)
  • from selenium.webdriver.common.by import By: 导入By类,用于制定如何查找网页元素(比如通过类名、ID等)。这里虽然没有直接使用,但它是selenium的常用工具。
  • from webdriver_manager.chrome import ChromeDriverManager: 导入ChromeDriverManager,它会自动下载并管理Chrome浏览器的驱动程序(chromedriver),无需手动安装。
  • from bs4 import BeautifulSoup: 导入BeautifulSoup, 一个强大的HTML杰西库,用来从网页源码中提取数据
2.设置 Chrome WebDriver
python 复制代码
options = Options()
options.add_argument('--headless') // 无UI模式
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()),options=options)
  • options = Options(): 创建一个Options对象,用于设置浏览器行为。
  • options.add_argument("--headless"): 添加一个参数,让浏览器以"无UI模式模式"运行。也就是说,浏览器会在后台运行,因为我们抓取数据,不需要界面。
  • driver = webdriver.Chrome(...): 创建一个 Chrome 浏览器的实例。
    • service=Service(ChromeDriverManager().install()): 使用ChromeDriverManager自动下载并设置Chrome驱动程序。驱动程序是Python和浏览器之间的桥梁
    • options=options: 将我们设置的无UI模式应用到浏览器
3. 定义get_books函数
python 复制代码
def get_books(url):
   driver.get(url)
   time.sleep(3) # 等待JavaScript加载
   
   soup = BeautifulSoup(driver.page_source, 'html.parser')
   books = []
   
   items = soup.find_all('tr', class_='item')
   print(f"Found {len(items)} items") # 调试
   
   for item in items:
      title = item.find('div', class_="pl2').find('a').text.strip()
      info = item.find('p', class_='pl').text.strip()
      rating_tag = item.find('span', class_='rating_nums')
      rating = rating_tag.text if rating_tag else '无评分'
      quote_tag = item.find('span', class_='inq')
      quote = quote.tag.text if quote_tag else '暂无简介'
      
      books.append({'title': title, 'info': info, 'rating': rating, 'quote': quote})
   return books

这个函数的作用是给制定的URL (豆瓣读书页面)提取书籍信息

  • def get_books(url): 定义一个函数,参数是url(网页地址)
  • driver.get(url): 让浏览器访问指定的URL。
  • time.sleep(3): 暂停3秒钟。因为豆瓣的页面使用JavaScript动态加载内容,暂停一下确保页面完全加载
  • soup = BeautifulSoup(driver.page_source, 'html.parse'):
    • driver.page-source: 获取浏览器加载后的网页源码(HTML)
    • BeautifulSoup(..., 'html.parser'): 用BeautifulSoup解析HTML, 方便提取数据
  • books = []: 创建一个空列表, 用来存储书籍信息
  • items = soup.find_all('tr', class_='item')
    • find_all('tr', class_='item'): 查找所有HTML中的<tr>标签,且带有class="item"的属性。在豆瓣页面,每本书的信息都包裹在一个这样的<tr>标签里
  • print(f"Found {len(items)} items"): 打印找到的书籍数量,用于调试。如果数量不对,可能说明网页结构变了
  • for item in items:: 循环遍历每本书的<tr>标签,提取信息:
    • title = item.find('div', class_='pl2').find('a').text.strip():
    • find('div', class_='pl2'): 找到<div class="pl2">, 这是书名所在的区域
    • find('a'): 找到里面的<a>标签(超链接),书名在其中
    • .text: 提取文本内容
    • .strip(): 去除多余的空格或换行符
  • info = item.find('p', class_='pl').text.strip(): 找到<p class="pl">, 这是出版信息(如作者、出版社、价格)
  • rating_tag = item.find('span', class_='rating_nums): 找到评分所在的<span class="rating_nums">
  • rating = rating_tag.text if rating_tag else "无评分"
    • 如果找到了评分标签,就取其文本;如果没找到(rating_tag 是 None),返回"无评分"。
  • quote_tag = item.find('span', class_='inq'):找到简介所在的 。
  • quote = quote_tag.text if quote_tag else "暂无简介":同上,取简介或返回默认值。
  • books.append({...}) :将每本书的信息(字典形式)添加到 books 列表中。

return books: 返回包含所有书籍信息的列表

这个函数就像一个"图书管理员",它打开网页,找到每本书的"卡片"(<tr>),然后把卡片上的信息(书名、评分等)抄下来,整理成清单。

4. 定义save_to_csv函数
python 复制代码
def save_to_csv(books, filename="douban_books_top_250.csv"):
    with open(filename, mode="w", encoding="utf-8-sig", newline="") as file:
      writer = csv.DictWriter(file, filenames=["序号", "书名", "出版信息", "评分", "简介"])
      writer.writeheader()
    
      # 增加索引从1到250
      for index, book in enumerate(books, start=1)
           book['序号'] = index
           writer.writerow(book)
      print(f"Data saved to {filename}")

这个函数将书籍数据保存到CSV文件中

  • def save_to_csv(books, filename="douban_books_top_250.csv"): 定义函数,参数是书籍列表books和文件名(默认是douban_books_top_250),如果调用时不提供文件名,就用这个默认值
  • with open(filename, mode="w", encoding="utf-8-stig", newline="") as file::
    • open(): 打开一个文件
    • mode="w": 以写入模式打开(会覆盖原有文件)
    • encoding="utf-8-stig": 使用UTF-8编码(支持中文),sig确保Windows的Excel中打开时中文不会乱码
    • newline="": 避免CSV文件有多余空行(这是Python处理CSV时的常见设置)
    • with: 这是一个上下文管理器,自动在操作完成后关闭文件,防止资源浪费
    • as file: 将打开的文件对象命名为file,后续操作会用到它
  • `writer = csv.DictWriter(file, fieldnames=["序号", "书名", "出版信息", "评分", "简介"])
    • 创建一个CSV写入器,制定列名(表头),这些名字会出现在文件的第一行
  • writer.writeheader(): 将fieldnames中指定的列名写入CSV文件的第一行
python 复制代码
for index, book in enumerate(books, start=1): 
    book["序号"] = index 
    writer.writerow(book)
  • for index, book in enumerate(books, start=1):

    • 这是一个循环,遍历 books 列表中的每一本书。
    • enumerate(books, start=1)
      • enumerate 是一个内置函数,它会给列表中的每个元素配一个编号。
      • start=1:让编号从 1 开始(默认是 0)。
      • 每次循环:
        • index 是当前的编号(1, 2, 3, ..., 250)。
        • book 是当前书的字典,比如 {'title': '活着', 'info': '余华 / 作家出版社', ...}。
  • book["序号"] = index

    • 为当前书的字典添加一个新键值对:"序号": index。
    • 比如,第一本书的字典会变成 {'title': '活着', 'info': '...', '序号': 1}。
  • writer.writerow(book)

    • 将当前书的字典写入 CSV 文件的一行。
    • DictWriter 会根据 fieldnames 的顺序,自动匹配字典的键,把值写入对应列。
    • 比如:2,活着,余华 / 作家出版社,9.2,生的苦难与伟大。
5. 定义 main函数
python 复制代码
def main():
    base_url = "https://book.douban.com/top250"
    all_books = []
    
    for start in range(0, 250, 25):
       url = f"{base_url}?start={start}"
       books = get_books(url)
       all_books.extend(books)
     
    save_to_csv(all_books)
    driver.quit()

这个函数是程序的核心,控制抓取和保存的流程。

  • base_url = "book.douban.com/top250" :豆瓣 Top 250 的基础 URL。
  • all_books = [] :创建一个空列表,存储所有 250 本书的信息。
  • for start in range(0, 250, 25):
    • range(0, 250, 25):生成一个序列:0, 25, 50, ..., 225。豆瓣每页显示 25 本书,总共 250 本,分 10 页。
    • 每次循环抓取一页。
  • url = f"{base_url}?start={start}" :构造每页的 URL,比如 book.douban.com/top250?star... 1 页)、?start=25(第 2 页)。
  • books = get_books(url) :调用 get_books 函数,抓取当前页的书籍。
  • all_books.extend(books) :将当前页的书籍添加到总列表中(extend 是列表的合并方法)。
  • save_to_csv(all_books) :抓取完所有页面后,将数据保存到 CSV。
  • driver.quit() :关闭浏览器,释放资源。
6. 执行代码
python 复制代码
if __name__ == "__main__"
    main()
  • if name == "main": :这是 Python 的习惯写法,确保 main() 只在直接运行这个脚本时执行(而不是被其他文件导入时运行)。
  • main() :调用主函数,启动程序。

代码的工作流程

  1. 配置并启动一个无界面的 Chrome 浏览器。
  2. 循环访问豆瓣 Top 250 的 10 个页面(每页 25 本书)。
  3. 对每个页面:
    • 用 selenium 加载网页。 - 用 BeautifulSoup 解析网页,提取书籍信息。
  4. 将所有 250 本书的信息存入列表。
  5. 将列表保存到 douban_books.csv 文件。
  6. 关闭浏览器。 执行结果

完整代码

python 复制代码
import csv
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from bs4 import BeautifulSoup

# Setup Chrome WebDriver
options = Options()
options.add_argument("--headless")  # Run in headless mode (no UI)
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)

def get_books(url):
    driver.get(url)
    time.sleep(3)  # Wait for JavaScript to load (adjust as needed)
    
    soup = BeautifulSoup(driver.page_source, 'html.parser')
    books = []
    
    items = soup.find_all('tr', class_='item')  # Douban uses <tr> for book items
    print(f"Found {len(items)} items")  # Debugging output
    
    for item in items:
        title = item.find('div', class_='pl2').find('a').text.strip()
        info = item.find('p', class_='pl').text.strip()
        rating_tag = item.find('span', class_='rating_nums')
        rating = rating_tag.text if rating_tag else "无评分"
        quote_tag = item.find('span', class_='inq')
        quote = quote_tag.text if quote_tag else "暂无简介"

        books.append({'书名': title, '出版信息': info, '评分': rating, '简介': quote})
    
    return books

# Save data to CSV
def save_to_csv(books, filename="douban_books_top_250.csv"):
    with open(filename, mode="w", encoding="utf-8-sig", newline="") as file:
        writer = csv.DictWriter(file, fieldnames=["序号", "书名", "出版信息", "评分", "简介"])
        writer.writeheader()

        #  Add index number from 1 to 250
        for index, book in enumerate(books, start=1):
            book["序号"] = index
            writer.writerow(book)
    print(f"Data saved to {filename}")

# Main function
def main():
    base_url = "https://book.douban.com/top250"
    all_books = []
    
    for start in range(0, 250, 25):
        url = f"{base_url}?start={start}"
        books = get_books(url)
        all_books.extend(books)

    # Save to CSV
    save_to_csv(all_books)

    driver.quit()

if __name__ == "__main__":
    main()
相关推荐
别让别人觉得你做不到28 分钟前
Python(1) 做一个随机数的游戏
python
小彭律师2 小时前
人脸识别门禁系统技术文档
python
张小九993 小时前
PyTorch的dataloader制作自定义数据集
人工智能·pytorch·python
zstar-_4 小时前
FreeTex v0.2.0:功能升级/支持Mac
人工智能·python·macos·llm
苏生要努力4 小时前
第九届御网杯网络安全大赛初赛WP
linux·python·网络安全
于壮士hoho4 小时前
DeepSeek | AI需求分析
人工智能·python·ai·需求分析·dash
蒙奇D索大4 小时前
【人工智能】自然语言编程革命:腾讯云CodeBuddy实战5步搭建客户管理系统,效率飙升90%
人工智能·python·django·云计算·腾讯云
AndrewHZ4 小时前
【Python生活】如何构建一个跌倒检测的算法?
python·算法·生活·可视化分析·陀螺仪·加速度计·跌倒检测
lizz6664 小时前
Python查询ES错误ApiError(406, ‘Content-Type ...is not supported
python·elasticsearch
lqjun08274 小时前
Focal Loss 原理详解及 PyTorch 代码实现
人工智能·pytorch·python