news 2026/10/23 23:03:09

Python爬虫实战:从网页请求到数据存储的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python爬虫实战:从网页请求到数据存储的完整指南

做爬虫这件事,最初往往源于一句很朴素的抱怨:“这网站上明明有我要的数据,为什么不能直接复制下来?”我第一次写Python爬虫,就是帮朋友整理一个行业网站上的商品价格信息,手动复制粘贴到第两百条的时候,眼睛都快花了。后来花了一个下午写了个脚本,十分钟就把三千多条数据整整齐齐地存进了表格里。从那一刻我意识到,所谓“用Python爬取想要的网页信息”,本质上就是把自己从重复劳动里解放出来的过程。

我见过很多人把爬虫想得很玄,觉得要懂一堆底层协议、浏览器内核,其实大部分日常需求根本用不上那么深。你只需要搞清楚三件事:怎么把网页请求回来,怎么把网页里有用的内容挑出来,怎么把挑出来的内容存好。Python在这条链路里有非常成熟的工具链,只要按部就班地走一遍,一个能用的爬虫脚本大概率能在半天内跑起来。这篇文章就从我实际做项目的角度,把整个过程拆开揉碎讲一遍,内容包括工具选型、请求写法、解析技巧、数据清洗、常见坑的排查,以及我自己反复踩过的几个雷。不管你是刚接触Python的小白,还是已经有基础想系统梳理一下,这篇文章应该都能给你一些能直接上手的参考。

1. 动手前先想清楚:爬虫项目的第一步是需求拆解

很多人拿到一个爬虫需求就急着写代码,结果写一半发现目标页面的数据是动态加载的,或者目标数据散落在好几个页面里,又或者根本不需要写爬虫,网站自己就提供了导出功能。所以我习惯先把需求拆清楚,这比选什么工具都重要。

1.1 明确目标数据:你要抓的到底是什么

说白了,你得先回答这几个问题:

  • 目标网站是哪个?页面结构大概什么样?
  • 要抓的数据字段有哪些?比如价格、标题、发布时间、评论数。
  • 数据量有多大?是几十条、几千条、还是每天要持续抓几万条?
  • 抓取频率是多少?一次性跑完,还是需要定时增量更新?
  • 数据最终存到哪里?Excel、CSV、数据库,还是直接推到API接口?

别小看这些问题。有一次我接了个需求,对方说要抓某论坛的帖子标题,我按常规写了列表页遍历,结果跑起来发现他想要的其实是帖子里某个隐藏板块的附件链接,整个页面结构完全不一样,等于返工。后来我养成了习惯:先手动打开目标页面,用浏览器开发者工具看一下数据长在哪里,再动手写代码。这一步花不了几分钟,但能省下后面大半天的调试时间。

1.2 协议与合规:抓取边界先摸清楚

每次讲爬虫我都必须提一句合规。虽然本文是技术分享,但边界得先说清楚:不抓取个人隐私数据、不抓取需要登录才能访问的非公开数据、不绕过网站的技术访问控制。你可以查看目标网站的robots.txt,里面会告诉你哪些路径允许爬虫访问。虽然robots.txt没有法律强制力,但尊重它是行业里的基本礼貌。

实际操作中我一般这么判断:如果能通过浏览器直接看到的数据,正常的、低频率的抓取通常问题不大;但如果数据需要通过账号登录后才能看,或者网站明确有付费墙,那就别碰。另外,抓下来的数据如果涉及个人可识别信息,记得做脱敏处理,别原样入库。这些都是从业者应该有的自觉。

1.3 工具选型:requests + BeautifulSoup 还是 Scrapy 还是 Selenium

Python爬虫生态里,工具选型是第一步,选错了后面会很难受。我按自己的使用经验做个对比:

方案适用场景优点缺点
requests + BeautifulSoup静态页面、中小规模抓取轻量、上手快、依赖少面对动态页面无能为力
Scrapy大规模、多页面、需要并发抓取框架化、扩展性强、自带去重和调度学习曲线陡,项目结构比脚本复杂
Selenium动态渲染页面、需要模拟点击所见即所得,几乎能操作任何页面慢、吃内存、需要维护浏览器驱动
Playwright动态渲染页面、自动化操作比Selenium快,支持多浏览器同样有环境依赖,需要装浏览器内核
requests-html轻量动态页面API友好,支持JavaScript渲染底层封装较重,出问题排查难

我的选择逻辑很直接:能静态抓就静态抓,一个requests就搞定的事没必要上Scrapy。只有遇到需要渲染JavaScript的页面时,我才会考虑Selenium或者Playwright。Scrapy适合那种需要长期跑、数据量达到几十万上百万、还要做增量采集的项目,普通的个人小项目用它反而有点杀鸡用牛刀。

