ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Python爬虫入门实战:requests抓取、正则解析与数据可视化

Python爬虫入门实战:requests抓取、正则解析与数据可视化 说实话我写了十几年的Python教程最常被问到的一句话就是“老师基础语法我都看完了然后呢”这个问题放到一套完整的入门课程里差不多就是day13前后该面对的事。前面的日子我们搞定了变量、数据类型、流程控制、函数、文件操作和异常处理但这些东西单拎出来都像零件摆在那儿很好看拼不起来就没意思。所以day13我通常不舍得拿来讲新语法而是干一件特别提气的事写一个真正能从网上把数据抓下来的小爬虫。这篇文章就把day13的完整内容摊开讲你会看到怎么用requests拿网页、怎么用正则从HTML里扣数据、怎么把结果存成CSV再画一张简单的图。学完这一天你就从“会写语法”变成“能搞数据”了。1. 为什么day13要安排爬虫爬虫到底在做什么很多教程把爬虫放在非常靠后的位置动不动就“进阶内容”。我自己教下来发现爬虫根本没有那么玄乎它恰恰是把前面学过的零碎语法串起来的最好载体。网络请求、字符串处理、正则匹配、文件读写、异常捕获全部能在一段不到五十行的代码里见面。对学习者来说这是第一次真正用代码解决“现实世界”的问题浏览器里能看到的信息怎么变成自己电脑里的结构化数据。1.1 先搞清楚网络请求的底层逻辑爬虫这名字听着唬人拆开来看就三步给服务器发一个请求等它把网页内容返回来再从返回的内容里提取你要的东西。这里最核心的概念是HTTP请求和响应。你在浏览器地址栏输入一个网址敲回车本质上就是向那台服务器发送了一条“GET请求”服务器处理完以后会返回一个HTML文档给你浏览器再把HTML渲染成花花绿绿的页面。爬虫做的事情就是跳过“渲染”这一步直接拿走HTML源码。所以你爬到的数据长得和浏览器里看到的不一样很正常你要的信息其实藏在HTML标签中间。举个例子你打开一个新闻列表页浏览器显示的是排版精美的标题列表。但你用“查看网页源代码”去看看到的是一堆这样的内容h3 classnews-titlea href/news/12345某地发生了一件大事/a/h3标题“某地发生了一件大事”就夹在a标签的尖括号之间。爬虫的活儿就是把这些尖括号里的字符串抠出来。这也是为什么爬虫入门阶段用正则表达式就够了——HTML再复杂你只关心特定标签里的特定内容正则就是最快的刀。1.2 代码为什么能拿到浏览器才能看到的页面有人会问我直接复制网页源码不就行了但实际需求是动态的——今天想看这十页明天想看那一百页而且数据要清洗、要汇总、要定期更新手工复制根本不现实。代码比人强的地方在于它可以带着参数循环请求自动换页自动存盘。关键是代码访问网页的时候服务器是能认出“你不是浏览器”的。因为普通浏览器发请求时会带上一个叫User-Agent的请求头标明自己是Chrome还是Safari。而很多脚本没有任何标识服务器一看就知道是程序在访问轻则拒绝重则封IP。所以职业习惯是写爬虫第一件事就把请求头伪装好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 }这串东西去哪找浏览器按F12打开开发者工具切到Network面板刷新页面随便点一个请求在Request Headers里就能看到完整的User-Agent。复制过来就行。1.3 选对练习目标比学会技术更重要入门阶段最容易踩的坑是一上来就盯着一线大厂的网站写爬虫。结果遇到验证码、登录墙、滑块、风控代码写了两小时报错一下午心态直接崩掉。我建议练习目标必须满足三个条件公开无需登录、页面结构规整、访问频率低一点也不会惹麻烦。我自己上课经常用的练习站点是“猫眼电影Top100”这类静态榜单页。结构简单没有动态加载一个URL拿下来就是一整个列表非常适合做入门项目。另外像一些公开的天气接口、豆瓣读书榜单也都可以。关键原则是只爬公开数据控制访问频率别给人家服务器添麻烦。做技术的这点分寸要有。2. 动手前先把环境和依赖准备好工欲善其事必先利其器。day13虽然代码不长但环境配置没整好后面全是坑。我见过太多人卡在import requests报错这一行一卡就是半小时最后发现是库没装上。所以今天咱们先把环境这块彻底理顺。2.1 解释器、编辑器与虚拟环境的基本选择Python环境这块Windows用户我推荐去官网下载稳定版安装包安装时务必勾选“Add Python to PATH”。这步不勾后面在命令行里敲python就是“不是内部或外部命令”。装好之后在终端里输入python --version能显示出版本号就说明解释器没问题。编辑器方面PyCharm和VS Code是目前最主流的两款。PyCharm是专门为Python打造的IDE开箱即用调试方便特别适合新手缺点是比较占内存。VS Code轻量但需要自己配置Python插件、解释器路径热词里那些“vscode python环境配置”、“pycharm配置python环境”的搜索量说明大家确实都在这里犯过难。我的建议很简单做这个爬虫小项目你只要有一个能写代码、能按F5运行的编辑器就够了。哪个顺手用哪个等以后项目变大了再挑也不迟。还有一件值得养成的习惯给每个项目建一个虚拟环境。虚拟环境相当于给这个项目单独圈一个“依赖小房间”里面装的库不影响全局也不怕和其他项目冲突。创建方法python -m venv venvWindows激活命令是venv\Scripts\activatemacOS和Linux是source venv/bin/activate。激活后命令行前面会出现一个(venv)前缀这时候pip安装的包都进小房间了。2.2 用国内镜像源装依赖告别下载超时爬虫要用到requests库安装命令一条pip install requests但很多朋友在装库时遇到过那个经典报错ReadTimeoutError下载到一半就断了。原因很简单——默认从PyPI官方源下载服务器在海外网络延迟高。解决办法是切换国内镜像源。清华、阿里、豆瓣都提供了PyPI镜像随便选一个用。一次性指定镜像源安装pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple如果想一劳永逸直接改全局配置。Windows下在用户目录创建一个pip.ini文件Linux/macOS创建~/.pip/pip.conf写入[global] index-url https://pypi.tuna.tsinghua.edu.cn/simple改完之后以后所有pip install默认走清华源下载速度能快一个数量级。顺带说一句如果你用的是conda也有类似的conda源配置原理一样。2.3 验证环境写一个三行的冒烟测试依赖装好以后别急着写爬虫先跑一个最小请求脚本验证环境通不通import requests resp requests.get(https://www.baidu.com, timeout5) print(resp.status_code)如果输出200说明requests能正常发请求、拿响应。如果报错多半是网络代理冲突或者DNS问题排查完再往下走。这个“最小可运行验证”的习惯能帮你把环境问题和代码逻辑问题彻底隔离开。3. 从零写一个能跑的小爬虫好了环境没问题现在我们正式进入实操环节。下面我用猫眼电影Top100榜单作为例子完整走一遍“发起请求 - 解析数据 - 清洗数据 - 保存文件”的流程。每一步我都会讲清楚为什么这么写以及有哪些细节容易被忽略。3.1 第一步带上伪装的请求头把网页源码拿回来猫眼Top100的URL是https://www.maoyan.com/board/4一页显示10部电影榜单一共10页。先拿第一页做测试。import requests 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/xhtmlxml,application/xml;q0.9,image/avif, image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9, } url https://www.maoyan.com/board/4 try: resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() # 状态码不是200时主动抛异常 except requests.RequestException as e: print(请求失败:, e) exit() print(resp.status_code) print(resp.text[:500]) # 打印前500个字符预览这里有几个细节要重点说。timeout10这个参数很多人会漏掉但它非常重要。如果没有超时限制一旦对方服务器响应慢你的脚本就会一直挂在那儿像死机一样既不知道结果也不知道该不该放弃。设成10秒的意思是如果10秒内服务器没返回数据requests主动抛一个Timeout异常程序继续往下走或者报错退出。raise_for_status()是requests的一个小保险。它检查响应状态码如果是4xx或5xx就直接抛异常。这样你就能知道请求有没有真正成功而不是拿着一个404页面吭哧吭哧解析半天什么都拿不到还一脸懵。拿到resp之后resp.text就是整个网页的HTML字符串。你可以先用print看一眼前500个字符确认内容不是空白的、不是乱码的再往下走。3.2 第二步用正则表达式从HTML里精准抠数据网页源码拿回来以后我们要在上万行HTML字符串里找到电影名字、主演、上映时间、评分这些信息。这时候正则表达式就登场了。先用最简单的方式看一眼结构。在源码里搜索“主演”附近的内容会发现每条电影信息长这样p classnamea href/films/1200486 title霸王别姬>import re pattern re.compile( rp classnamea href/films/.*? title(.*?).*?/a/p r.*?p classstar主演(.*?)/p r.*?p classreleasetime上映时间(.*?)/p r.*?p classscorei classinteger(.*?)/ii classfraction(.*?)/i/p, re.S ) result pattern.findall(resp.text)这段正则看着长其实拆开就四组括号每组括号对应一个字段括号里的.*?是非贪婪匹配意思是从这个位置开始一直匹配到下一个指定字符为止。re.S这个标志特别关键它让.能匹配换行符因为HTML源码里标签之间经常有换行和空格不加re.S就会匹配失败。findall方法返回一个列表每个元素是元组就是一部电影的五个字段。先打印出来看看for item in result: print(item)输出是类似这样(霸王别姬, 张国荣,张丰毅,巩俐, 1993-01-01(中国内地), 9., 6)到这一步数据已经从网页里抠出来了。但这里我还是要提醒一句正则表达式解析HTML是入门阶段最顺手的方案但它不是万能的。如果页面结构变了或者嵌套层级很深正则很容易翻车。等你熟练了以后可以再去学BeautifulSoup和lxml这类专门解析HTML的库它们的容错性更强。但入门阶段正则能把HTML结构和字符串处理的功底打扎实这个价值很重要。3.3 第三步数据清洗把字符串变成能用的数据正则抠出来的东西还带着脏数据。比如评分被拆成了“9.”和“6”两段上映时间后面还挂着“(中国内地)”这种括号注释。直接拿去用肯定不行得清洗。清洗这一步其实就是在练习我们前面学过的字符串方法和类型转换。movies [] for name, star, releasetime, integer, fraction in result: score float(integer fraction) # 把9.和6拼起来转成浮点数 release_year releasetime[:4] # 截取前4位得到年份 movies.append({ name: name.strip(), star: star.strip(), releasetime: releasetime.strip(), score: score, release_year: release_year })这里用到两个核心操作。float(integer fraction)是把字符串拼接后再转换类型。“9.”加“6”得到“9.6”再用float转成浮点数9.6。这就是热搜词里那个“python类型转换”的实际应用场景。很多时候爬虫拿到的都是字符串但数据分析、排序、画图都需要数值转换一下才顺手。releasetime[:4]是字符串切片取前四个字符。“1993-01-01(中国内地)”切完就是“1993”。也许你会问为什么不直接用正则抠年份其实也可以但这里用切片更简单直观而且还能复习字符串操作。清洗完我们把数据放进一个列表里每个元素是字典。为什么用字典因为字典能清晰地表达“每个字段是什么”后面转CSV、转JSON都非常方便。3.4 第四步把结果写进CSV文件给数据归档数据在内存里终究不踏实一关程序就没了。我们得把它存到磁盘上。CSV是表格数据的通用格式Excel能直接打开Python的csv标准库也能轻松读写。import csv with open(maoyan_top10.csv, w, encodingutf-8, newline) as f: fieldnames [name, star, releasetime, score, release_year] writer csv.DictWriter(f, fieldnamesfieldnames) writer.writeheader() writer.writerows(movies)这里有几个细节值得沉淀。encodingutf-8是很多新手会犯错的点。有人会问我明明写的utf-8为什么用Excel打开CSV还是乱码这是因为Excel默认按GBK编码打开文件。解决方案有两个一是写入的时候用utf-8-sig编码给文件加一个BOM头Excel就能正确识别了二是在保存之前手动在Excel里导入时选UTF-8。我通常直接用utf-8-sig一劳永逸。newline是防止CSV写入时出现多余空行。Windows平台下如果不指定这个参数writerows写入的每一行后面会跟一个空行文件看起来非常不整洁。这是新手碰到最多的诡异问题之一。到这里我们已经完成了爬虫的完整闭环请求 - 解析 - 清洗 - 存储。跑完代码你会在项目文件夹里看到一个maoyan_top10.csv里面躺着今天榜单前十的电影信息。4. 把爬下来的数据做一次最小可视化爬虫只是手段数据才是目的。所以day13我还会花一点时间把刚才存下来的CSV读出来画一张最简单的柱状图。这一步不为别的就为了让读者亲眼看到数据在手里代码真的能变成看得见摸得着的东西。4.1 为什么要提前接触可视化有人觉得可视化是数据分析师的事初学者没必要碰。但我的看法不一样。编程学习中有一个很现实的规律正反馈越快的知识越容易坚持。你花一小时写的爬虫最后如果只得到一个别人看不懂的CSV文件成就感会大打折扣。可如果这时你能画出一张评分对比图那种“数据在我的掌控之中”的感觉是用多少钱都买不来的。而且画图本身也是Python学习的一部分。它不要求你先学完数学、统计学才能动手只要有一组数值型数据就能画出最基础的图表。这个过程会反过来逼你理解数据结构怎么把CSV变成列表怎么从列表里抽出一列怎么把字符串转成浮点数。这些都是前面学过的东西现在终于派上了用场。4.2 用matplotlib画一张评分对比图画图最常见的是matplotlib库。装一下pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple安装完以后写一段脚本读取CSV并画图import csv import matplotlib.pyplot as plt movies [] with open(maoyan_top10.csv, r, encodingutf-8-sig) as f: reader csv.DictReader(f) for row in reader: movies.append(row) movies.reverse() # 让榜单第1名显示在上面 names [m[name] for m in movies] scores [float(m[score]) for m in movies] plt.figure(figsize(10, 8)) plt.barh(names, scores, color#ff6b6b) plt.xlabel(评分) plt.title(猫眼电影Top10评分对比) plt.tight_layout() plt.savefig(top10_scores.png, dpi150) plt.show()这短短二十行代码里有三个点值得留意。csv.DictReader(f)会把每一行都读成一个字典键是表头。这样我们就能用m[name]、m[score]这样直观的方式取数。float(m[score])又是类型转换——CSV里读出来的一定是字符串画图必须转成数值。plt.barh画的是横向柱状图。为什么要横着画因为电影名比较长横向排布能完整展示名字纵向的话名字会挤成一团。plt.savefig把图片保存到本地。这一步很多人都容易忘——图在屏幕上显示了关掉窗口就没了保存成文件才能沉淀下来。dpi150是清晰度设置数值越高图片越清晰文件也越大。运行脚本后你会得到一张图片十部电影的评分高低一目了然。到了这一步从“爬到数据”到“看懂数据”的闭环就完整了。4.3 一个小小的实用扩展多页数据汇总Top100榜单一共有10页URL的规律是https://www.maoyan.com/board/4?offset0、?offset10、?offset20……每页偏移10。这正好可以复习for循环和翻页逻辑。把上面的解析代码封装成一个函数再写个循环去请求每一页最后把所有页的数据合并整个排行榜就能一次性爬完。def fetch_page(offset): url fhttps://www.maoyan.com/board/4?offset{offset} # ... 复用前面请求和解析的代码 ... return movies all_movies [] for i in range(10): all_movies.extend(fetch_page(i * 10)) # 写入同一个CSV文件f字符串格式化在这里大显身手把循环变量塞进URL里。list.extend是把每一页的列表合并成大列表。这一小段扩展练习把函数、循环、列表操作全部串起来了对我来说这比单独讲十个语法点都有用。5. 实操中一定会踩的坑和排查办法爬虫项目虽然不大但第一次完整跑下来不出点问题反而不正常。我把这些年带学生过程中最常见的几类问题整理成了一张速查表每一个我都亲自踩过也帮别人排查过。症状可能原因解决方案请求后解析不到任何数据页面结构变了或反爬拦截先用print(resp.text)查看实际返回内容确认结构是否正确输出中文全是乱码编码识别错误使用resp.encoding resp.apparent_encoding自适应编码请求超时或连接被重置访问频率过高或缺少Headers设置headers伪装浏览器增加timeout加time.sleep(1)限速CSV用Excel打开全是乱码编码用了utf-8写入时改encodingutf-8-sig正则匹配结果全是空列表正则写错或HTML结构变化先在浏览器查看源码实际结构复制真实标签到正则工具里调试import requests直接报错环境没配对确认虚拟环境已激活用pip list查看已安装的包除了这张表还有两个经验之谈。第一个是代码一定要有“可重跑”的意识。爬虫脚本和别的脚本不一样它依赖外部网络环境今天能跑明天可能就断了。所以异常处理绝不能省。请求失败、解析为空、写入失败每种情况都用try...except包起来至少让程序在崩溃前告诉你“我是哪个环节出了问题”。我在前面代码里写的requests.RequestException就是干这个的。第二个是访问频率。很多爬虫被封IP不是因为对方多敏感而是因为你循环里没有间隔一秒钟发了十几次请求服务器不封你封谁。入门阶段养成一个好习惯每请求一页至少time.sleep(1)。爬得慢一点不会死被封了才麻烦。这也是一种基本的网络礼仪普通个人学习项目千万别给别人服务器造成压力。顺着话题再多说一句学习爬虫不等于什么都能爬。只访问公开的、允许访问的数据对自己的学习目标负责别把精力花在绕过别人安全机制上。这条原则看上去是道德要求其实是技术人的自我保护。还有一个小坑也很常见很多人喜欢在同一个代码文件里反复写测试代码改来改去最后自己都不知道哪个版本能跑。我的习惯是每个项目文件按功能分开requests_and_parse.py专门负责请求和解析save_data.py专门负责存储visualize.py专门负责画图。这样排错的时候你直接定位到对应的文件效率高很多。把今天的东西连起来再走一遍写到这里day13的内容其实已经讲完了。最后分享一点我个人的体会。每次带学员走到这一天我都会观察他们写完爬虫时的表情——那种感觉不是“我会了一个新语法”而是“我能自己从网络世界里拿到我想要的东西了”。这种能力的转变会让很多人在这一天真正爱上编程。往后你可以继续往更多页翻爬、把数据存进数据库、用更强大的解析库处理复杂页面也可以转头去学数据分析。路有很多条但day13是你第一次独立完成“从一个陌生网页到一张可视化图表”的完整旅程。最后再送大家一个小技巧。写完爬虫以后不要急着改需求加功能先盯着那两张输出——CSV文件和PNG图片——问自己三个问题数据对吗字段全吗如果明天再跑一次它还能稳定工作吗把这三个问题想明白你的爬虫才算真正过关。
返回列表