2026/10/15 10:17:53

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

Python爬虫实战:Requests+BeautifulSoup抓取Books to Scrape 1. 项目背景与核心价值Books to Scrape 是一个专门为爬虫学习设计的沙盒网站它模拟了真实电商网站的结构和反爬机制但不会触发法律风险。这个项目看似简单实际上涵盖了爬虫工程师日常工作中的完整链路从页面请求、数据解析到结构化存储。我选择这个案例教学是因为它完美呈现了三个关键学习点如何处理分页数据该网站有50页图书列表如何提取嵌套的多级页面信息列表页→详情页如何应对常见的反爬策略该网站故意设置了请求频率限制2. 技术方案设计2.1 工具选型解析采用 Requests BeautifulSoup 组合而非 Scrapy原因有三轻量级架构更适合教学演示避免Scrapy的学习曲线干扰核心逻辑该网站没有动态渲染内容无需Seleniumimport requests from bs4 import BeautifulSoup import csv import time2.2 爬取策略设计采用广度优先策略先遍历所有列表页获取图书链接再并发请求详情页提取数据最后统一写入CSV文件注意网站明确要求请求间隔≥3秒我们在代码中会设置time.sleep(3.5)3. 核心代码实现3.1 分页URL生成器该网站分页规则很有代表性首页http://books.toscrape.com/ 第n页http://books.toscrape.com/catalogue/page-n.htmldef 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, encodingutf-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 异常处理机制必须处理的三种异常情况网络请求超时增加重试机制页面结构变化添加字段存在性校验编码问题统一UTF-8处理def safe_request(url, retry3): for i in range(retry): try: response requests.get(url, timeout10) 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_workers3) as executor: results list(executor.map(parse_book_detail, links)) return results5.2 数据质量检查导出前建议进行数据校验检查必填字段缺失率验证价格数值范围去重处理基于URLdef validate_data(books): for book in books: assert book[price] 0, fInvalid price: {book[title]} assert 1 book[rating] 5, fInvalid rating: {book[title]}6. 实战经验分享6.1 反爬应对策略该网站设置的几个典型反爬机制User-Agent检测需设置常见浏览器UA请求频率限制严格遵守3秒间隔异常流量检测避免短时间内大量请求推荐使用真实浏览器头headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 }6.2 数据存储优化CSV虽然简单但大数据量时建议分块写入每100条flush一次使用csv.DictWriter确保字段一致性添加爬取时间戳作为批次标识def write_chunk(writer, chunk): for item in chunk: item[crawl_time] datetime.now().isoformat() writer.writerow(item)7. 项目扩展方向这个基础项目可以深化为价格监控系统定期爬取比价图书推荐引擎基于评分/价格分析自动化测试平台验证网站稳定性例如构建价格趋势分析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(titlePrice Trend)8. 法律合规提醒即使对沙盒网站也需注意严格遵守robots.txt规定控制请求频率不影响服务器数据仅用于学习研究商业用途需获得授权建议在代码中添加合规声明 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.