当前位置: 首页 > news >正文

Python爬虫实战(一):图书网站API接口爬取

一、前言

在大数据时代,数据采集是数据分析的第一步。对于初学者来说,爬虫技术往往从静态网页起步,但现代Web应用大量采用前后端分离架构,数据通过Ajax接口动态加载。这种场景下,传统的BeautifulSoup解析HTML往往力不从心,必须转向API接口分析JSON数据解析

本文将以 Scrape Center图书网站 为实战目标,深入讲解如何:

  • 分析动态网站的API接口规律
  • 使用requests库构造请求并处理SSL证书问题
  • 解析嵌套JSON数据结构
  • 实现列表页+详情页的两级爬取策略
  • 使用pandas进行数据清洗与持久化存储

目标站点特点:该网站是一个典型的单页应用(SPA),页面内容由JavaScript渲染,数据通过RESTful API接口返回JSON格式,非常适合练习接口型爬虫技术。


二、网站分析与接口探测

2.1 网站首页概览

首先打开目标网站https://spa5.scrape.center/,可以看到一个精美的图书展示页面:

观察发现:页面加载后,图书信息并非直接写在HTML源码中,而是通过异步请求获取。这意味着我们需要打开浏览器开发者工具(F12),切换到Network → XHR面板,分析背后的数据接口。

2.2 接口规律分析

通过抓包分析,我们可以发现两个核心API:

接口类型URL格式说明
列表接口https://spa5.scrape.center/api/book/?limit={数量}&offset={偏移量}返回图书列表,含基础信息
详情接口https://spa5.scrape.center/api/book/{id}/返回单本图书的详细信息

分页参数逻辑:

  • limit:每页返回的图书数量(实测为18条/页)
  • offset:数据偏移量,第1页offset=0,第2页offset=18,以此类推

这种偏移量分页(Offset-based Pagination)是RESTful API中最常见的分页方式之一,相比页码分页更加灵活,但也需要注意边界条件判断。

2.3 返回数据结构剖析

列表接口返回的JSON结构如下(已简化):

{"count":1000,"results":[{"id":"1","name":"解忧杂货店","authors":["东野圭吾"],"score":"8.5","price":39.5,"cover":"https://.../cover.jpg"}]}

详情接口返回更丰富的字段:

{"id":"1","name":"解忧杂货店","authors":["东野圭吾"],"tags":["小说","日本文学","治愈"],"url":"https://spa5.scrape.center/detail/1","introduction":"...","comments":[...]}

关键洞察:id字段是连接列表页与详情页的枢纽。列表页获取id,再拼接详情页URL获取完整数据——这是典型的两级爬取架构


三、代码实现与深度解析

3.1 完整源码