2. 环境准备与基础请求:让脚本先学会“打开网页”

工具链选好之后,第一件事是把环境搭起来。Python版本建议直接上3.10以上,现在新项目真的没必要再考虑2.x了。虚拟环境这个东西,我一开始觉得麻烦,后来被依赖冲突教育过几次之后,发现真香。

2.1 环境准备与依赖安装

创建一个项目目录,然后建虚拟环境:

mkdir my_spider cd my_spider python3 -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate

虚拟环境的好处是会为当前项目隔离出一套独立的第三方库环境,不同项目之间互不污染。我见过太多“在我电脑上能跑”的惨案,就是因为全局环境里装了一堆不同版本的库,换台机器就崩了。

接下来安装核心依赖:

pip install requests beautifulsoup4 lxml pandas

requests用来发HTTP请求,beautifulsoup4用来解析HTML,lxml是指定的解析器引擎,比Python内置的html.parser快得多,pandas用来做数据清洗和存储。这几个组合足够应付绝大多数静态页面的抓取场景了。

2.2 requests 的基本用法:从GET开始

请求一个页面的最小代码是这样的:

import requests url = "https://example.com/list.html" resp = requests.get(url, timeout=10) print(resp.status_code) print(resp.text[:500])

这里有几个细节需要说明。timeout参数很重要,我见过很多新手不设置这个参数,结果目标网站响应慢的时候,脚本就一直挂在那里,看起来像是卡死了。设置一个合理的超时时间(我一般设10秒),至少能让脚本在出错的时候快速失败,而不是无限等待。

其次,拿到响应之后先看status_code,如果是200就继续往下走,如果是404、403或者500,你就要停下来排查了,而不是盲目地往解析器里扔数据。

2.3 请求头与反爬初步:别裸奔

第一次用requests跑某个站点的时候,我收到过403 Forbidden。原因很简单,就是没有设置User-Agent。网站一看这个请求连浏览器标识都没有,直接当成非浏览器请求给拒了。

所以只要写爬虫,我几乎都会带上一些常见的请求头:

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": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", } resp = requests.get(url, headers=headers, timeout=10)

User-Agent可以从自己浏览器的开发者工具里复制,不同网站的检测策略不一样,有些还会检查Referer、Accept-Language这些字段。我通常的做法是先用浏览器打开目标页面,看看Network面板里实际发出的请求头是什么样的,然后把关键的几个字段复制到代码里。这样写出来的请求和浏览器发出来的请求长得几乎一样,能少很多麻烦。

另外,很多网站对请求频率很敏感。如果你一口气发几十个请求,对方可能直接把你的IP封了。我在代码里习惯用time.sleep控制请求间隔,比如:

import time from random import uniform # 每次请求后随机休眠1到3秒,模拟人类浏览节奏 time.sleep(uniform(1, 3))

这样做的目的不是“做贼心虚”,而是降低对目标服务器的压力,避免给对方造成不必要的负担。很多爬虫被拉黑,不是技术问题,是礼貌问题。

3. 页面解析与数据提取:从HTML中“抠”出真正有用的信息

请求拿到HTML之后,下一步就是解析。这一步做得不好,后面全白搭。我从第一次写爬虫到现在,用过正则、BeautifulSoup、XPath、甚至手写字符串查找函数,一路走过来,现在90%的静态页面我都用BeautifulSoup解决。

3.1 BeautifulSoup 定位与选择器

BeautifulSoup的核心用法是定位节点。拿到一个HTML文档之后,你可以先用find或者find_all来找标签,但更高效的方式是用CSS选择器。

比如你想抓一个列表页里所有商品的标题和价格,HTML结构可能是这样的:

<ul class="product-list"> <li class="product-item"> <h2 class="title">商品A</h2> <span class="price">99.00</span> </li> <li class="product-item"> <h2 class="title">商品B</h2> <span class="price">129.00</span> </li> </ul>

对应代码:

from bs4 import BeautifulSoup soup = BeautifulSoup(resp.text, "lxml") items = soup.select("ul.product-list li.product-item") for item in items: title = item.select_one("h2.title").text.strip() price = item.select_one("span.price").text.strip() print(title, price)

select_one只返回第一个匹配结果,select返回所有匹配结果,这个要分清。我见过有人用select_one拿所有列表项,结果只拿到第一条,愣是在那儿debug了半天。

3.2 正则与XPath对比

正则适合什么样的场景?比如你想从一段JavaScript代码里抠出某个变量,或者某个数据是嵌在一个很长的文本串里,有明显的格式特征。但我不推荐用正则去解析HTML本身,因为HTML的标签结构会有各种嵌套和属性顺序变化,正则表达式写起来会越来越复杂,最后变成一坨只有自己能看懂的“神秘代码”。

