前几篇我们学会了发请求、提取数据。但你发现没有——数据抓到了,可都在 Python 变量里。程序一结束,就什么都没了。
这一篇解决两件事:
- 把抓下来的数据存进 CSV 文件(Excel 能直接打开)
- 用循环翻页,一次抓好几页的数据
CSV 是什么?
一句话:CSV 是用逗号分隔的纯文本文件,Excel 能直接打开,兼容性最好。
书名,作者,价格 Python入门,张三,39.9 数据分析,李四,49.9每行一条数据,每列之间用逗号隔开。Python 自带的csv模块就能读写,不用装额外东西。
方法一:Python 内置 csv 模块写入
基本写法
importcsvwithopen('books.csv','w',encoding='utf-8-sig',newline='')asf:writer=csv.writer(f)# 写表头writer.writerow(['书名','作者','价格'])# 写数据行writer.writerow(['Python入门教程','张三',39.9])writer.writerow(['数据分析实战','李四',49.9])两个必须注意的参数(新手踩坑重灾区)
1.encoding='utf-8-sig'—— 解决 Excel 中文乱码
用utf-8存,记事本打开没问题,但 Excel 打开中文全乱码。因为 Excel 默认用 GBK 编码打开 CSV。
utf-8-sig会在文件开头加个 BOM 标记,Excel 看到就知道"这是 UTF-8",正常显示中文。
记住:存 CSV 给 Excel 用,编码一定写utf-8-sig。
2.newline=''—— 解决空行问题
不加的话,在 Windows 上用 Excel 打开会发现每两行之间多一个空行。加上newline=''就好。
方法二:pandas 存 CSV(更简单)
如果你装了 pandas(后面数据分析肯定要用),还能更简单:
importpandasaspd# 数据装成字典列表data=[{'书名':'Python入门教程','作者':'张三','价格':39.9},{'书名':'数据分析实战','作者':'李四','价格':49.9},]# 转成 DataFrame,存 CSVdf=pd.DataFrame(data)df.to_csv('books_pandas.csv',encoding='utf-8-sig',index=False)三行搞定。index=False是不让 pandas 把索引列(0、1、2…)也存进去。
两种方法怎么选?
| 情况 | 推荐 |
|---|---|
| 数据量小、想少依赖 | csv 模块 |
| 数据量大、后面还要分析 | pandas |
| 数据已经是字典列表 | pandas |
| 边抓边写 | csv 模块 |
翻页抓取:从 1 页到 N 页
真实场景里,数据很少只在一页上。排行榜 10 页、搜索结果 50 页,总不能手动改 URL。
怎么找分页规律?
打开有分页的网页,点"第2页",看地址栏:
第1页:https://example.com/ranking?page=1 第2页:https://example.com/ranking?page=2 第3页:https://example.com/ranking?page=3规律很明显——page=后面的数字就是页码。有的网站用p=、pageNum=,思路都一样:找到 URL 里变化的数字,用循环变量替换它。
基本写法
importrequestsfrombs4importBeautifulSoupforpageinrange(1,4):# 抓第1到第3页url=f'https://example.com/ranking?page={page}'print(f'正在抓取第{page}页')response=requests.get(url)soup=BeautifulSoup(response.text,'lxml')# ... 提取数据的代码 ...就一个for循环,把页码当变量拼进 URL。搞定。
完整实战:抓 3 页排行榜存进 CSV
把所有知识串起来,来一个完整的:
importcsvimporttimeimportrequestsfrombs4importBeautifulSoup 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'}all_data=[]forpageinrange(1,4):# 抓 3 页url=f'https://example.com/ranking?page={page}'print(f'正在抓取第{page}页...')response=requests.get(url,headers=headers)ifresponse.status_code!=200:print(f'第{page}页请求失败,状态码:{response.status_code}')continuesoup=BeautifulSoup(response.text,'lxml')# 提取数据(根据实际网页结构调整选择器)items=soup.select('.ranking-item')foriteminitems:rank=item.select_one('.rank').get_text(strip=True)title=item.select_one('.title').get_text(strip=True)score=item.select_one('.score').get_text(strip=True)all_data.append({'排名':rank,'标题':title,'分数':score})print(f'第{page}页抓了{len(items)}条')time.sleep(1)# 每抓一页歇1秒,别太快# 全部抓完,存进 CSVwithopen('ranking.csv','w',encoding='utf-8-sig',newline='')asf:writer=csv.DictWriter(f,fieldnames=['排名','标题','分数'])writer.writeheader()# 写表头writer.writerows(all_data)# 批量写所有数据print(f'全部搞定!共存了{len(all_data)}条数据到 ranking.csv')三个关键点
1.csv.DictWriter:数据是字典列表时用它,按字段名写入,不用操心列顺序。
2.time.sleep(1):每抓一页歇 1 秒。请求太快对方服务器压力大,可能封你 IP。既礼貌,也自保。
3.status_code != 200判断:某一页失败了就跳过,不至于整个程序崩掉。数据采集,容错很重要。
真实运行效果
上面这套流程,用配套资源包在真实站点 books.toscrape.com 上跑一遍,抓前 3 页:
每页 20 本,3 页共 60 本书,全部抓完存进data/books.csv,前 5 本预览正常。翻页、容错、休眠、写入 CSV 全链路跑通。
新手常见坑
| 坑 | 症状 | 解决 |
|---|---|---|
| Excel 中文乱码 | 记事本正常,Excel 乱码 | encoding='utf-8-sig' |
| 每行之间空行 | Excel 打开多空行 | open 加newline='' |
| 字段里有逗号 | 担心列错位 | 用 csv 模块,自动加引号处理 |
数据里有逗号完全不用怕——csv 模块会自动给含逗号的字段加双引号,读取时再自动去掉。所以别自己手动拼字符串,用 csv 模块就对了。
今天的重点回顾
- CSV 是逗号分隔的纯文本文件,Excel 直接打开
- csv 模块是 Python 自带的,
writer.writerow()一行一行写 - 编码一定写
utf-8-sig,不然 Excel 中文乱码 - open 加
newline='',防止空行 - pandas 存 CSV 更简单:字典列表 → DataFrame →
to_csv - 翻页用 for 循环,找到 URL 里的页码变量,循环替换
- 加
time.sleep()休眠,别请求太快被封
到这一步,你已经能独立完成一个完整的小型数据采集项目:发请求 → 解析提取 → 翻页 → 存 CSV。
完整可跑工程版(真实站点 books.toscrape.com 抓前3页60本书存CSV)在配套资源包里。
下一篇讲工程化完善——超时、重试、异常捕获,把爬虫从"能跑"变成"耐造"。
梅雅达编程工作室 · Python数据实战系列第4篇
能抓能存,你已经能独立跑通一个小型采集项目了。别小看这一步,很多人学很久都做不到。