importjsonimportpandasaspdimportrequestsimporturllib3# ========================================# 第一部分:环境配置与初始化# ========================================# urllib3.disable_warnings() 的作用是禁用由 urllib3 引发的 SSL 证书验证警告。# 目标站点使用了自签名证书或证书链不完整,直接请求会抛出 InsecureRequestWarning。# 在生产环境中,建议配置正确的证书路径而非直接禁用,此处仅为学习目的。urllib3.disable_warnings()# 初始化数据容器:采用"列式存储"策略,每个字段维护一个列表# 这种设计便于最后直接构建 DataFrame,比逐行追加字典效率更高book_ids=[]# 图书IDnames=[]# 书名authors_list=[]# 作者(可能有多位,需处理为字符串)urls=[]# 详情页链接themes=[]# 主题标签# 构造请求头:模拟真实浏览器行为,绕过基础的UA检测反爬机制# 现代反爬系统会检查User-Agent、Accept-Language等字段的一致性headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ''AppleWebKit/537.36 (KHTML, like Gecko) ''Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0','Accept':'application/json, text/plain, */*','Accept-Language':'zh-CN,zh;q=0.9,en;q=0.8','Referer':'https://spa5.scrape.center/'}# ========================================# 第二部分:分页爬取逻辑# ========================================RECORDS_PER_PAGE=18# 每页记录数,与接口limit参数保持一致MAX_PAGES=3# 控制爬取页数,避免对目标服务器造成过大压力page=0# 页码计数器whilepage<MAX_PAGES:# 计算偏移量:offset = 页码 × 每页数量# 这种分页方式的优势在于可以灵活调整起始位置,支持"断点续爬"offset=page*RECORDS_PER_PAGE# 构造列表页API地址:使用f-string进行参数拼接,清晰直观list_url=f'https://spa5.scrape.center/api/book/?limit={RECORDS_PER_PAGE}&offset={offset}'print(f"\n{'='*50}")print(f"正在爬取第{page+1}页,偏移量 offset={offset}")print(f"请求URL:{list_url}")print(f"{'='*50}")# 发送GET请求:# verify=False 跳过SSL证书验证(学习用途)# timeout参数建议添加,防止网络波动导致程序卡死try:response=requests.get(list_url,headers=headers,verify=False,timeout=10)response.raise_for_status()# 检查HTTP状态码,4xx/5xx会抛出异常exceptrequests.RequestExceptionase:print(f"请求失败:{e}")break# 解析JSON响应:requests内置的.json()方法比json.loads(response.text)更简洁# 但底层原理相同:将JSON字符串反序列化为Python字典data=response.json()# 边界条件判断:如果results为空列表,说明已到达最后一页,优雅退出循环ifnotdata.get('results'):print("未获取到数据,可能已到达最后一页,爬取结束。")break# ========================================# 第三部分:列表页数据提取 + 详情页递归爬取# ========================================# 遍历当前页的每一本图书forbook_itemindata['results']:# 提取列表页已有字段book_id=book_item['id']book_name=book_item['name']# 作者字段处理技巧:# 接口返回的是列表类型,如 ["东野圭吾"] 或 ["刘慈欣", "韩松"]# 需要转换为字符串,同时清洗换行符、单引号等噪音字符book_authors=str(book_item['authors'])\.replace('[','')\.replace(']','')\.replace("'","")\.replace('\\n','')\.strip()print(f"\n[列表页] ID:{book_id}| 书名:{book_name}| 作者:{book_authors}")# 将列表页数据暂存到容器book_ids.append(book_id)names.append(book_name)authors_list.append(book_authors)# ========================================# 详情页爬取:基于ID拼接URL,实现"由浅入深"的数据获取# ========================================detail_url=f'https://spa5.scrape.center/api/book/{book_id}/'try:detail_response=requests.get(detail_url,headers=headers,verify=False,timeout=10)detail_response.raise_for_status()exceptrequests.RequestExceptionase:print(f"详情页请求失败 ID={book_id}:{e}")# 失败时填充空值,保证数据结构完整性,避免后续DataFrame构建时报错urls.append('')themes.append('')continue# 解析详情页JSONdetail_data=detail_response.json()# 提取详情页特有字段book_url=detail_data.get('url','')# 使用.get()提供默认值,防止KeyError# 主题标签同样为列表类型,需做字符串转换与清洗book_theme=str(detail_data.get('tags',[]))\.replace('[','')\.replace(']','')\.replace("'","")\.strip()print(f"[详情页] URL:{book_url}| 主题:{book_theme}")urls.append(book_url)themes.append(book_theme)# 页码递增,准备下一页page+=1# 礼貌爬取:在页与页之间添加短暂延迟,降低服务器负载,避免触发频率限制# 实际生产环境中建议使用 random.uniform(1, 3) 随机延时,模拟人类行为# import time; time.sleep(1)# ========================================# 第四部分:数据整合与持久化# ========================================print(f"\n{'='*50}")print(f"爬取完成!共获取{len(names)}条图书记录")print(f"{'='*50}")# 使用字典构造"列式数据",键为列名,值为列表(DataFrame的标准输入格式)book_dict={"链接":urls,"书名":names,"作者":authors_list,"主题":themes,}# 构建DataFrame:pandas会自动对齐各列长度,进行向量化操作work=pd.DataFrame(book_dict)# 数据持久化:保存为制表符分隔的txt文件# sep='\t' 使用制表符分隔,Excel可直接打开且不会混淆内容中的逗号# index=False 不保存行索引,保持数据整洁# encoding='utf-8' 确保中文不乱码output_file='books_list.txt'work.to_csv(output_file,sep='\t',index=False,encoding='utf-8')print(f"\n数据已保存至:{output_file}")print("预览前5条数据:")print(work.head())

3.2 核心设计思想解析

(1)两级爬取架构

本案例采用了**“列表页→详情页”**的两级爬取策略,这是工业爬虫中最常见的模式之一:

列表页API ── 获取ID列表 ── 循环拼接详情API ── 获取完整数据

优势:

  • 减少单次请求的数据传输量(列表页轻量,详情页丰富)
  • 降低服务器压力,避免一次性返回过多数据导致超时
  • 便于实现断点续传:如果中断,只需记录当前处理到的ID
(2)数据清洗策略

接口返回的authorstags字段均为Python列表类型,直接存储会导致数据格式混乱。我的处理策略是:

# 原始数据:['东野圭吾'] 或 ['刘慈欣', '韩松']# 转换后:"东野圭吾" 或 "刘慈欣, 韩松"

这里使用了防御性编程str()转换 +replace()清洗 +strip()去空白,确保即使接口返回格式微调,代码也能健壮运行。

(3)异常处理机制

代码中在每个网络请求点都设置了try-except块:

  • 列表页失败:直接退出循环,避免无效重试
  • 详情页失败:填充空字符串,保证DataFrame列长度一致,不中断整体流程

这种**“优雅降级”**思想在实际生产中至关重要——爬虫面对的是不可靠的网络环境,必须假设每一步都可能失败。


四、运行效果展示

4.1 控制台输出

程序运行时的控制台输出如下,可以清晰看到两级爬取的流程:

输出特征:

  • 每页请求前有清晰的分隔线与页码提示
  • 列表页与详情页数据分行展示,便于调试时定位问题
  • 实时打印进度,长任务执行时给予用户反馈

