Python 爬虫实战:分页循环爬取科普资讯基础实现方案
前言资讯类站点的数据存储普遍采用分页布局架构单页接口仅返回固定条数资讯内容全量数据分散在 page1、page2……pageN 多页资源中单次请求无法完成全站资讯归集分页循环遍历是爬虫规模化采集科普资讯的必备开发逻辑。在前两篇 UA 伪装、JSON 解析落地 CSV 的技术底座之上本章整合已有请求封装、数据清洗、CSV 增量存储能力围绕分页参数规律探测、循环终止条件判定、页码步进控制、异常分页容错四大核心要点搭建完整分页爬虫架构适配参数为页码型、偏移量型两类主流分页接口实现科普资讯从多页拉取、字段预处理到本地 CSV 自动归档全链路自动化运行。本文涉及核心开发资源超链接如下requests 官方开发文档分页接口循环请求依赖库复用请求头伪装配置Python 内置 csv 模块官方文档多批次资讯数据增量写入本地文件Python 异常处理语法参考文档分页请求异常捕获、断点续爬逻辑开发参考HTTP 请求参数规范 RFC 文档URL 拼接与 Query 分页参数编码规范。一、分页接口底层原理与分类1.1 分页接口实现逻辑后端分页本质依托 SQL 语句的 limit 与 offset 语法实现数据切片前端通过 URL 携带分页参数告知数据库截取数据区间服务器按照参数筛选对应数据集后封装 JSON 返回客户端。爬虫分页开发的核心就是通过程序自动修改分页参数循环遍历每一个数据分片直至无新数据返回时结束循环。科普资讯站点主流分页分为两类不同分页结构对应不同循环编码逻辑。1.2 两大主流分页类型说明表格分页类型参数特征URL 示例循环规则页码分页page 为页码size 为单页条数参数为正整数自增https://api.xxx.com/news?page1size20page 从 1 开始逐次 1 循环偏移分页offset 为数据起始下标limit 为条数https://api.xxx.com/news?offset0limit20offset 每次自增等于 limit 数值绝大多数中小型科普资讯网站采用页码分页也是本章主力实现方案偏移分页多用于大型内容平台文末附带拓展适配代码。1.3 分页爬虫前置必备能力UA 请求头伪装规避单页高频循环访问触发基础 UA 拦截JSON 字段解析与清洗提取标题、发布时间、分类、阅读量等科普关键字段CSV 增量写入每爬完一页即时落盘数据防止程序意外中断造成数据丢失循环终止判断识别空数据页、超出最大页码自动跳出循环结束爬虫。二、基础版页码分页爬虫实现单参数 page 自增2.1 整体开发思路定义基础接口域名、单页条数、起始页码、存储 CSV 文件名、固定表头构造循环结构page 初始值为 1每次循环完成后页码自增 1循环体内拼接带分页参数的完整请求 URL携带伪装请求头发起接口调用解析返回 JSON提取资讯列表空列表代表无后续数据终止循环对单页数据做字段清洗处理调用 CSV 追加写入方法落地数据增加单次请求异常捕获单页爬取失败跳过当前页码继续下一页面。2.2 基础完整可运行代码python运行import requests import csv import os # 全局爬虫配置项 BASE_API https://api.kepu.com/article/list SAVE_FILE 科普资讯全量数据.csv PAGE_SIZE 15 # 单页接口返回资讯条数 START_PAGE 1 # 固定存储字段表头 CSV_HEAD [id, title, category, publish_date, author, read_num] # 通用伪装请求头 HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept: application/json;charsetutf-8 } def clean_data_field(raw_val): 复用前文字段清洗规则处理空值与特殊符号 if raw_val is None or str(raw_val).strip() : return 暂无信息 res str(raw_val).replace(\n, ).replace(,, ) return res def save_batch_csv(file_path, page_data, header): 单页数据增量追加写入CSV file_exists os.path.exists(file_path) with open(file_path, a, encodingutf-8-sig, newline) as f: writer csv.DictWriter(f, fieldnamesheader) if not file_exists: writer.writeheader() writer.writerows(page_data) def get_single_page_data(page_num): 根据页码获取单页清洗后资讯列表 params { page: page_num, size: PAGE_SIZE } try: resp requests.get(BASE_API, paramsparams, headersHEADERS, timeout12) resp.raise_for_status() json_data resp.json() item_list json_data.get(data, []) clean_list [] # 逐条筛选目标字段并清洗 for item in item_list: temp_dict {} for field in CSV_HEAD: temp_dict[field] clean_data_field(item.get(field)) clean_list.append(temp_dict) return clean_list except Exception as e: print(f第{page_num}页请求异常{str(e)}) return None if __name__ __main__: current_page START_PAGE while True: print(f正在爬取第{current_page}页科普资讯...) page_result get_single_page_data(current_page) # 返回None代表当前页请求出错跳过本页 if page_result is None: current_page 1 continue # 空列表表示无剩余数据终止分页循环 if len(page_result) 0: print(已到达最后一页分页爬虫结束) break # 落地当前页数据 save_batch_csv(SAVE_FILE, page_result, CSV_HEAD) print(f第{current_page}页入库成功共计{len(page_result)}条资讯) # 页码自增进入下一轮循环 current_page 12.3 代码分层原理详解参数自动拼接逻辑requests.get 的 params 入参自动完成 URL Query 参数拼接自动处理特殊字符转义替代手动字符串拼接 URL规避参数编码错误、拼接遗漏 符号等低级 bug是分页参数构造标准写法。循环终止核心逻辑len(page_result) 0是页码分页最常用终止条件后端在超出最大页码时返回空数组程序检测空列表后执行 break 跳出 while 死循环结束全量爬取。单页异常隔离设计单页网络波动、接口临时限流仅返回 None程序跳过当前页码直接 1 进入下一页不会因为单页故障直接终止整体爬虫提升爬虫容错性。边爬边存设计每完成一页数据解析立刻执行 CSV 追加区别于全页数据存入内存最后一次性写入海量分页场景下大幅降低内存占用避免内存溢出程序崩溃。清洗函数复用沿用 JSON 转 CSV 章节字段清洗规则统一全项目数据规范保证 CSV 文件格式统一、无单元格错位乱码问题。2.4 基础版分页爬虫优缺点表格优势现存短板逻辑直观页码自增规则简单新手易调试修改无最大页码上限限制异常接口无限返回非空数据会出现死循环单页独立请求、即时落地内存占用可控未配置请求延时短时间高频循环访问极易触发站点 IP 封禁异常单页跳过容错能力满足小型资讯站采集缺少断点续爬程序中途关闭需要从 page1 从头重爬三、进阶优化版分页爬虫上限页码 延时休眠 空页容错3.1 优化升级方向针对基础版死循环、高频访问被拦截问题新增三项关键优化第一配置最大爬取页码作为循环兜底终止条件第二引入 time.sleep () 单页请求延时模拟人工浏览间隔第三增加连续空页计数连续多页无数据提前结束爬虫适配后端页码异常跳空场景。3.2 进阶完整代码实现python运行import requests import csv import os import time # 优化后全局配置 BASE_API https://api.kepu.com/article/list SAVE_FILE 科普资讯优化版数据.csv PAGE_SIZE 15 START_PAGE 1 MAX_PAGE 200 # 兜底最大页码防止死循环 SLEEP_SECOND 1.2 # 每页爬取后休眠秒数 EMPTY_LIMIT 3 # 连续空页阈值连续3页无数据直接结束 CSV_HEAD [id, title, category, publish_date, author, read_num] HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36, Accept: application/json } def clean_data_field(raw_val): if raw_val is None or str(raw_val).strip() : return 暂无信息 return str(raw_val).replace(\n, ).replace(,, ) def save_batch_csv(file_path, page_data, header): file_exists os.path.exists(file_path) with open(file_path, a, encodingutf-8-sig, newline) as f: writer csv.DictWriter(f, fieldnamesheader) if not file_exists: writer.writeheader() writer.writerows(page_data) def get_single_page_data(page_num): params {page: page_num, size: PAGE_SIZE} try: resp requests.get(BASE_API, paramsparams, headersHEADERS, timeout12) resp.raise_for_status() json_data resp.json() item_list json_data.get(data, []) clean_list [] for item in item_list: temp_dict {k: clean_data_field(item.get(k)) for k in CSV_HEAD} clean_list.append(temp_dict) return clean_list except Exception as e: print(f第{page_num}页访问异常{e}) return None if __name__ __main__: current_page START_PAGE empty_count 0 # 连续空页计数器 while current_page MAX_PAGE: print(f开始采集第{current_page}页资讯) page_data get_single_page_data(current_page) if page_data is None: empty_count 1 current_page 1 time.sleep(SLEEP_SECOND) continue if len(page_data) 0: empty_count 1 print(f第{current_page}页无数据连续空页计数{empty_count}/{EMPTY_LIMIT}) # 连续空页达到阈值直接退出 if empty_count EMPTY_LIMIT: print(连续多页无数据爬虫提前终止) break else: empty_count 0 # 正常获取数据清空空页计数器 save_batch_csv(SAVE_FILE, page_data, CSV_HEAD) print(f第{current_page}页保存完成条数{len(page_data)}) current_page 1 # 每页请求后休眠放缓访问频率 time.sleep(SLEEP_SECOND) print(f爬虫执行完毕终止页码{current_page-1})3.3 进阶优化原理剖析最大页码兜底机制while 循环增加current_page MAX_PAGE判断即便接口异常永远返回非空数据爬虫到达设定上限页码自动退出从根源杜绝无限死循环。延时休眠防封禁原理time.sleep () 使程序每次单页爬取完成后暂停指定秒数拉长接口访问时间间隔模拟自然人打开网页的浏览间隙大幅降低站点风控识别为爬虫的概率延时参数在下一章做精细化优化拓展。连续空页计数器部分资讯站点后端页码错乱中间页码空数据、后续页码重新出现内容单次空页不终止连续空页达到设定阈值后结束兼顾异常页码与正常末尾无数据两种场景。空页计数器重置逻辑正常抓取到数据时清空 empty_count保证计数器仅记录连续空白页码计数逻辑精准。3.4 偏移量分页快速适配代码针对 offsetlimit 分页结构仅需修改参数构造与步进逻辑替换 get_single_page_data 内 params 代码python运行# offset分页初始偏移量0每次自增等于单页条数 offset 0 LIMIT_NUM 20 params {offset: offset, limit: LIMIT_NUM} offset LIMIT_NUM四、工程化分页爬虫工具类封装4.1 通用分页爬虫类代码python运行import requests, csv, os, time class PageNewsSpider: def __init__(self, api_url, save_path, header_list, page_size20, max_page100, sleep_time1): self.api api_url self.save_path save_path self.header header_list self.size page_size self.max_page max_page self.sleep sleep_time self.empty_threshold 3 self.headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36, Accept: application/json } def clean_val(self, val): if val in [None, ]: return 暂无信息 return str(val).replace(\n, ).replace(,, ) def get_page(self, page): params {page: page, size: self.size} try: res requests.get(self.api, paramsparams, headersself.headers, timeout12) res.raise_for_status() raw res.json().get(data, []) clean_arr [{k:self.clean_val(i.get(k)) for k in self.header} for i in raw] return clean_arr except Exception: return None def save_csv(self, data): flag os.path.exists(self.save_path) with open(self.save_path, a, encodingutf-8-sig, newline) as f: w csv.DictWriter(f, self.header) if not flag: w.writeheader() w.writerows(data) def run_spider(self): page 1 empty_cnt 0 while page self.max_page: print(f正在爬取第{page}页) data self.get_page(page) if data is None: empty_cnt 1 page 1 time.sleep(self.sleep) continue if len(data) 0: empty_cnt 1 if empty_cnt self.empty_threshold: print(连续空页爬虫结束) break else: empty_cnt 0 self.save_csv(data) print(f{page}页入库{len(data)}条) page 1 time.sleep(self.sleep) print(全部分页采集完成) # 调用实例 if __name__ __main__: headers_list [id, title, category, publish_date, author, read_num] spider PageNewsSpider(api_url接口地址, save_path科普汇总.csv, header_listheaders_list,page_size15,max_page150,sleep_time1.5) spider.run_spider()4.2 工具类使用价值封装完成后后续更换不同科普资讯站点仅需实例化修改入参复用分页循环、存储、清洗全逻辑实现一套代码适配多资讯站点分页采集模块化结构适配项目迭代。五、分页爬虫高频故障排查清单表格故障现象诱因处理方案所有页码均返回空数据参数名错误page 写成 p、size 写成 limit、接口域名失效抓包核对后端真实参数名称爬虫爬取几页后 403 拒绝访问无延时访问频率过高触发反爬增大 sleep 休眠时间搭配随机 UACSV 文件重复写入多条一模一样数据页码循环重复异常重试重复落盘优化空页判断逻辑失败页码不执行存储部分页面字段缺失报错接口部分资讯字段为空统一字段清洗空值填充逻辑六、章节总结科普资讯分页分为页码分页、偏移分页两大结构页码自增与偏移量步进是两种循环核心逻辑分页爬虫三大终止条件空数据页、连续空页超限、到达预设最大页码三层兜底防止死循环每页休眠延时、边爬边存、单页异常跳过是保障分页爬虫稳定运行三大优化点本章固定延时仅为基础防封方案下一篇专项学习随机延时、分段延时、动态休眠优化方案从代码层面规避短频访问封禁。