AI编程(四十一):爬虫入门 — 第一次亲手从网页”取”东西

作者:

在

上一篇只看不抓,把网页的骨架摸熟了;今天动手:装上 BeautifulSoup 这把”万能钥匙”,把网页里的东西真真切切”取”下来、存成自己的文件。你会发现爬虫根本不是黑客技术——它就是”看懂结构 + 按图索骥”,而按图索骥的功夫,你上一篇已经练完了。

一、还是那张值班表,今天不加班了

先把上一篇欠的账摆上桌。

上次你遇到的事:单位公告栏网页上挂着一张值班表,领导让你整理成 Excel 存档,每周一次。你已经学会了”看”网页骨架——右键查看源代码,找到那个

,看见

一行一行排着日期和姓名。但看完之后呢?你还是只能复制粘贴,手工整理,每周一次,每次十分钟,一年下来白白干掉八个多小时。

今天把这八个多小时抢回来。

目标很明确:写一个程序,运行一下,值班表就自己变成一个文件躺在你的电脑上。不需要打开浏览器,不需要选中文字,不需要 Ctrl+C。

你可能会嘀咕:我上周学的 API(第38篇)不是能拿数据吗?为什么还要学新的?答案在上一篇就说了:不是每家网站都开”官方点餐窗口”。API 是餐厅点餐,爬虫是自助取餐——窗口没开的时候,你总得会自己拿盘子。而且说句实话,日常生活里你能碰到的数据(公告、排班、价目表、成绩、目录),九成九没有 API,全都长得像”一张网页”。所以这一篇,是整个系列里最”实用”的几篇之一。

今天只引入一个新东西:BeautifulSoup(读作”美丽汤”,这名字确实有点搞笑,忍一下)。它干的活儿一句话就能说清:把网页源码变成”可以按名字查东西”的结构。上一篇你学会在源码里”找门牌号”,BeautifulSoup 就是那个拿着门牌号帮你取快递的管家。

二、BeautifulSoup:给网页配一个”拆套娃的管家”

先讲人话版原理

上一篇的类比你还记得吧:网页是一摞套娃,一层套一层,每个盒子上贴着标签(tag)、门牌号(class / id)。

问题是,源码本质上就是一大串文本字符。你用 Python 的字符串操作去里面抠数据,就像让你闭着眼在套娃堆里摸出”第三层的那个小娃娃”——能摸到,但慢、容易错、代码写得像天书。

BeautifulSoup 干的事:把这串字符先拆成真正的”套娃结构”,然后给你一堆人话查询:

  • “帮我找名叫 table 的盒子” → soup.find('table')
  • “把页面里所有名叫 td 的小盒子都拿出来” → soup.find_all('td')
  • “找门牌号写着 duty 的那个盒子” → soup.find(class_='duty')
  • “把这个盒子里的文字给我” → 盒子.get_text()

就这四句,今天的核心全在这了。听着不多?够你把值班表抓下来了。

装库:两条命令

打开终端(Windows 是”命令提示符”或 PowerShell,Mac 是”终端”):

pip install requests beautifulsoup4

一个是上一篇用过的”取件员”(requests,负责把网页源码取回来),一个是今天的”拆套娃管家”(beautifulsoup4)。装完各敲一句验证:

python -c "import requests, bs4; print('都装好了', bs4.__version__)"

打印出版本号就妥了。

小插曲:为什么它叫 beautifulsoup4?因为这是第4版。你 pip install 的是 beautifulsoup4,但代码里 import 的名字是 bs4——装的名字和用的名字不一样,这是个著名的坑,提前给你打好疫苗:装 beautifulsoup4,用 bs4。

第一个抓取程序:先拿”自己准备的网页”练手

学抓东西,先别急着对真实网站下手——真实网站源码几万行,第一次就啃硬骨头容易劝退。咱们先自己捏一个”迷你网页”练手,等手熟了再上真网站。

新建一个文件 值班表.html,内容如下(完全照抄即可):


  
    

2026年10月值班表

发布日期:2026-10-17

周一张三
周二李四
周三王五

看着眼熟吧?这就是上一篇”看”的那个骨架。现在写 spider1.py:

from bs4 import BeautifulSoup

# 第1步:拿到网页源码(今天先从本地文件读,模拟"取回来的源码")
with open("值班表.html", encoding="utf-8") as f:
    html = f.read()

# 第2步:交给管家,拆成套娃结构
soup = BeautifulSoup(html, "html.parser")

# 第3步:按名字取东西
title = soup.find("h1").get_text()      # 找到 h1 盒子,取出文字
print("标题是:", title)

rows = soup.find_all("tr")              # 把所有 tr 盒子都拿出来
for row in rows:
    cells = row.find_all("td")          # 每个 tr 里再找 td 小盒子
    day = cells[0].get_text()
    name = cells[1].get_text()
    print(day, "值班的是", name)

