ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Python爬虫实战:Requests+BeautifulSoup抓取Books to Scrape

Python爬虫实战:Requests+BeautifulSoup抓取Books to Scrape

1. 项目背景与核心价值

Books to Scrape 是一个专门为爬虫学习设计的沙盒网站,它模拟了真实电商网站的结构和反爬机制,但不会触发法律风险。这个项目看似简单,实际上涵盖了爬虫工程师日常工作中的完整链路:从页面请求、数据解析到结构化存储。

我选择这个案例教学,是因为它完美呈现了三个关键学习点:

  • 如何处理分页数据(该网站有50页图书列表)
  • 如何提取嵌套的多级页面信息(列表页→详情页)
  • 如何应对常见的反爬策略(该网站故意设置了请求频率限制)

2. 技术方案设计

2.1 工具选型解析

采用 Requests + BeautifulSoup 组合而非 Scrapy,原因有三:

  1. 轻量级架构更适合教学演示
  2. 避免Scrapy的学习曲线干扰核心逻辑
  3. 该网站没有动态渲染内容,无需Selenium
import requests from bs4 import BeautifulSoup import csv import time

2.2 爬取策略设计

采用广度优先策略:

  1. 先遍历所有列表页获取图书链接
  2. 再并发请求详情页提取数据
  3. 最后统一写入CSV文件

注意:网站明确要求请求间隔≥3秒,我们在代码中会设置time.sleep(3.5)

3. 核心代码实现

3.1 分页URL生成器

该网站分页规则很有代表性:

首页:http://books.toscrape.com/ 第n页:http://books.toscrape.com/catalogue/page-n.html
def generate_page_urls(): base_url = "http://books.toscrape.com/catalogue/page-{}.html" for page in range(1, 51): # 共50页 yield base_url.format(page)

3.2 详情页数据提取

每本书需要采集的字段包括:

  • 书名
  • 价格(含货币符号处理)
  • 库存状态
  • 星级评分(转换数字)
  • 产品描述
  • 分类标签
def parse_book_detail(url): response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') # 提取核心字段 title = soup.select_one('h1').text price = float(soup.select_one('.price_color').text[1:]) # 去掉£符号 stock = 'In stock' in soup.select_one('.availability').text # 星级转换逻辑 star_class = soup.select_one('.star-rating')['class'][1] star_map = {'One':1, 'Two':2, 'Three':3, 'Four':4, 'Five':5} rating = star_map[star_class] return { 'title': title, 'price': price, 'stock': stock, 'rating': rating, 'url': url }

4. 完整爬取流程

4.1 主控程序架构

def main(): with open('books.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=['title','price','stock','rating','url']) writer.writeheader() for page_url in generate_page_urls(): book_links = get_book_links(page_url) for link in book_links: book_data = parse_book_detail(link) writer.writerow(book_data) time.sleep(3.5) # 遵守爬取间隔

4.2 异常处理机制

必须处理的三种异常情况:

  1. 网络请求超时(增加重试机制)
  2. 页面结构变化(添加字段存在性校验)
  3. 编码问题(统一UTF-8处理)
def safe_request(url, retry=3): for i in range(retry): try: response = requests.get(url, timeout=10) response.raise_for_status() return response except Exception as e: if i == retry - 1: raise time.sleep(2)

5. 高级技巧与优化

5.1 并发控制实现

虽然该网站要求串行访问,但实际项目中可以这样优化:

from concurrent.futures import ThreadPoolExecutor def batch_crawl(links): with ThreadPoolExecutor(max_workers=3) as executor: results = list(executor.map(parse_book_detail, links)) return results

5.2 数据质量检查

导出前建议进行数据校验:

  • 检查必填字段缺失率
  • 验证价格数值范围
  • 去重处理(基于URL)
def validate_data(books): for book in books: assert book['price'] > 0, f"Invalid price: {book['title']}" assert 1 <= book['rating'] <= 5, f"Invalid rating: {book['title']}"

6. 实战经验分享

6.1 反爬应对策略

该网站设置的几个典型反爬机制:

  1. User-Agent检测(需设置常见浏览器UA)
  2. 请求频率限制(严格遵守3秒间隔)
  3. 异常流量检测(避免短时间内大量请求)

推荐使用真实浏览器头:

headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' }

6.2 数据存储优化

CSV虽然简单,但大数据量时建议:

  1. 分块写入(每100条flush一次)
  2. 使用csv.DictWriter确保字段一致性
  3. 添加爬取时间戳作为批次标识
def write_chunk(writer, chunk): for item in chunk: item['crawl_time'] = datetime.now().isoformat() writer.writerow(item)

7. 项目扩展方向

这个基础项目可以深化为:

  1. 价格监控系统(定期爬取比价)
  2. 图书推荐引擎(基于评分/价格分析)
  3. 自动化测试平台(验证网站稳定性)

例如构建价格趋势分析:

import pandas as pd def analyze_price_trend(): df = pd.read_csv('books.csv') df['crawl_time'] = pd.to_datetime(df['crawl_time']) return df.groupby('title')['price'].plot(title='Price Trend')

8. 法律合规提醒

即使对沙盒网站也需注意:

  1. 严格遵守robots.txt规定
  2. 控制请求频率不影响服务器
  3. 数据仅用于学习研究
  4. 商业用途需获得授权

建议在代码中添加合规声明:

""" This crawler is for educational purpose only. Data will not be used for any commercial activities. Request interval is set to 3.5s as required. """
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进