4.2 最终数据文件

爬取完成后,生成的books_list.txt文件用Excel打开后效果如下:

文件特点:

  • 制表符分隔,Excel自动识别为表格
  • 中文显示正常(UTF-8编码)
  • 无行索引干扰,数据纯净可直接用于后续分析

五、进阶思考与优化方向

5.1 性能优化:异步并发

当前代码采用同步串行请求,详情页逐个获取效率较低。当数据量达到数千条时,建议使用aiohttp实现异步并发:

importaiohttpimportasyncioasyncdeffetch_detail(session,book_id):url=f'https://spa5.scrape.center/api/book/{book_id}/'asyncwithsession.get(url)asresponse:returnawaitresponse.json()

据测试,异步模式可将爬取效率提升5-10倍,特别适合此类I/O密集型任务。

5.2 反爬对抗策略

虽然本站点为学习用途未设置强反爬,但实际场景中需要考虑:

  • 请求频率控制:使用time.sleep(random.uniform(1, 3))模拟人类操作间隔
  • IP代理池:高频率请求时轮换代理IP
  • 请求头轮换:定期更换User-Agent,甚至模拟完整的浏览器指纹

5.3 数据存储升级

当数据量增大时,txt/CSV文件的管理变得困难,建议升级存储方案:

场景推荐方案优势
结构化数据 < 10万条SQLite轻量级,无需单独部署
大规模数据 + 分析MySQL/PostgreSQL支持复杂查询与索引
非结构化/文档型MongoDB灵活存储JSON原生数据

六、总结

通过本次实战,我们完整掌握了接口型爬虫的核心技术栈:

  1. 接口分析能力:学会使用浏览器开发者工具抓取Ajax请求,分析URL规律与参数含义
  2. JSON解析技巧:理解Python字典/列表的嵌套结构,熟练进行数据提取与清洗
  3. 两级爬取架构:掌握"列表页获取ID → 详情页获取完整数据"的经典模式
  4. 工程化思维:异常处理、数据校验、礼貌爬取等生产级代码习惯

如果本文对你有帮助,欢迎点赞、收藏、关注!有任何问题欢迎在评论区留言讨论。

http://www.jsqmd.com/news/819273/

相关文章:

  • 基于Playwright的插件化浏览器自动化框架:从脚本到工程化实践
  • BNO055九轴姿态传感器:从传感器融合原理到Arduino/Python实战应用
  • DeepSeek模型上云卡在哪?Azure部署失败率高达63%的3个隐形雷区,速查!
  • 别再死记公式了!手把手教你用Multisim仿真RC正弦波振荡电路(含二极管稳幅)
  • 林俊旸创业!20亿美元估值,转战世界模型和具身大脑
  • dotpmt:超越点文件管理的模板化配置分发框架
  • Shell脚本状态管理革命:用SQLite为Bash脚本注入持久化记忆与智能决策能力
  • ESP32-S2/S3 UF2引导程序损坏修复:从ROM模式到工厂重置全攻略
  • Openclaw-Connector:构建高可靠数据集成管道的核心架构与实战
  • OpenClaw客服技能库实战:身份验证、工单管理与知识库增强
  • 测试妹子让我写单测,我偷偷用AI一天干完一周的活
  • IT运维管理体系建设之事件管理流程手册
  • macOS WPS格式兼容性解决方案:从Markdown到PDF的稳健工作流
  • 基于MCP协议构建Rust文档查询服务器:连接AI编程助手与docs.rs
  • Linux防火墙与网络安全配置
  • Network-AI框架:构建智能网络自动化运维平台的核心架构与实践
  • Sora 2正式版到底强在哪?——基于237个Prompt压力测试的9维能力矩阵评分(附可复用提示词模板)
  • 粒子加速器中堆积效应原理与优化策略
  • 5分钟快速上手QQ群数据采集开源工具:新手友好的自动化解决方案
  • 安达发|铝型材行业数字化转型:APS生产排产如何破解排产难题?
  • 开源vs闭源,中文场景实测差距达3.7倍!2026年高保真语音合成工具横向对比,含RTF、WER、抗噪鲁棒性原始数据
  • 如何解决国内GitHub访问龟速的痛点?Fast-GitHub插件深度体验指南
  • MineContext:基于图计算与机器学习的代码上下文智能挖掘实践
  • 你的数字保险箱钥匙丢了?别慌!ArchivePasswordTestTool帮你轻松找回
  • 5月15日直播丨CANNBot进阶开发-自动生成Vector算子之RegBase
  • LangChain:从RAG到智能体,构建下一代AI应用的工程化框架
  • 2026年5月更新:不锈钢堵头实力厂家宁波泰戈油塞联系方式与口碑解析 - 2026年企业推荐榜
  • 安达发|模具行业APS生产排程:破解生产痛点,赋能精益智造
  • 开源业财一体化系统fscl:微服务架构下的财务与供应链协同实践
  • Go语言SIP协议栈sipher实战:从原理到高并发音视频通信开发