运行:

python spider1.py

预期输出:

标题是: 2026年10月值班表
周一 值班的是 张三
周二 值班的是 李四
周三 值班的是 王五

恭喜,这是你人生第一个爬虫。是的,就这么几行。爬虫的”神秘感”今天正式破除:取源码(requests/open)→ 拆结构(BeautifulSoup)→ 按名取物(find / find_all)→ 拿到手(get_text)。四步,一步都不能少,但也一步都不难。

代码里有个小细节留意一下:BeautifulSoup(html, "html.parser") 里那个 "html.parser" 是”用哪把剪刀拆套娃”——Python 自带的剪刀,不用额外装,今天全程用它。

换成真网页:把”取源码”那一步换掉

本地文件练熟了,换真网页只需要改一行——把”读文件”换成”发请求”:

import requests
from bs4 import BeautifulSoup

# 对比上一个程序:只有这一段是新的
resp = requests.get("https://example.com", timeout=10)
resp.encoding = "utf-8"
html = resp.text

soup = BeautifulSoup(html, "html.parser")
print(soup.find("h1").get_text())

看到了吗?BeautifulSoup 部分一个字都没变。这就是分层的好处:requests 负责”把源码取回来”,BeautifulSoup 负责”在源码里找东西”,各干各的,换谁都不影响谁。你现在可以把任何网页的源码喂给刚才那个”拆套娃 + 按名取物”的套路。

用哪个真实网站练手?https://example.com 是个专门给人练习的极简页面,永远稳定,最适合第一次。等你手熟了,再去抓你自己单位的公告页——那才是这篇课真正的靶子。

存下来:抓到的东西要落袋为安

抓到手只是成功一半,存成文件才算闭环。接着上面的代码写:

# 把抓到的值班表存成 CSV(第25篇的手艺你还记得吧)
import csv

lines = [["周一", "张三"], ["周二", "李四"], ["周三", "王五"]]  # 前面循环里抓到的数据
with open("值班表.csv", "w", encoding="utf-8-sig", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["日期", "姓名"])
    writer.writerows(lines)

print("已保存到 值班表.csv")

utf-8-sig 这个参数是给 Excel 准备的——不加它,中文在 Excel 里会显示成乱码(第25篇的坑,复习一下)。到这儿,”每周手工整理十分钟”的活儿,正式变成”运行一次脚本三秒钟”。

三、跟AI说需求 → 读懂 → 改进

老规矩,这个学习法是本系列的主心骨,今天走一遍完整流程,让你看看怎么用AI把刚才的程序”越改越像正经软件”。

第一步:跟AI说需求

把需求说具体,别只说”帮我写爬虫”。参考这个说法:

“我想抓一个网页上的值班表。表的结构是:一个

里有很多

,每行两个

,第一个是日期、第二个是姓名。请帮我写 Python 代码:用 requests 取源码,用 BeautifulSoup 把每行的日期和姓名抓出来,打印出来,并且保存成 CSV 文件(带表头)。网页先用本地文件 值班表.html 测试。”

看出来了吗?这段话里最重要的不是”帮我写代码”,而是你把网页结构描述清楚了——上一篇练习3练的就是这个。AI 拿到这种需求,一次就能写对;你说”帮我抓个网页”,它只能猜,猜错了你还得返工。

第二步:读懂AI给的代码

AI 给你的代码大概率和上面的差不多。读懂的标准不是”能默写”,而是能回答三个问题:

  1. 哪一行负责”取源码”?(requests.get / open)
  2. 哪一行负责”拆结构”?(BeautifulSoup(...))
  3. 哪一行负责”按名字取”,名字是哪来的?(find('table') 里的 'table',名字来自你观察网页源码时看到的标签名)

能答上这三个问题,你就真的读懂了。答不上?把对应那行代码单独贴给AI:”这行在干什么?用比喻解释。”

第三步:改进

读懂之后提新要求,让程序更皮实。比如:

“现在有两个问题帮我改:①如果网页上某天没排班,

只有一个,我的代码会报错’列表索引超出范围’,怎么处理?②我希望运行时先打印’正在抓取…’,抓完了打印’共抓到N条’。”

AI 大概率会教你用 try/except(第10篇的手艺)或者 if len(cells) >= 2: 判断(第5篇的手艺),再加上两个 print。注意这里发生的事:你今天只学了 BeautifulSoup 一个新东西,但改进程序用的全是前40篇的老手艺。编程学习就是这样,新知识是砖,旧知识是水泥,房子是一起垒起来的。

四、四个必踩的坑(先打疫苗)

坑1:忘了 get_text(),抓出来一堆标签。soup.find("h1") 拿到的是整个盒子(连标签带内容),直接 print 会输出