XPath是另一种定位方式,主要用在lxml里。它比CSS选择器更灵活,功能也更强大,尤其是在处理“按文本内容定位”“按元素位置定位”的时候,写起来比CSS选择器直观。比如:

from lxml import html tree = html.fromstring(resp.text) titles = tree.xpath('//h2[@class="title"]/text()')

如果你对CSS选择器更熟悉,就用CSS;如果你更适应XPath的写法,那就用XPath。工具无高下,顺手就行。我个人的建议是,新手优先掌握BeautifulSoup的CSS选择器,因为它最贴近日常的HTML理解方式,等熟练之后再去学XPath做补充也不迟。

3.3 数据清洗与结构化存储

解析出原始字符串之后,往往还要做清洗。网页里的文本经常带着多余的空白、换行、制表符,价格字段可能带特殊符号,还有一些字段可能为空。我的习惯是每一步都写成函数,这样既方便测试,也方便复用。

比如清洗价格:

def parse_price(raw): # 把价格字符串中的非数字字符去掉,只保留小数点和数字 cleaned = re.sub(r"[^\d.]", "", raw) if not cleaned: return None return float(cleaned)

而数据存储,我一般分两种。数据量小、结构简单的,直接存CSV;数据量大、需要频繁查询的,存SQLite或者MySQL。存CSV用pandas一行就行:

import pandas as pd data = [ {"title": "商品A", "price": 99.0}, {"title": "商品B", "price": 129.0}, ] df = pd.DataFrame(data) df.to_csv("products.csv", index=False, encoding="utf-8-sig")

这里有个细节:编码字段我用的是utf-8-sig而不是utf-8。因为Excel在打开CSV的时候,默认按GBK编码解析,不带BOM的UTF-8文件会被识别成乱码。加了个BOM头之后,Excel就能正确识别了。这个坑我踩过一次之后,所有CSV都会加上这个参数。

3.4 动态加载页面的处理思路

静态页面毕竟只是多数网站的一部分,很多现代网站的数据是通过JavaScript动态渲染的。你requests拿回来的HTML源码里可能只有一个空壳框架,真正的数据是通过额外的接口请求加载的。

遇到这种情况,我一般按优先级尝试这么几个方案:

  • 先用开发者工具打开页面的Network面板,看看页面加载过程中有没有XHR请求返回JSON数据。如果有,直接请求那个JSON接口,解析JSON比解析HTML省事一万倍。
  • 如果接口被加了复杂签名,可以考虑直接模拟浏览器渲染,上Playwright或者Selenium。
  • 最后一个备选方案是看页面里有不有内嵌的JSON数据(比如
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 1:50:06

手写Roberts/Prewitt/Sobel边缘检测算法原理与工业实践

1. 为什么今天还要手写边缘检测算法&#xff1f;——从OpenCV封装背后看图像轮廓提取的本质很多人看到这个标题第一反应是&#xff1a;“OpenCV里cv2.Canny()一行就搞定&#xff0c;谁还去碰Roberts、Prewitt、Sobel这些‘老古董’&#xff1f;”我最初也这么想。直到去年在某高…

作者头像 李华
网站建设 2026/10/22 14:29:50

浙江一位初中英语老师用小程序带班的三个月

去年秋天&#xff0c;绍兴一所初中的英语老师陈老师&#xff08;化名&#xff09;发现一个怪现象&#xff1a;班里四十多个孩子&#xff0c;每天早读都在背单词&#xff0c;但听写正确率始终在六成上下打转。她翻看几个学生的单词本&#xff0c;发现大家习惯从A开始抄写&#x…

作者头像 李华
网站建设 2026/10/23 4:02:40

基于YOLO的八类动物多目标检测:从数据转换到TTA推理全流程实战

简介&#xff1a;这是一份面向目标检测学习者的YOLO系列算法动物数据集&#xff0c;覆盖猴子、大象、猪、牛、鹿、熊、棕熊、老虎等类别&#xff0c;适合用于模型训练、验证与算法对比实验&#xff0c;尤其适合正在入门或进阶YOLO目标检测的开发者。压缩包共2000个文件&#xf…

作者头像 李华
网站建设 2026/10/23 15:14:19

高能物理CMSSW框架实战:从事件模型到模块化流水线

简介&#xff1a;CMSSW&#xff08;Compact Muon Solenoid Software&#xff09;是欧洲核子研究组织CMS实验的离线数据分析软件框架&#xff0c;面向粒子物理研究者、数据分析工程师及开源社区开发者&#xff0c;用于处理高能质子碰撞产生的海量探测器数据。该框架以cmsRun可执…

作者头像 李华