尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

零基础学Python爬虫:18个实战案例掌握数据采集全流程

零基础学Python爬虫:18个实战案例掌握数据采集全流程 很多人学 Python 爬虫卡住的地方不是语法而是教程太碎。今天看一个单页爬虫明天看一个 JS 逆向到了最后连一个完整的、能从“打开网页”走到“存好数据”的项目都没做完。如果你也有这种感觉这篇文章就是给你准备的。这里有一个明确判断18 个爬虫实战案例不是用来凑数量的而是用越来越贴近真实项目的例子把“请求、解析、清洗、存储”这条链路彻底走通。对这些案例不需要会 JavaScript不需要懂逆向工程只需要 Python 基础语法、requests 和 BeautifulSoup再加上一点耐心。读完这篇文章你能得到三个结果第一理解网页数据从产生到落盘的完整链路第二拿到可以直接运行的 5 组核心源码并看懂它们背后的通用套路第三知道遇到翻页、JSON 接口、登录、反爬和增量更新时应该往哪个方向思考。1. 为什么说 18 个案例比刷三遍语法更有用Python 爬虫的学习路径和 Python 基础语法的学习路径很不一样。语法学习是“记住规则 做练习”爬虫学习是“遇到问题 拆解问题 把网页解构成数据”。很多零基础读者习惯先把 Python 教程看完再动手结果看完requests 和 BeautifulSoup 的文档打开一个真实网页仍然不知道从哪里下手。原因很简单文档讲的是“库能干什么”实战讲的是“遇到一个具体网页先看哪里再写什么”。爬虫实战需要三层能力这三层能力只能通过案例来训练能力层级解决的问题对应训练请求层拿到网页源码或接口数据requests、URL 规律、请求头解析层从 HTML 或 JSON 中提取目标字段BeautifulSoup、正则、json 解析存储层把数据保存成 CSV、Excel 或数据库csv、pandas、sqlite3只看概念读者会误以为爬虫的难度主要在“反爬”上。但从教学视角看80% 的初学者卡在请求层的 URL 拼接和解析层的选择器编写上。18 个案例的设计思路就是先把这两个基础缺口补上再逐步加入翻页、接口、登录态和增量更新等真实场景。什么样的人最适合按这套案例学习刚学完 Python 基础语法想做点东西验证能力的人。工作中需要从网页手动复制数据想用脚本替代重复操作的人。想转行数据分析岗位需要自己采集练习数据的人。被各种“爬虫速成课”误导想重新打好请求和解析基本功的人。这套案例不适合谁不适合想抓取 App 加密数据、想绕过验证码、想大规模采集商业平台数据的人。原因不是技术做不到而是风险和法律边界不划算。这篇文章讲的是安全、合规、可持续的爬虫入门方式。2. 爬虫的核心概念与工作原理2.1 抓网页就像给服务器发一张“明信片”爬虫的本质只有一个动作向服务器发送 HTTP 请求然后接收响应。服务器返回的响应通常有两种形式一种是 HTML 页面需要解析一种是 JSON 数据直接提取即可。用类比来说浏览器访问网页是“人在看”爬虫访问网页是“程序在看”。服务器并不关心对面是谁它只关心请求是否符合规则。一个最基本的 requests 请求只需要三行代码import requests url https://example.com resp requests.get(url) print(resp.status_code) print(resp.text[:200])2.2 什么是批量型、增量型和垂直型爬虫在搜索材料中经常看到这三个词“批量型爬虫、增量型爬虫、垂直型爬虫”。它们是爬虫按使用场景做的分类理解了这个分类就理解了 18 个案例的编排逻辑。批量型爬虫一次抓取大量历史数据通常从第 1 页开始逐页抓取直到最后一页。它适合做初始数据积累比如抓取一个商品分类下所有历史在售记录。缺点是如果网站每天新增数据每次全量抓取成本高、频率快容易被限流。增量型爬虫只抓取上次抓取之后新增或变化的数据。它需要记录“上次抓到哪里”常用方式包括数据库去重、记录最新 ID、记录最新时间戳。适合日报、新闻、监控类场景。垂直型爬虫只关注某个特定领域或站点比如只抓图书信息、只抓房源信息、只抓某个招聘网站的职位。这类爬虫的特点是目标固定、字段清晰、解析逻辑单一非常适合入门练习。类型抓取范围典型场景难度批量型历史全量数据初次建库、离线分析★★增量型新增和变化数据日报监控、价格跟踪★★★垂直型特定网站/领域信息采集、竞品观察★★2.3 解析 HTML 的核心思路拿到 HTML 之后解析核心不是写正则而是用选择器找节点。BeautifulSoup 提供了 find 和 find_all 两个最常用的方法配合标签名、class、id 可以定位到任何一处内容。from bs4 import BeautifulSoup soup BeautifulSoup(html_text, html.parser) title soup.find(h1).get_text() items soup.find_all(div, class_item)初学者最容易犯的错误是“试图用一次 find_all 拿到所有答案”。实际更可靠的写法是先定位到每条数据的容器节点再在每个容器内继续查找字段。这个思路会反复出现在后面的案例里。3. 环境准备与前置条件3.1 Python 版本建议使用 Python 3.8 以上版本。不同教程对版本要求不同但本文案例使用的 requests、BeautifulSoup 库在 3.8 到 3.12 之间都能正常工作。版本请以实际环境为准不用刻意追求最新。Windows 用户可以从官网下载安装包安装时务必勾选“Add Python to PATH”。Linux 用户可以通过系统包管理工具安装安装完成后在终端里验证python --version pip --version如果 pip 命令找不到可以尝试python -m pip --version3.2 安装依赖库本文需要三个第三方库requests 用于发请求beautifulsoup4 用于解析 HTMLlxml 用于提高解析速度。安装命令如下pip install requests beautifulsoup4 lxml国内网络环境下如果 pip 下载速度慢可以临时使用镜像源pip install requests beautifulsoup4 lxml -i https://pypi.tuna.tsinghua.edu.cn/simple3.3 推荐 IDE 与项目结构对零基础读者推荐 VSCode 配合 Python 插件或者直接用 PyCharm 社区版。本文案例的代码文件建议按功能来组织python-spider-cases/ ├── 01_download_one_image.py ├── 02_batch_download_images.py ├── 03_weather_api.py ├── 04_douban_top250.py ├── 05_incremental_news.py └── requirements.txt把爬虫脚本拆成多个小文件而不是写在一个文件里能帮助读者在出错时快速定位问题也为后续把脚本改造成类或模块留好空间。4. 18 个实战案例总览这 18 个案例按照“从简单到复杂、从静态到动态、从 HTML 到 JSON、从单页到批量”的顺序排列。需要注意示例站点可能会改版部分 URL 和网页结构可能变化运行代码时以实际页面为准。判断依据是协议与字段含义而不是某个固定字符串。序号案例爬取目标核心知识点难度1下载单张图片图片文件requests 字节流写入★2批量下载表情包/壁纸图片链接集合循环 列表存储★3天气数据查询JSON 接口requests.get json 解析★4新闻列表抓取标题/时间/链接find_all get_text★5豆瓣电影 Top250 第一页电影标题/评分/简介BeautifulSoup 选择器★★6豆瓣电影 Top250 全部250 条记录翻页 URL 参数★★7CSDN 博客文章标题采集标题/链接class 选择器 列表★★8招聘网站职位列表职位名/公司/薪资列表页字段提取★★9京东商品搜索结果商品名/价格URL 参数 请求头★★10手机 App 接口数据JSON 字段接口 URL 分析★★11微博热搜榜热搜词/热度移动端页面解析★★12知乎问题回答数据回答内容/点赞数API 返回 JSON★★★13B站视频信息标题/播放量/弹幕量网页 JSON 字段★★★14微信文章信息文章标题/公众号搜狗微信搜索解析★★★15链家在售房源小区/户型/价格翻页 详情字段★★★16汽车之家车型参数参数表表格解析★★★17酒店价格信息酒店名称/价格复杂站点反爬思路★★★18增量爬虫综合案例新增新闻/更新记录去重 时间戳★★★从学习角度第 1 到第 4 个案例用来建立信心第 5 到第 9 个案例用来掌握主流解析套路第 10 到第 14 个案例用来学习不同数据格式第 15 到第 18 个案例用来接触真实复杂场景。5. 首批入门案例从单张图片到批量下载5.1 案例 1单张图片下载图片下载和文本下载本质相同区别在于图片需要以二进制方式写入文件。# 文件路径01_download_one_image.py import requests url https://img.example.com/sample.jpg headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout10) if resp.status_code 200: with open(sample.jpg, wb) as f: f.write(resp.content) print(图片下载成功大小, len(resp.content), 字节) else: print(下载失败状态码, resp.status_code)说明resp.content返回的是二进制内容不能用resp.text保存图片。设置timeout10是为了防止某个请求卡死导致程序无响应。User-Agent是一个声明自己是什么客户端的请求头不同站点对默认 UA 的处理方式不同加上 PC 浏览器 UA 更稳妥。5.2 案例 2批量下载表情包批量下载的核心是先拿到所有图片的链接再通过循环逐一下载。# 文件路径02_batch_download_images.py import requests from bs4 import BeautifulSoup base_url https://example.com/funny headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(base_url, headersheaders, timeout10) soup BeautifulSoup(resp.text, html.parser) img_tags soup.find_all(img) img_urls [] for img in img_tags: src img.get(src) if src and src.startswith(http): img_urls.append(src) print(找到图片数量, len(img_urls)) for index, img_url in enumerate(img_urls[:10]): r requests.get(img_url, headersheaders, timeout10) if r.status_code 200: with open(fimage_{index}.jpg, wb) as f: f.write(r.content) print(f已下载第 {index 1} 张图片)5.3 这批案例的小结论前 4 个案例在难度上不需要任何框架知识但它们完成了两件重要的事让读者写出第一个“发请求并保存数据”的完整流程以及理解“URL 是输入文件是输出”的最小闭环。真正让爬虫变得有价值的是后面的批量化和自动化而不是单次请求本身。6. 列表页与翻页案例豆瓣电影 Top250豆瓣电影 Top250 是中文爬虫学习中最经典的案例之一。它的页面结构稳定、数据字段清晰、服务器响应友好非常适合用来练习列表页解析和翻页循环。6.1 观察 URL 规律打开豆瓣电影 Top250第一页 URL 是https://movie.douban.com/top250?start0filter第二页把start0改成start25第三页改成start50。这说明豆瓣使用的是“start 偏移量”翻页方式每页显示 25 条总共 10 页。6.2 完整源码# 文件路径04_douban_top250.py import requests from bs4 import BeautifulSoup import csv import time 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_one_page(start): url fhttps://movie.douban.com/top250?start{start}filter resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() soup BeautifulSoup(resp.text, html.parser) items soup.find_all(div, class_item) rows [] for item in items: title_tag item.find(span, class_title) title title_tag.get_text() if title_tag else rating_tag item.find(span, class_rating_num) rating rating_tag.get_text() if rating_tag else quote_tag item.find(p, class_quote) quote quote_tag.get_text().strip() if quote_tag else rows.append([title, rating, quote]) return rows def main(): all_rows [] for start in range(0, 250, 25): print(f正在抓取 start{start} 的页面) rows fetch_one_page(start) all_rows.extend(rows) time.sleep(2) with open(douban_top250.csv, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([标题, 评分, 短评]) writer.writerows(all_rows) print(抓取完成共保存, len(all_rows), 条记录) if __name__ __main__: main()运行方式python 04_douban_top250.py运行成功后当前目录下会出现douban_top250.csv可以用 Excel 打开。使用utf-8-sig编码是因为 Windows 下的 Excel 对无 BOM 的 UTF-8 文件可能出现中文乱码。这里最值得学习的不是豆瓣本身而是其中三个通用套路用range(0, 250, 25)拼接所有页面 URL。用time.sleep(2)控制请求节奏避免对目标站造成压力。用csv.writer把内存中的结构化数据保存到本地文件。6.3 翻页案例的常见问题如果运行后发现 CSV 里只有表头没有数据最常见原因是find_all(div, class_item)返回空列表。这意味着页面结构已经变化或者请求被重定向到了登录页。第一步应该打印resp.status_code和resp.text[:500]来确认响应内容到底是什么。7. JSON 接口案例天气数据与热搜数据不是所有网站都适合直接解析 HTML。很多网站的页面数据是通过 JavaScript 异步请求加载的这种接口返回的通常是 JSON。对爬虫来说JSON 接口比 HTML 页面更容易处理因为字段结构是现成的不需要猜选择器。7.1 天气数据接口示例# 文件路径03_weather_api.py import requests import json city_code 101010100 # 城市代码这里以北京为例 url fhttps://www.example-weather-api.com/weather?city{city_code} headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout10) if resp.status_code 200: data resp.json() print(json.dumps(data, ensure_asciiFalse, indent2))说明resp.json()会把响应体直接解析成 Python 字典或列表。json.dumps(..., indent2)用于格式化打印方便人工查看结构。不同天气服务的字段命名不一样需要先打印一份完整 JSON 再决定取哪些字段。7.2 JSON 接口的通用提取代码模板def extract_fields(data, path): current data for key in path: if isinstance(current, list): current current[int(key)] else: current current.get(key) return current这个模板支持类似[data, list, 0, title]的多级路径提取适合在调试接口时快速验证字段位置。7.3 什么时候优先找 JSON 接口当目标页面打开时如果页面内容不是一次性返回而是先看到空白框架、然后逐步渲染出来就需要优先在网络面板中查找 JSON 接口。判断方法打开浏览器开发者工具切换到 Network 面板刷新页面筛选XHR或Fetch再逐个查看响应内容。这个习惯对后面抓取微博热搜、知乎回答、B站信息非常有用。8. 需要登录和反爬的案例思路第 11 到第 18 个案例中有一部分会涉及登录状态、请求头限制或访问频率限制。下面从通用角度讲清楚处理思路不涉及任何绕过机制也不提供破解手段。8.1 使用 Session 保持会话如果目标页面需要登录后访问可以使用 requests 的 Session 对象来保持 Cookie。import requests session requests.Session() session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) }) # 模拟登录仅作为示例真实登录参数以目标站为准 payload { username: your_username, password: your_password, } login_url https://example.com/login session.post(login_url, datapayload, timeout10) # 用同一个 Session 访问需要登录的页面 resp session.get(https://example.com/profile, timeout10) print(resp.status_code)注意登录接口的字段名、加密方式、验证码要求因站而异。本文只演示 Session 保持登录的思路具体参数需要从开发者工具的 Network 面板中获取。8.2 设置 User-Agent 和超时重试很多站点会拦截不带 User-Agent 或 User-Agent 明显异常的请求。推荐的请求头设置方式import requests from requests.adapters import HTTPAdapter session requests.Session() session.mount(http://, HTTPAdapter(max_retries3)) session.mount(https://, HTTPAdapter(max_retries3)) headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36, Accept: text/html,application/json,text/plain,*/*, Accept-Language: zh-CN,zh;q0.9,en;q0.8 } session.headers.update(headers)8.3 遇到验证码的正确处理方式如果遇到验证码、滑块校验或者“访问频率过高”的提示说明目标站点的风控机制已经触发。此时应该做三件事立即暂停脚本而不是继续提高请求频率。降低抓取频率把请求间隔从 1 秒提升到 5 秒以上。评估数据源。如果只是想学习可以换成没有风控的练习站点如果是业务需求则优先考虑官方 API 或数据授权合作。这个原则同样适用于手机 App 数据、电商平台数据和社交平台数据。爬虫的价值在于提高学习效率和信息获取效率而不是破解别人部署的防护系统。9. 增量型爬虫实现思路在 18 个案例中第 18 个案例是增量爬虫。它和前 17 个案例最大的区别是前 17 个跑一次就结束增量爬虫需要反复运行并且每次只抓取新增数据。9.1 增量爬虫的核心记住“上次抓到哪里”常见的记录方式有三种方式适用场景优缺点根据 ID 去重列表型数据简单可靠需要维护已抓取 ID 集合根据时间戳新闻、公告需要目标页面提供时间字段根据内容哈希无法确定唯一键通用但计算开销较大9.2 一个简单的增量去重框架import json import os CACHE_FILE seen_ids.json def load_seen_ids(): if os.path.exists(CACHE_FILE): with open(CACHE_FILE, r, encodingutf-8) as f: return set(json.load(f)) return set() def save_seen_ids(seen_ids): with open(CACHE_FILE, w, encodingutf-8) as f: json.dump(list(seen_ids), f, ensure_asciiFalse) def fetch_latest_items(): # 替换为真实的抓取逻辑 return [ {id: 1001, title: 新闻一}, {id: 1002, title: 新闻二}, {id: 1003, title: 新闻三}, ] def main(): seen load_seen_ids() items fetch_latest_items() for item in items: if item[id] not in seen: print(新增:, item[id], item[title]) # 到这里可以保存到数据库或写入文件 seen.add(item[id]) save_seen_ids(seen) print(完成已记录, len(seen), 个 ID) if __name__ __main__: main()这个框架把去重逻辑和抓取逻辑分开读者在真实项目里只需要替换fetch_latest_items()返回的数据即可。9.3 增量爬虫的工程建议去重状态值存到文件、SQLite 或 Redis不要每次重新初始化。每次运行先记录开始时间结束后记录本次处理条数。异常中途退出时应该保留已经写入的数据避免重复抓取。10. 常见问题与排查方法下面表格汇总了入门阶段最常遇到的 8 个问题。遇到问题时按表格中的“排查方式”先看现象再定位原因。问题现象可能原因排查方式解决方案中文乱码编码判断错误打印resp.encoding和resp.apparent_encoding手动设置resp.encoding utf-8SSL 证书报错目标站证书不受信任检查 URL 是否为 https不要直接关闭验证先检查系统时间与证书找不到数据节点页面结构已变打印resp.text[:1000]重新检查真实页面的 HTML 结构返回 403请求被拒绝查看 response headers更新 User-Agent、Accept 等请求头返回 404URL 拼接错误检查 URL 参数打开浏览器查看实际请求地址请求超时目标服务器响应慢增加 timeout 值设置timeout(5, 10)并在异常中重试列表为空选择器写错用选择器工具验证改用 find_all 容器节点逐层查找被限流封禁请求频率过高查看响应中的提示信息增大 sleep 间隔加随机延时排查通用顺序是先看状态码再看响应文本前 500 字最后检查选择器和 URL。不要一上来就怀疑反爬。11. 最佳实践与工程建议11.1 请求频率把“礼貌”写进代码无论目标站是练习站点还是真实站点都应该控制请求频率。一个简单的限速写法import time import random def polite_sleep(): time.sleep(random.uniform(1.5, 3.5))随机间隔比固定间隔更接近真实用户行为也能显著降低触发限流的概率。11.2 异常处理不要一个请求失败就中断整个任务正确做法是捕获异常、记录失败 URL、跳过当前请求、继续后续任务。import logging logging.basicConfig(levellogging.INFO, filenamespider.log) def safe_get(url, session, retries3): for attempt in range(retries): try: resp session.get(url, timeout10) if resp.status_code 200: return resp except Exception as e: logging.warning(f第 {attempt 1} 次请求失败: {url}, 错误: {e}) time.sleep(2) return None11.3 数据存储小项目用 CSV大项目用数据库前 18 个案例使用 CSV 或 JSON 文件就够了。实际项目如果数据量超过几万条建议切换到 SQLite 或 MySQL并给唯一键加索引。11.4 日志记录让脚本“事后可查”每个脚本至少应该记录三件事请求 URL、响应状态码、保存文件路径。这样即使第二天发现数据不对也能快速定位是哪个环节出了问题。11.5 法律与合规边界这一点必须反复强调爬取公开信息用于学习研究没问题但要注意尊重目标网站的 robots.txt 声明。不能抓取用户个人隐私信息、账号信息、非公开接口数据。爬取的数据不能用于商业转售、批量导出后发布、恶意竞争等用途。抓取频率要控制在对服务器无明显影响的范围内。遇到验证码、登录墙、风控拦截时应停止尝试而不是继续使用更激进的方式。判断一个爬虫项目是否合适有一个简单标准你希望别人用同样的方式爬你自己的网站吗如果答案是否定的就不要对别人做同样的事。12. 总结与后续学习方向这 18 个案例真正想讲清楚的是爬虫学习中反复出现的通用套路URL 是入口请求头是身份证明响应体是原材料解析逻辑是加工线CSV/数据库是成品仓库。把这五步走通一次后面的学习会轻松很多。对零基础读者建议不要一口气写 18 个案例。先复制第 5 章的单图片下载代码跑通再把第 6 章的豆瓣 Top250 代码完整运行一遍观察 CSV 结果最后用第 9 章的增量去重框架改造成自己的“每日新闻提醒脚本”。完成这三个步骤再回头补充其他案例效率会明显更高。后续可以继续深入的方向有三个学习 scrapy 框架理解批量爬虫的项目工程化方式。学习 pandas把爬取的数据直接做清洗与分析。学习反爬应对的合法边界重点理解请求头、Cookie、代理池和验证码背后的风控逻辑而不是绕过手段。如果你在运行代码时遇到报错先复制错误信息去搜索再看代码里的函数名和缩进。绝大多数问题不是“太难”而是漏了一个冒号、选错了一个标签名。保持动手习惯18 个案例跑完之后你会发现自己已经能看懂很多开源爬虫项目的源码了。
返回列表