2026年10月值班表

这样一坨。你想要纯文字,就得 .get_text()。疫苗:拿到东西先问自己”我要的是盒子还是盒子里的文字”——要文字,加 .get_text();要属性(比如链接地址),用 .get('href')。

坑2:find 和 find_all 分不清,一个返回单个、一个返回列表。find 找第一个,返回的是一个盒子(可以直接 .get_text());find_all 找全部,返回的是列表,必须 for 循环遍历后再取文字。最常见的报错是 'ResultSet' object has no attribute 'get_text'——意思就是”你对一个列表喊 get_text,列表没有这个本事”。疫苗:要用循环的,一定是 find_all;不循环直接取文字的,一定是 find。

坑3:抓真实网页时忘了 resp.encoding,中文全变乱码。有些网站(尤其是国内网站)用的不是 UTF-8 编码,resp.text 直接读会给你一屏”锟斤拷”。疫苗:取完源码先加一行 resp.encoding = resp.apparent_encoding(让 requests 自己猜编码)或 resp.encoding = "utf-8",能挡掉八成乱码问题。本地文件读取同理,open(..., encoding="utf-8") 不能省。

坑4:find 找不到东西时返回 None,然后程序崩在下一行。soup.find("table") 如果网页里根本没有

,返回的是 None,你接着 .get_text() 就报 'NoneType' object has no attribute 'get_text'。疫苗:真网站的结构随时会变,找不到是常态不是意外。先 table = soup.find("table"),再 if table is None: print("没找到表格,网页结构可能变了"); exit()。这个小习惯下一篇、下下一篇全用得上——爬虫是跟”会变的东西”打交道,防御性检查不是可选项。

五、跟AI协作的正确姿势(抓数据特供)

  1. 喂”一小段源码”,不要喂”整个网页”。上一篇说过:几万行源码全丢给AI,它也会看花眼。正确姿势是:你在源码里 Ctrl+F 搜到”值班”两个字,把它前后各几十行复制给AI,说”数据在这个区域里,帮我写提取代码”。精准打击。
  2. 让AI解释”选择器”,而不是替你猜选择器。AI 猜的 class 名可能根本不准。更稳的流程是:你用 F12 查看器亲自确认”这个表格的 class 叫 duty-table“,然后让AI”用 class_=’duty-table’ 来定位”。定位你来,写码它来。
  3. 让AI写”报错处理”,这是爬虫的灵魂。写完提取代码,多问一句:”如果这个标签找不到、或者某行少一个格子,帮我加上友好的错误处理,让程序不崩、而是告诉我哪里出问题了。”会报错的爬虫满街都是,能优雅报错的爬虫才是你的生产力工具。
  4. 改完先跑本地文件,再跑真网页。AI 给的代码,先拿 值班表.html 这种”自己可控的网页”跑通,确认提取逻辑没问题,再换成真网址。一步到位跑真网页,出了错你都不知道是”取源码”错了还是”找东西”错了——分层测试,是从第12篇就教你的老办法。

六、今日小练习

练习1:跑通你的第一个爬虫。照抄第二节的 值班表.html 和 spider1.py,运行并核对输出。然后改一个需求:把周三的值班人改成你自己的名字(改 HTML 文件即可),重新运行,确认程序抓到的是”改过之后”的值。

提示:这题练的是”程序读的是文件里的当前内容”这个直觉——改文件就能改结果,不用改代码。如果改完输出没变,检查你保存的是不是同一个 值班表.html。

练习2:让程序多抓一样东西。在 值班表.html 的

下面加一行

发布日期:2026-10-17

(其实文件里已经有了),修改 spider1.py,让它在打印标题之后,再打印出发布日期。

提示:p 盒子就在 h1 旁边,用 soup.find("p") 就能拿到。这题是为下一题热身——从”抓固定几样”到”抓任意几样”,其实只差一个 find。

练习3(动脑题):给”抓全校课表”写需求。假设学校网站上有一个课表页面(想象它有

、每周七天、每天五六节课),把你要跟AI说的需求写下来:目标、网页结构、输出格式(存成CSV还是直接打印)、可能出什么错。写得越具体越好。

提示:对照第一节那段”参考需求”的结构写——目标、结构、输出、容错,四要素齐了就是好需求。写完留着,下一篇(提取表格数据)你把这段话直接粘给AI,多半一次就能用。

下篇预告

下一篇(第42篇):提取表格数据 — 把真正的”一张大表”完整搬回家。今天你抓的是三行小表,下一篇上强度:多列的表格、带表头的表格、合并单元格的表格,还要让程序自动”数一数表里有几行几列”。套路不变(find + get_text),变的是”按图索骥”的图更复杂一点。你今天已经拿到了钥匙,下一篇练的是开更多种锁。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注