ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python爬虫零基础入门:从Requests到数据存储完整实战

2026/10/4 14:08:51 拓冰建站 浏览量
Python爬虫零基础入门:从Requests到数据存储完整实战 新手学爬虫最容易踩的坑不是不会写代码而是不知道从哪下手或者抄了一段代码跑不通就直接放弃。这篇文章我想用最直白的方式把 Python 爬虫从零到能自己写小工具的完整路径捋一遍。里面没有故作高深的术语也不会一上来就甩几十个库给你而是围绕一条主线怎么用 Python 把网页上的数据拿下来、洗干净、存起来。这套东西适合完全没接触过爬虫的人也适合写过几段代码但总是一知半解的朋友。你不需要先精通 Python 语法跟着实操走能跑通一个最简单的例子后面再慢慢补基础反而学得更快。我自己就是先会爬后补的编程底子。读完这篇文章你能独立完成一个简单的数据采集任务比如抓取某网站的新闻标题、商品价格、排行榜数据并存成表格文件。更重要的是你会理解爬虫背后的运行逻辑——知道它为什么能工作、哪里容易出问题、怎么排查问题而不是永远停留在“复制别人的代码”阶段。1. 内容整体设计与思路拆解1.1 爬虫到底是什么它的工作流程是怎样的说白了爬虫就是一个能自动访问网页并提取信息的程序。你平时用浏览器打开一个网站看到文字、图片、表格这是浏览器帮你向服务器发请求、接收响应、渲染页面的结果。爬虫做的事和浏览器本质上一样只是它拿到响应之后不去渲染成好看的页面而是从源代码里把你要的数据抠出来。一个完整的爬虫流程拆开来看就四步发送请求向目标网站的 URL 发出 HTTP 请求相当于告诉服务器“我想看这个页面”。获取响应服务器返回 HTML 文档或者 JSON 数据、图片二进制内容。解析内容从返回的数据里定位并提取目标信息。存储数据把提取到的内容保存到 CSV、Excel、数据库或者直接打印出来看。很多人学爬虫时容易被各种术语吓住比如“请求头”“会话”“动态加载”其实这些都是围绕上面四步展开的细节。你把主流程刻在脑子里后面学任何框架、库都是在这四步里做文章。1.2 零基础入门的技术选型为什么选择 requests 解析库组合爬虫领域可选的工具非常多光是发请求就有 requests、httpx、aiohttp解析有 BeautifulSoup、lxml、parsel大型框架有 Scrapy自动化有 Selenium、Playwright。对一个零基础的人来说一上来就学 Scrapy 或者 Playwright 绝对是灾难因为每个框架都有自己的一套概念你会被“中间件”“管道”“选择器”这些词绕晕。我推荐的组合是requests BeautifulSoup lxml理由非常实在requests 是 Python 世界里最简单的 HTTP 库发送请求只需一行代码适合理解请求与响应的本质。BeautifulSoup 解析 HTML 时容错率高语法贴近直觉即使 HTML 写得烂也能解析出来适合新手建立信心。lxml 作为 BeautifulSoup 的解析引擎速度比 Python 内置的 html.parser 快很多。等你用这一套跑通了两三个实战项目再去接触 Scrapy、异步爬虫、浏览器自动化会轻松很多——因为到那时候你已经理解了爬虫的通性学新工具只是在换“包装”而已。1.3 学习路径规划先跑通后理解再优化我给零基础朋友的建议是不要按教科书顺序从 Python 语法第一章往后啃。你只需要掌握最基础的四件事就能开始写爬虫变量和数据类型知道字符串、列表、字典怎么用条件判断和循环for 循环遍历列表是必备技能函数定义把重复操作封装起来异常处理try/except爬虫里太常用了这些基础你花两三天就能掌握然后立刻开始爬虫实战。别的不懂的语法用到什么查什么。这种“以需求驱动学习”的方式效率最高因为每次查到的东西你马上用得上记忆自然深刻。2. 环境准备搭建 Python 开发环境2.1 安装 Python 时容易忽视的细节无论你用 Windows、macOS 还是 Linux安装 Python 本身不是难事但有两个细节直接影响后面的体验。细节一勾选“Add Python to PATH”。Windows 用户在安装 Python 时安装界面第一个勾选框就是它。如果漏掉了你在命令行里输入 python 会提示“不是内部或外部命令”到时候还得手动配置环境变量非常麻烦。细节二区分 Python 2 和 Python 3。现在新项目一律用 Python 3。官网下载时注意版本号3.9、3.10、3.11 都可以不要下载 2.x 版本。在命令行输入python --version可以确认自己安装的版本。安装完成后建议顺手验证一下 pip 是否可用。pip 是 Python 的包管理工具后面安装第三方库都靠它。命令行里输入pip --version能看到版本信息就说明没问题。2.2 使用虚拟环境隔离项目依赖虚拟环境是 Python 开发里非常重要的实践但很多新手根本不知道它的存在。简单说虚拟环境就是为你的项目单独创建一个“小房间”在这个房间里安装的第三方库不会污染全局环境不同项目之间依赖不会打架。创建虚拟环境只需要两步# 在项目目录下创建名为 venv 的虚拟环境 python -m venv venv # 激活虚拟环境 # Windows 系统 venv\Scripts\activate # macOS / Linux 系统 source venv/bin/activate激活后命令行前面会出现(venv)的标识说明你已经进入虚拟环境。之后用 pip 安装的所有包都只会装到这个环境里。刚开始学爬虫可能觉得虚拟环境没必要但当你同时做两三个项目一个需要 requests 2.31另一个需要 requests 2.28你就知道虚拟环境有多香了。我建议从第一个爬虫项目开始就养成这个习惯。2.3 安装 requests、BeautifulSoup4 和 lxml进入虚拟环境后安装三个基础库只需要一行命令pip install requests beautifulsoup4 lxml你可能会听别人说还要装 pandas、numpy 之类的库那是做数据分析阶段的工具。零基础入门爬虫这三个库够你用很久了。验证安装是否成功可以打开 Python 交互式环境依次导入python import requests from bs4 import BeautifulSoup print(环境准备完成)能打印出结果就说明环境搞定了。这个过程看起来简单但值得认真做一遍——我见过太多人代码写好了结果卡在“导入库失败”这一步原因就是库没装进虚拟环境。3. 核心机制解析HTTP 请求与响应的原理3.1 URL、请求头和响应体的关系爬虫本质上是在和 HTTP 协议打交道。你需要在理解层面搞清楚访问一个网址时客户端爬虫和服务器之间到底交换了什么。先说 URL。一个典型的网址像https://example.com/news?id123它分成几个部分协议https、域名example.com、路径/news、查询参数?id123。爬虫的核心工作之一就是学会构造这些 URL——知道哪些参数控制翻页、哪些参数是搜索关键词、哪些参数是用户身份标识。再说请求头Headers。它是你发给服务器的“自我介绍”里面最关键的是User-Agent用来标识客户端的类型和版本。如果你用 requests 默认的请求头去访问网站服务器看到的 UA 是一长串 Python 字符很容易被识别成爬虫。这也是为什么新手写的爬虫容易被封——因为你连“伪装”都没做。响应体就是服务器返回给你的内容。普通网页返回的是 HTML 文档API 接口返回的是 JSON 字符串。HTML 是用尖括号标签包裹的结构化文本你的解析工作就是对它做信息的定位和提取JSON 则更友好直接用 Python 自带的 json 库就能转成字典。3.2 状态码服务器在告诉你什么HTTP 状态码是三位数字新手最需要记住的是三组200请求成功拿到了内容。301/302重定向服务器让你去另一个地址请求。requests 库默认会帮你处理重定向但你最好知道它发生过。403/404/500/502这些通常是负面结果。403 代表服务器拒绝访问很多是反爬策略生效了404 是地址不存在500 和 502 是服务器自己出了问题。在实际爬取中我会先打印状态码确认请求是否成功再进行后续解析。如果返回 403就先别急着改解析代码而是检查请求头、cookies 是否缺失。3.3 会话Session与 cookies保持登录状态的原理有些网站的数据需要登录才能看到这时候就需要用到 Session 和 cookies。你可以把 Session 理解成“保持对话状态的客户端对象”当你用同一个 Session 连续发送多个请求服务器会记住你的身份。用 requests 的 Session 非常直观import requests session requests.Session() # 用 session 登录 session.post(https://example.com/login, data{username: user, password: pass}) # 后续请求都会携带登录状态 resp session.get(https://example.com/dashboard)在写爬虫时我建议只要是需要连续访问多个页面的场景就用 Session 而不是裸的 requests.get()。它不仅能维持 cookies还能统一设置请求头管理起来干净得多。4. 实操核心requests 库的用法与页面解析4.1 第一个爬虫获取网页内容并保存学习任何技能第一步都是跑通一个最简单的例子。下面这段代码是你能写出的最基础的爬虫import requests url https://example.com headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } resp requests.get(url, headersheaders, timeout10) print(resp.status_code) # 输出 200 print(resp.text[:500]) # 打印响应内容的前 500 个字符这段代码做了四件事定义目标 URL、设置请求头、发送 GET 请求、打印内容。我每次给学生讲爬虫都从这段代码开始因为它展示了请求-响应的完整链路又没有一句多余的话。其中两个参数值得解释headers里的 User-Agent 是从真实浏览器复制的目的是让服务器觉得访问来自普通用户。timeout10设置超时时间防止程序因为服务器无响应而永久卡住。跑通这段代码后你可以尝试把resp.text写入本地文件with open(page.html, w, encodingutf-8) as f: f.write(resp.text)保存下来的 HTML 文件可以用浏览器直接打开看看和你访问网站时的差别会有非常直观的感受。4.2 信息提取的三种方式对比正则、BeautifulSoup、XPath拿到 HTML 之后接下来就是“从一堆标签里找数据”的过程。常用方法有三种各有优劣。正则表达式最灵活但也最容易出错。比如提取一个邮箱地址用正则可能一行搞定但 HTML 标签嵌套复杂时写正则就会变成一场灾难。我不建议零基础的人用正则来解析 HTML它的位子是处理字符串而不是解析结构化文档。BeautifulSoup是推荐给新手的首选。它把 HTML 解析成一棵树你可以通过标签名、class、id 来定位元素写法非常自然。比如找一个 class 为 title 的 h1 标签代码是这样from bs4 import BeautifulSoup soup BeautifulSoup(resp.text, lxml) title soup.select_one(h1.title) print(title.text)XPath则更强大的选择器语言尤其适合复杂层级的数据提取。lxml 库支持 XPath定位一个元素可能只需要一句很精炼的表达式。等你处理过几个真正复杂的页面会体会到 XPath 的痛快。这三者的选择没有绝对标准我的习惯是简单页面用 BeautifulSoup复杂页面用 XPath纯文本里的特定格式数据才用正则。新手完全可以从 BeautifulSoup 开始遇到搞不定的再切换。4.3 BeautifulSoup 精讲find、find_all 与 selectBeautifulSoup 的核心方法就三个吃透它们能解决 90% 的解析需求。from bs4 import BeautifulSoup soup BeautifulSoup(html_doc, lxml) # 1. find()找第一个符合条件的元素 first_link soup.find(a) # 2. find_all()找所有符合条件的元素返回列表 all_links soup.find_all(a, class_external) # 3. select()使用 CSS 选择器语法返回列表 titles soup.select(div.article h2)使用 find_all 时要特别注意一个坑class在 Python 里是关键字所以 BeautifulSoup 里要用class_来匹配 class 属性。忘掉下划线会导致代码报错这个细节几乎每个新手都会栽一次。给元素定位时优先使用 id 或 class因为它们通常有明确的语义。比如新闻标题通常藏在h2 classnews-title这样的结构里直接用soup.select(h2.news-title)就能全部抓出来。拿到元素后你还需要三个常用操作element.text获取标签内的纯文本内容。element.get(href)获取标签属性的值比如超链接地址。element.find_next_sibling()找到下一个兄弟节点翻页或列表场景偶尔用得上。4.4 XPath 使用方法从入门到进阶XPath 是一门独立的查询语言在 XML 和 HTML 上都可以用。lxml 库是把 XPath 和 Python 结合得最好的方案。from lxml import html tree html.fromstring(resp.text) # 选取所有 h2 元素并提取文本 titles tree.xpath(//h2/text()) # 选取 class 为 article 的 div 下所有 p 标签 paragraphs tree.xpath(//div[classarticle]//p/text())XPath 的常用符号逻辑如下//从任意位置开始查找。/从当前节点直接选取子节点。.当前节点。..父节点。选取属性比如href、class。text()选取文本。我用 XPath 最频繁的一个场景是翻页列表。比如一个新闻网站从第 1 页到第 50 页的 URL通常只变化一个查询参数。我用 XPath 先提取出“下一页”的链接再循环请求就能自动翻页抓取。要注意一点XPath 的索引从 1 开始不是 Python 习惯的从 0 开始。//div[1]和//div[0]的意思完全不同后者经常匹配到什么都不是。这个细节写错了程序不报错但结果全是空的很容易让人一头雾水。5. 进阶实操动态页面、POST 请求与反爬应对5.1 静态页面和动态页面的区别为什么有的网页你会爬不到东西用 requests 获取到的 HTML 是服务器“初次渲染”的结果。有些网站的数据不是直接写在 HTML 里的而是通过 JavaScript 在浏览器里二次请求 API 后动态渲染出来的。你打开网页能看到内容但 requests 拿到手的 HTML 源文件里根本没有那些数据。怎么判断一个页面是不是动态渲染方法很简单在浏览器里右键查看源代码搜索你看到的文字内容如果源代码里搜不到就是动态加载的。处理动态页面的方案有三类找 API 接口用浏览器的开发者工具里的 Network 面板看页面加载时发了哪些 XHR 请求直接请求 JSON 数据接口。这是最省资源的方式。使用 Playwright/Selenium让真实浏览器去执行 JavaScript模拟用户操作再提取渲染后的内容。缺点是慢且占用资源。分析页面 JS 逻辑用代码去模拟执行关键的数据获取逻辑。这种方式难度较高只适合特定站点。零基础入门的策略是优先找 API实在不行再上浏览器自动化。打开开发者工具切换到 Network 标签刷新页面看哪些请求返回的是 JSON 数据往往比直接解析 HTML 简单得多。5.2 用 Data 参数发送 POST 请求GET 请求是把参数放在 URL 里POST 请求则是把参数放在请求体里。登录、搜索、筛选等操作大多使用 POST。requests 发送 POST 请求只需换一个方法import requests data { keyword: python, page: 1, size: 20 } resp requests.post(https://example.com/api/search, datadata, timeout10) print(resp.json())注意一个细节服务端接口接收的数据格式有的要求datadata普通表单有的要求jsonjson_dataJSON 格式写错了会得到 400 或 415 错误。新手排查这个问题时最容易浪费时间的点就在这里——往往是参数名对、值对只是提交格式不对。5.3 基础反爬应对策略频率控制、请求头伪装、代理轮换爬虫肯定会遇到反爬机制。应对策略按技术难度可以从三个层面入手。第一个层面访问频率控制。这是最基本的礼貌。你的爬虫如果每秒发几十个请求正常网站都会把你封掉。在代码里加一个随机延时显得“像人”import time import random time.sleep(random.uniform(1, 3))第二个层面请求头伪装。除了 User-Agent你还可以对 Referer、Origin 等常见请求头进行补充设置。Referer 表示你从哪个页面跳转过来的有些图片服务器或文件服务器会校验它如果为空就拒绝返回。第三个层面代理 IP 轮换。当你的 IP 因为请求过多被对方封禁就需要使用代理池在每次请求时随机换一个 IP。这部分涉及代理服务器的获取与验证属于进阶内容。我建议新手不要一开始就琢磨反爬。先把自己的请求频率控制好先给对方留下一个“礼貌访问者”的印象。很多网站允许低频爬虫访问却会立刻封锁高频程序这不是技术问题而是使用姿势问题。5.4 登录态模拟Cookie 与 Session 的实践登录后数据的爬取核心就是模拟登录态。有两条实现路径。路径一用 Session 模拟登录流程先 POST 提交账号密码拿到登录后的 cookies再带着这个 Session 去请求目标数据。路径二手动从浏览器开发者工具里取登录后的 Cookie 字符串直接放进请求头里发送。headers { Cookie: sessionidxxx; user_tokenyyyy, User-Agent: Mozilla/5.0 ... } resp requests.get(https://example.com/private-data, headersheaders)路径二的优点是不用处理复杂的登录逻辑缺点是 Cookie 有有效期过期后需要重新手动获取。路径一适合需要长期稳定采集的场景登录成功后 cookies 由程序维护自动续期。我个人的经验是入口路径尽量用 Session 模拟登录遇到验证码或扫码登录这些搞不定的环节再用浏览器的 Cookie 补充方案。两个思路都掌握能覆盖绝大多数网站的登录态需求。5.5 数据存储保存为 CSV 文件数据爬下来不存储等于白干。最通用的存储方式是 CSV 文件Excel 可以直接打开Python 也方便继续处理。import csv rows [ [标题, 链接, 发布时间], [Python 爬虫入门, https://example.com/1, 2025-01-01], [Scrapy 实战, https://example.com/2, 2025-01-02] ] with open(articles.csv, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerows(rows)这里有一个非常关键的细节encoding不能乱写。如果你写的utf-8Excel 打开中文文件时会乱码。正确的做法是utf-8-sig它会让 Excel 正确识别 UTF-8 编码的中文内容。这个坑我踩过无数次每次换新电脑写爬虫都会栽进去一次。如果后续需要更复杂的数据分析也可以存到 pandas 的 DataFrame再导出 Excel。但那是进阶用法零基础阶段先掌握 CSV 就够了。6. 完整实战项目抓取一个新闻列表并保存6.1 项目目标与分析理论知识讲再多不如动手做一个完整项目。这个实战例子我选择了一个在很多教程里最常见、也最适合入门练手的场景抓取新闻网站首页的文章标题、链接和发布时间保存到 CSV 文件。拿到一个爬虫任务后第一步一定不是写代码而是用浏览器打开目标页面按 F12 打开开发者工具仔细看 HTML 结构。你需要搞明白三个问题标题在哪个标签里时间信息在哪个字段里列表和详情页的关系是什么我强烈建议新手在看 HTML 结构上花足够多的时间。你会发现很多爬虫出来的数据不对不是代码写错了而是对网页结构的理解有偏差。6.2 完整代码实现与逐行说明下面用新浪新闻的首页做示例网站结构可能随时调整但思路通用。代码先不做防御先抓下来再说import requests import csv import time from lxml import html BASE_URL https://news.sina.com.cn/ HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } def fetch_news(): resp requests.get(BASE_URL, headersHEADERS, timeout10) if resp.status_code ! 200: print(f请求失败状态码{resp.status_code}) return tree html.fromstring(resp.text) news_list [] # 定位新闻条目的容器 items tree.xpath(//li//a[contains(href, doc)]) for item in items[:30]: # 只取前30条避免过多请求 title item.text.strip() if item.text else link item.get(href, ) if title: news_list.append([title, link]) save_to_csv(news_list) def save_to_csv(news_list): if not news_list: print(没有抓到任何数据) return with open(news.csv, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([标题, 链接]) writer.writerows(news_list) print(f已保存 {len(news_list)} 条新闻到 news.csv) if __name__ __main__: fetch_news()这段代码有几个地方值得展开说明。先看 XPath 表达式的设计思路。//li//a意思是选取所有 li 元素下的 a 标签contains(href, doc)是过滤条件只保留链接中包含 doc 的超链接。这个过滤逻辑是怎么想到的因为在开发者工具里观察时正则新闻链接普遍包含doc字段而广告、推荐位链接不包含它。这种基于链接特征的过滤是爬虫实战里非常常用的技巧。再看item.text.strip()。HTML 里的文本往往带有换行和多余空格必须用 strip() 清理。同时还要判断if item.text——如果 a 标签里嵌套了图片或其他标签.text可能是空字符串或 None不做判断会把空条目也存进去。最后看 timeout 和状态码检查。请求加了 10 秒超时状态码非 200 就打印错误并返回。这套“防御式”写法属于爬虫的基本素养——爬虫是面向网络环境的程序网络是不稳定的必须假设什么都会出错然后优雅地处理错误而不是让程序崩溃。6.3 运行效果与调优运行代码后项目目录下会生成 news.csv 文件。用 Excel 打开能看到两列数据标题和链接。如果发现一条数据都没抓到按优先级排查请求是否真的成功在代码里打印 resp.status_code 确认。页面结构是否改版重新检查 XPath 表达式可以在浏览器里用 $x(//li//a) 测试。数据是否是动态加载的检查源代码里能否搜到新闻标题。如果抓到了一些但数据有缺失通常是过滤条件写得太严格或者太宽松。调 XPath 时把限制条件放宽一点观察多抓了哪些再逐步收紧条件比直接写一个严密条件成功率高得多。6.4 扩展思路从列表页深入详情页上面只是抓了列表页实战中常常需要进入详情页抓取正文内容。扩展思路并不复杂就是遍历上一步抓到的链接逐一请求详情页再解析正文def fetch_detail(url): resp requests.get(url, headersHEADERS, timeout10) tree html.fromstring(resp.text) # 正文通常在 article 或 p 标签里 paragraphs tree.xpath(//div[classarticle]//p/text()) return .join(paragraphs)不过这里要提醒一个效率问题抓取详情页时如果你是一次性发几十个请求很容易被服务器限流。比较稳妥的做法是控制并发数量比如一次最多 5 个请求加上随机延时让请求在时间上均匀分布。等爬到一定数量后检查一下数据有没有重复——同一篇文章可能出现在多个频道去重是实战中必须考虑的。7. 常见问题与排查技巧实录7.1 高频报错的速查表爬虫过程中遇到的报错类型其实非常有限我把最常见的错误、原因和解决方案整理成一个表格报错信息出现原因解决方案requests.exceptions.ConnectionError网络不通或目标网站可访问检查网络确认网址正确换一个 URL 测试requests.exceptions.Timeout服务器响应过慢超出了 timeout 设定增加 timeout 值检查网络换代理UnicodeDecodeError网页编码和实际解析编码不一致在 resp.encoding 里手动指定编码如resp.encoding utf-8AttributeError: NoneType object has no attribute xxx用 find/select 没找到对应元素返回了 None先在浏览器里确认元素是否存在检查选择器表达式IndexError列表取值超出范围检查 find_all 返回结果是否为空增加判断条件这里我想特意展开讲一下第一和第四个错误。ConnectionError 是新手遇到最多的它的迷惑性在于不是代码写错了而是网络环境问题或者网站拦截了你的请求。如果同一个网站用浏览器能打开用 requests 却报这个错八成是请求头里缺东西或者网站对非浏览器客户端做了封锁。NoneType 的错误最常出现在解析阶段它的报错信息比较抽象——“你调用的对象根本不存在”。我见过很多新手卡在这里几个小时最后发现只是网页结构变了或者 class 名称里多了一个空格。解决这类问题唯一可靠的方法就是在写解析代码之前先在开发者工具里确认元素结构最好在 Python 交互环境里打印 soup 对象直观地检查解析结果。7.2 请求返回 403 和 418 的排查思路HTTP 403 是服务器明确拒绝访问418 则是带有调侃性质的“我是一个茶壶”错误——对方在说你确实是机器人。这两个状态码都指向反爬机制。排查 403/418 时按照以下顺序逐一尝试添加 or 更新 User-Agent尽可能模拟真实浏览器。补全请求头包括 Referer、Accept-Language、Accept-Encoding 等。如果目标页面的数据必须登录检查是否缺少 Cookie。降低请求频率观察是大规模并发触发还是单次请求就被拒。换一个 IP 再试确认是不是 IP 被封。从策略上说被识别后比较好的处理方式是“退一步”把请求频率调慢模拟人的浏览节奏而不是一味加强伪装技巧。高频对抗只会导致对方升级反爬策略最后大家都麻烦。7.3 解析结果为空时如何定位问题解析结果为空是另一个高频事故。代码不报错但数据就是不出来这类问题最难排查因为你无从下手。我的排查套路是分步验证# 第一步确认请求是否真的成功 print(resp.status_code, len(resp.text)) # 第二步把网页保存到本地用编辑器查看原始内容 with open(debug.html, w, encodingutf-8) as f: f.write(resp.text) # 第三步在本地文件里搜索目标关键词 # 用 CtrlF 搜索标题文字看它是否在 HTML 里如果第一步正常、第三步搜索不到目标内容说明页面可能有动态加载数据不在初始 HTML 里需要另找 API 接口。如果第三步能搜到就继续打印解析结果soup BeautifulSoup(resp.text, lxml) elements soup.select(你的选择器) print(找到多少个元素, len(elements)) print(elements[:3])把找到个数和预览打印出来就能快速判断是“选择器定位不到”还是“定位到了但提取逻辑有误”。这套流程我已经用了很多年几乎能解决所有解析为空的问题。7.4 新手阶段必须养成的三个习惯第一每次请求前先确认状态码再进入下一步。这能让问题在哪个环节爆发立刻显现而不是混在一起最后无从判断。第二开发阶段把网页存到本地再写解析逻辑。不要每次调试都去发送网络请求一方面影响目标服务器另一方面网络不稳定会干扰你的调试。把 HTML 存为本地文件解析逻辑在本地测试确认无误后再接上真正的网络请求。第三做好请求频率控制。我曾经因为偷懒没有在循环里加延时半小时内把一个测试站点的接口打到 429 状态码——这就是请求太多被限流了。后来再也不敢轻视这个问题。学完这篇文章你已经掌握了一套完整的最小可运行的爬虫技术栈。先自己动手跑通文章里的示例再找一个小网站独立完成一个采集任务这个“自己做一遍”的过程比看十篇文章都有价值。之后可以顺着两个方向进阶一个是深入框架学习 Scrapy 的工程化能力另一个是扩展场景尝试数据清洗和可视化。不管选哪条路基础都是你现在掌握的这些核心逻辑——请求、解析、存储所有复杂的爬虫系统本质上都是这三个环节的规模化组合。