Python爬虫必学:接口、JSON与分页实战全解析
很多零基础学Python爬虫的人真正卡住的地方往往不是requests用不熟而是这样一个瞬间网页上明明能看到自己想要的数据可把抓下来的HTML源码翻个底朝天就是搜不到目标文本。我第一次遇到这个情况硬是折腾了一下午最后才弄明白——网页上的内容根本不是藏在HTML里而是浏览器悄悄去请求了一个接口接口返回数据后再由JavaScript渲染到页面上。也是从那一刻起我确认了爬虫入门除了要玩转requests和解析库之外还绕不开三样东西接口、JSON、分页。这篇文章就用最直白的方式把这三件事拆开讲清楚你只要有一点点Python基础跟着读下来问题不大。1. 页面上的数据不在HTML里接口才是真正的数据老家1.1 用开发者工具亲眼看一次数据请求我当时抓的是一个资讯列表页浏览器里能看到文章标题、浏览量、发布时间但requests抓回来的源码里搜文章标题干干净净搜不到。后来按F12打开开发者工具切到Network面板勾选XHR再按F5刷新页面才发现了端倪——页面上每出现一批数据Network里就会多出几个请求名字一般长这样/api/article/list、/api/feed、/query?page1。点开其中一个切到Preview或Response选项卡页面上的文章标题、浏览量全都躺在里面。这就解释清楚了现在的主流网站尤其资讯、电商、社交类页面里的数据大多是前端通过JavaScript向后台接口发起请求拿到JSON之后再动态渲染出来的。requests默认抓到的只是最外层的HTML壳子壳子里没有数据当然什么都搜不到。所以爬虫真正要盯的不是那个给人看的页面URL而是页面背后返回JSON数据的接口URL。1.2 接口的基本构成URL、方法、参数、响应接口这个词翻译成大白话就是两个程序之间约定好的通话方式。你可以把服务器想象成一家餐厅接口就是点餐台。URL是菜单上的菜名编号你想吃什么就对着哪个编号下单请求参数是口味备注比如不要辣打包服务器处理后返回给你的结果就是一份做好的菜而这盘菜在接口世界里通常是JSON格式。从技术角度拆一个HTTP接口由四部分组成URL告诉服务器你要访问哪个资源比如/api/article/list。请求方法最常用的两个是GET和POST。GET一般用来获取数据参数拼在URL问号后面POST一般用来提交数据参数放在请求体里。请求头给服务器看的身份和浏览器环境信息比如User-Agent、Cookie。响应服务器返回的状态码、响应头和响应体。响应体如果是JSONContent-Type通常是application/json。零基础阶段你接触的绝大多数分页列表接口都是GET所以先专注于GET就够了。判断一个URL是网页还是接口最直接的办法就是看响应头import requests resp requests.get(https://jsonplaceholder.typicode.com/posts/1, timeout10) print(resp.headers.get(Content-Type)) print(resp.text)如果输出application/json; charsetutf-8说明这确实是接口返回的是JSON而不是HTML网页。把这段地址直接粘贴到浏览器地址栏里看到的也是一段结构化文本而不是花花绿绿的页面这就是接口URL和网页URL最直观的区别。2. JSON 是接口返回数据的通用语言2.1 为什么接口普遍用JSON而不是别的格式很多人第一次接触JSON都会犯怵觉得这是个新语言。其实JSON全称是JavaScript Object Notation翻译过来叫JavaScript对象表示法它本质上就是一种数据交换格式不是编程语言也不需要你有前端基础才能学。早年接口返回数据用过XML结构严谨但写起来啰嗦一个字段几行标签传输起来又占带宽。后来大家逐渐转向JSON因为它足够轻量结构清晰而且几乎所有编程语言都有现成的解析库。可以这样理解JSON就是搬家用的纸箱箱子外面贴的标签是键箱子里装的东西是值小箱子套大箱子就是嵌套结构。服务器把数据装进JSON这口统一的箱子里客户端负责开箱取货双方没有歧义。2.2 JSON的四种值类型和两种容器结构JSON的全部家当其实就这两类容器、四个基础值对象用花括号{}表示里面是一组一组键值对键必须用双引号包起来比如name: 张三。数组用方括号[]表示里面按顺序放一堆值比如[1, 2, 3]、[a, b]。基础值字符串你好、数字18、3.14、布尔值true/false、空值null。下面是一段典型的接口返回JSON我加了些注释你一眼就能看明白结构{ code: 0, message: success, data: { total: 1499, page_num: 1, page_size: 20, has_more: true, items: [ { id: 101, title: 文章标题, view_count: 234, is_top: false, tag_list: [python, 爬虫] } ] } }最外层是一个对象里面有code、message、data三个键。data的值又是一个对象里面除了几个分页相关字段还有一个items数组数组里每个元素都是一篇文章对象。文章对象里又有title、view_count这些基础值以及tag_list这样一个字符串数组。学会一层层剥开这种嵌套结构就是JSON解析的核心。2.3 JSON语法里最容易犯的错用Python写惯了字典回头写JSON容易踩三个坑。第一键必须用双引号不能用单引号很多新手把Python字典那一套直接搬过来解析就报错第二JSON里不允许写注释也不能有尾逗号最后一个键值对后面多了个逗号就报错第三布尔值必须是true/false小写而不是Python的True/False。遇到解析错误别慌把报错信息里的行号和列号对应到字符串里基本都能定位。临时校验最方便的办法是把JSON粘贴到任意在线JSON校验工具或者直接用Python的json.loads跑一下它会告诉你错在哪一行。写解析代码之前我习惯先把一段真实的返回数据复制到本地格式化好看清楚层级关系再动手这个习惯帮我少踩了很多坑。3. Python 与 JSON 打交道的三种姿势3.1 json.loads 和 json.dumps最基础的转换函数Python内置的json模块是处理JSON的主力零基础先记住两个函数就够了。json.loads()负责把JSON字符串转成Python对象json.dumps()负责把Python对象转成JSON字符串。名字里带s可以理解成string也就是处理的是字符串。import json text {name: 小明, age: 18} data json.loads(text) print(type(data)) # class dict print(data[name]) # 小明 back_to_text json.dumps(data) print(back_to_text)这里有个细节容易被忽略json.dumps()默认会把中文转成\uXXXX这种Unicode转义序列打印出来人看不懂。解决办法是加上ensure_asciiFalse参数back_to_text json.dumps(data, ensure_asciiFalse) print(back_to_text) # {name: 小明, age: 18}如果你解析的是JSON文件而不是字符串那就用json.load()和json.dump()这对函数注意少了个s一个接收文件对象一个写入文件对象。3.2 requests 的 .json() 方法比手动转换更方便用requests发请求接着手动json.loads(resp.text)当然可以但requests自带一个.json()方法它会在内部完成响应内容的解码和转换resp requests.get(https://jsonplaceholder.typicode.com/posts/1, timeout10) data resp.json() print(data[title])一个值得注意的点是.json()只有在响应体确实是合法JSON时才会正常工作如果服务器返回的是HTML错误页或者一段普通文本调用.json()会直接抛异常。建议在解析前先判断状态码resp requests.get(url, timeout10) if resp.status_code 200: data resp.json() else: print(请求失败, resp.status_code)3.3 多层嵌套取值学会之后再考虑用jsonpath刚入门时取嵌套数据最朴素的方式就是一层层索引比如要拿上面示例里第一篇文章的标题代码就是first_title data[data][items][0][title] print(first_title)这段代码就是标准的剥洋葱先取data再取data里的data再取items数组然后取数组第一个元素最后拿title。等嵌套越来越深这个写法会变得很长而且任何一个环节字段名写错就取不到值。这时候可以用jsonpath这个库它像XPath一样用路径表达式定位数据from jsonpath import jsonpath titles jsonpath(data, $.data.items[*].title) print(titles) # [文章标题, ...]$.data.items[*].title的意思是从根节点开始取data下的items数组里的所有元素各自的title。不过我不建议零基础一上来就依赖jsonpath最好先手写几层索引、把Python字典和列表的操作练熟。等哪天真被多层嵌套烦到了再上这个库理解成本会低很多。4. 分页服务器为什么总是一次只给一页4.1 一次性把全量数据塞给你会发生什么假设一个接口背后有100万条数据服务器如果一次性全部返回响应体可能达到几百MB网络传输慢、客户端解析卡、服务器内存和带宽双双告急。即便数据量没这么大很多产品设计也不希望调用方一次性拿到全量数据这样做既难控制风险也不利于统计调用频次。于是分页成了接口设计的默认做法每次只返回一页数据通过参数告诉服务器我要第几页、每页多少条。爬虫新手容易有一个误区拼命想把所有数据一次性拿回来。真实的爬虫恰恰相反要尊重接口的分页规则一页一页拿中间留出合适的间隔这才既稳定又不容易触发限流。4.2 分页参数三种主流形式分页参数没有统一的国际标准但最常见的就三种我用表格给你列清楚分页形式请求参数示例特点常见场景页码分页page2pageSize20直观第2页每页20条返回通常会带total或has_more资讯列表、商品列表、文章列表偏移分页offset40limit20从第40条开始取20条老接口比较多老版本API、后台管理系统游标分页cursorMTU4MjAw服务器返回一个不透明游标下次请求带着它继续社交动态、即时消息、高频更新数据页码分页最好理解适合数据相对稳定的场景。偏移分页有个明显的痛点如果在翻页过程中有人新增或删除了数据后面页的数据会重复或者漏掉因为offset是固定偏移量。游标分页对高频更新最友好服务器用游标记住你上次看到哪了但实现起来略复杂新手先看得懂即可。4.3 返回结果里的分页信息到底怎么看服务器不光返回本页数据通常还会附带分页元信息常见字段有total总记录数比如1499条。page或page_num当前页码。page_size每页条数。has_more是否还有下一页返回true说明继续翻。next_cursor游标分页专用表示下一次请求要带的游标值。也有少数接口不走寻常路不把总数放在响应体里而是放在响应头里比如X-Total-Count。第一次接触某个接口时先花两分钟把返回体完整打出来看看确认到底有哪些分页字段这比闷头写循环重要得多。5. 实战写一个通用分页爬虫把数据全部拉回来5.1 用公开测试接口练手不碰任何有争议的数据学习阶段建议用明确开放、无版权争议的测试接口练手。我这里用的是JSONPlaceholder一个专门给开发者做练习的免费假数据接口地址是https://jsonplaceholder.typicode.com/posts。它支持的参数是_page和_limit分别表示页码和每页条数返回的是文章数据。这个接口稳定、公开用来学分页再合适不过。动手之前先做个三步分析第一步用浏览器打开接口地址观察返回的JSON结构第二步试着在地址栏加上?_page1_limit2看返回条数是不是变成2条第三步关注响应头你会发现里面有个X-Total-Count: 100这就是总记录数。顺便提一句有些接口的总数不在响应体里而在响应头里这是一线开发里很常见的隐蔽坑。5.2 循环翻页直到拿完所有数据先写一个最基础的版本不断把页码加1直到返回的列表为空。为什么用while而不是for因为你一开始不知道总共有多少页而while天然适合翻到没数据为止这种不确定次数的循环。import requests base_url https://jsonplaceholder.typicode.com/posts page 1 limit 20 all_posts [] while True: resp requests.get( base_url, params{_page: page, _limit: limit}, timeout10 ) resp.raise_for_status() data resp.json() if not data: break all_posts.extend(data) total int(resp.headers.get(X-Total-Count, 0)) print(f已抓取第 {page} 页累计 {len(all_posts)} 条) if len(all_posts) total: break page 1 print(f全部完成共 {len(all_posts)} 条数据)代码里有两个终止条件第一个是当前页返回空列表说明服务器那边没有更多数据了第二个是累计条数达到响应头里的X-Total-Count提前结束循环避免多打一次空页。两个条件都写上是稳妥做法因为有些接口在请求超出范围时会返回200加空列表有些则会直接返回非200状态码只依赖一个条件容易漏。5.3 把数据落盘顺手做一次去重抓回来的数据存内存里程序一结束就没了实际使用中要落盘。最省事的方式是直接存成JSON文件import json with open(posts.json, w, encodingutf-8) as f: json.dump(all_posts, f, ensure_asciiFalse, indent2)落盘前顺手做个去重。分页过程中如果有新数据插入同一篇文章可能出现在不同页导致重复。最简单的去重方式是按照id字段建一个集合seen_ids set() unique_posts [] for post in all_posts: if post[id] in seen_ids: continue seen_ids.add(post[id]) unique_posts.append(post)这一步看着简单但真实项目里因为没去重导致数据统计翻倍的例子太多了不值得再踩一遍。6. 分页爬虫最容易翻车的三个细节6.1 接口返回空列表不代表你要的数据已经拿完这是我第一次写分页循环时踩过的坑程序某一次请求返回了200状态码但data是空我当时直接break了后来发现漏了很多数据。排查到最后发现是因为请求频率太高服务器在这一页悄悄返回了空数据但状态码依然是200。正常结束和限流返回空之间光靠状态码判断不出来。正确的做法是如果当前页为空但累计数量还没达到总数或者has_more还是true不要急着结束先降低频率、换个时间再重试一到两次。同时打印进度信息看到累计条数突然不再增长立刻停止排查而不是盲目继续跑。6.2 请求太快接口会直接给你颜色看爬虫最忌讳的就是一股脑高频率请求。一次抓几千页的任务每页间隔0.5到1秒实测下来已经比较稳妥如果你用的是免费公共接口请求间隔要更长别让对方服务因为你的脚本出现压力。代码里加个随机延时很简单import time import random time.sleep(random.uniform(0.3, 0.8))同样的请求头最好通过requests.Session()来发它能复用底层的连接效率更高也不容易被服务器当成异常流量。Session的用法很简单就是创建一个session对象然后把requests.get换成session.get。6.3 爬取任何数据前先想清楚合规边界最后这条压轴。学爬虫练技术和实际去抓一个网站的数据完全是两回事。练习阶段优先使用明确开放的公开接口和官方API如果某个接口没有公开文档也不建议为了获取数据去绕过对方的限制。网上常有爬虫被判的新闻绝大多数问题不是爬虫这个技术本身而是被抓取的对象、获取的数据、使用的方式踩了红线。个人学习阶段我建议坚持三条底线只抓公开可访问的数据尊重网站的robots协议和服务条款拿到的数据只用来自学和分析不传播、不商用。养成这个习惯后面用爬虫做任何事你都不会因为数据来源问题睡不着觉。最后分享一个我自己的习惯凡是官网文档里能查到的API接口我都优先用官方API原因很简单——稳定、省得自己维护解析逻辑、也不会被对方限制。学爬虫真正的核心能力是读懂客户端和服务器之间的通信方式把JSON结构分析和分页逻辑这两个基本功练扎实以后遇到再复杂的接口你只需要几分钟就能摸清它的脾气。

相关新闻

CNN/VGG/ResNet人脸表情识别实战:从数据到部署全流程

CNN/VGG/ResNet人脸表情识别实战:从数据到部署全流程

简介:面向计算机专业毕业设计与深度学习初学者的完整人脸表情识别项目,以卷积神经网络为核心,覆盖数据预处理、模型搭建、训练评估与实时识别演示的完整流程,可直接用于课程作业、论文写作或实战练手。压缩包共36个文件&#xff0…

2026/9/24 21:12:16 阅读更多 →
工厂焊装车间照明节能改造:KNX照明系统方案分区灯控人体感应

工厂焊装车间照明节能改造:KNX照明系统方案分区灯控人体感应

焊装车间是汽车工厂中照明设计最复杂的场景之一。焊接作业时弧光强烈,而检验工位又要求极高照度——两者对灯光的需求完全不同,用同一套照明方案无法兼顾。据《乘用车工厂焊装车间照明节能设计的探讨》一文披露,一汽大众华北生产基地焊装车间…

2026/9/24 21:12:16 阅读更多 →
结构可靠性分析:从安全系数到失效概率的定量评估

结构可靠性分析:从安全系数到失效概率的定量评估

在结构设计里,最怕的不是算不准,而是你以为自己算得很准。刚工作那会儿,我按规范给一根简支梁取了安全系数2.5,所有验算都满足,结果现场反馈说梁在使用荷载下挠度偏大,局部焊缝还有开裂迹象。复核时我反复检…

2026/9/24 21:11:15 阅读更多 →

最新新闻

电路板元器件检测:YOLO小目标漏检与密集框调参实战

电路板元器件检测:YOLO小目标漏检与密集框调参实战

简介:本资源面向从事电子制造质检、PCB缺陷检测及YOLO目标检测实战的开发者与研究人员,提供一套可直接用于训练的电路板元器件图像数据集,覆盖目标检测、小目标检测与密集检测等典型场景。压缩包共约2000个文件,以1660个txt标签、…

2026/9/24 22:03:05 阅读更多 →
单片机基础核心知识点汇总(四十三)

单片机基础核心知识点汇总(四十三)

目录 前言 一、软件定时器的核心本质 1、核心工作原理 2、核心特性 二、定时器服务任务:软件定时器的核心载体 1、服务任务的特点 2、核心影响 三、两种工作模式与核心 API 1、两种定时模式 2、核心 API 1. 创建定时器 2. 启动 / 停止 / 重置 3. 回调函数格式 四…

2026/9/24 22:03:05 阅读更多 →
2009年408真题:Cache组相联映射地址计算三步拆解

2009年408真题:Cache组相联映射地址计算三步拆解

最近在复盘408真题的计组部分时,又把2009年第14题翻了出来。这道题本身只有短短几行字,考的是Cache组相联映射中最基础的一类计算:给定Cache总块数、每组路数和块大小,让你算主存某个字节地址会被装入到Cache的哪一个组。题目不长…

2026/9/24 22:03:05 阅读更多 →
车辆检测数据集实战:从VOC转YOLO到yolov5训练避坑指南

车辆检测数据集实战:从VOC转YOLO到yolov5训练避坑指南

简介:这份资源是面向计算机视觉初学者与目标检测实践者的YOLOv5车辆检测数据集,类别聚焦为car,可用于交通监控、自动驾驶、安全驾驶等场景下的模型训练与验证。压缩包共2000个文件,以1285个txt标签、1284张jpg图像和1284个xml标注…

2026/9/24 22:03:05 阅读更多 →
需求获取方法

需求获取方法

2026/9/24 22:03:05 阅读更多 →
Ekko Studio docx Skill 源码级解析:Word 修订(Tracked Changes)与批注(Comments)的 WordprocessingML 处理

Ekko Studio docx Skill 源码级解析:Word 修订(Tracked Changes)与批注(Comments)的 WordprocessingML 处理

AI 应用人工智能AI Agent本地部署前端后端工作流自动化 【免费下载链接】ekko-studio Ekko Studio is a local-first AI workspace for multi-agent chat, coding, and visual workflows, available on desktop and the web. 项目地址: https://gitcode.com/gh_mirr…

2026/9/24 22:02:05 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →