你有没有过这种经历:想分析某个公开网站上的数据,结果手动复制粘贴到Excel里,一干就是一下午。以前我遇到这种情况的第一反应是自己写爬虫,但每次一写就是两天:环境装了又崩,页面结构看半天,好不容易跑通,网站一改版又白干。最近半年我把这套流程搬到了AI Studio里,用AI辅助生成和调试代码,慢慢形成了一套“让数据自己来”的自定义爬虫搭建方法。这篇文章就把这套方法完整拆开,从需求拆解、代码生成、页面解析、数据入库,到最后的定时调度和踩坑记录,一次性讲清楚。不管你是做数据分析、市场调研,还是个人项目,只要你有“把某个网站上的公开数据变成结构化数据”的需求,这篇文章都值得你花十分钟看完。
1. AI Studio 到底帮爬虫开发者解决了什么
1.1 各种AI Studio的共同逻辑
如果你搜过“AI Studio”这个词,会发现它背后其实有一堆兄弟。STM32Cube.AI 是嵌入式领域的AI开发工具,负责把训练好的神经网络模型转换成能在单片机上运行的代码;Android Studio 现在也内置了不少AI辅助能力,可以在你写安卓应用时自动补全代码块;Spring AI Alibaba Studio 则是Java生态里把大模型能力接进后端服务的一套开发体验。它们名字都叫Studio,但内核一致:一个完整的开发环境,加上内嵌的大模型能力,让开发者少写重复代码、少查文档、更快定位问题。
我在这里说的AI Studio,也是同一个逻辑,只不过换成了适合数据采集的形态:一个在线Notebook环境,能用Python写代码、能直接运行查看结果,同时旁边挂着AI对话助手。你描述需求,它生成代码;你把报错丢给它,它给出修复建议。爬虫这种试错成本高、重复模式又多的任务,恰好是这套组合最擅长的场景之一。
1.2 爬虫这种“边写边扔”的代码,正好是AI的主场
很多人觉得爬虫很难,其实难的不是代码本身,而是面对不同网站时无休止的适配。业务系统讲究长期维护、结构稳定,但爬虫经常是“对付”一个网站,换目标就换代码。大量工作都是样板式的:发一次请求、拿回HTML、选节点、存数据、换下一页。这种模板化极强的代码,让AI来生成几乎是降维打击。
更关键的是,爬虫调试过程极度需要即时反馈。在传统开发环境里,你写错一个XPath,得查半天文档、试好几轮才能定位。在AI Studio里,我一般直接把报错信息和当前网页的片段丢给AI,让它给出改好的解析逻辑,然后我在Notebook里运行一次就能看到结果。省去了本地配环境、装依赖、处理Python版本冲突这些琐碎事,整个开发节奏快了一个量级。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 把需求翻译成 AI 能执行的工程指令
2.1 先定义采集对象和数据字段
用AI Studio最忌讳的一件事,就是上来就说“帮我写个爬虫”。AI不是玄学,你想要什么,必须先在脑子里过一遍需求。我每次动手前都会强制自己回答几个问题:
- 目标页面的URL是什么?
- 要抓列表,还是详情页?还是列表加详情?
- 最终要保存哪些字段?每个字段什么类型?
- 更新频率是多少?是一次性抓完,还是每天增量?
举个例子,我想抓某个技术博客的公开文章列表,需求表大概是这样:
| 项目 | 内容 |
|---|---|
| 目标URL | https://example.com/blog |
| 采集范围 | 文章列表页的所有卡片 |
| 字段 | title、url、publish_date、summary、author |
| 输出格式 | CSV文件,UTF-8编码 |
| 更新频率 | 每天一次 |
别小看这个步骤。把需求想清楚之后,后面给AI的指令才会有信息量,AI生成的代码也才真的能跑、贴近你想要的结构。
2.2 一条能落地的提示词长什么样
很多新手用AI写代码效果差,问题不在AI,而在提示词太模糊。我之前试过只说“抓取文章”,AI确实生成了代码,但字段对不上、编码乱掉、没有限速,基本不能用。后来我把提示词写成了工程式描述,效果立刻不一样。
下面这条是我比较常用的模板:
text复制你是Python爬虫工程师。请帮我抓取 https://example.com/blog 上公开的技术文章列表。
要求如下:
1. 使用 requests 和 BeautifulSoup,不依赖浏览器自动化;
2. 解析每一篇文章卡片的 title、url、publish_date、summary、author;
3. 请求头带上常见浏览器 User-Agent;
4. 每次请求后随机等待1到3秒;
5. 最后把解析结果保存成 articles.csv,编码为 UTF-8,字段顺序固定;
6. 代码要能直接运行,遇到单条数据缺失时跳过而不是报错。
把URL、库、输出格式、编码、请求间隔、异常处理方式全部写清楚,AI生成的第一版代码大概率能直接跑。如果语言太笼统,它只能给你一个泛泛的框架,你还要花大量时间补细节。
2.3 第一版爬虫代码的生成与运行
把上面的提示词贴给AI Studio里的对话助手,它会生成类似下面这样的代码。我也把这段代码贴在这里,你可以直接参考:
python复制import requests
from bs4 import BeautifulSoup
import csv
import random
import time
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
def fetch_articles():
url = "https://example.com/blog"
resp = requests.get(url, headers=HEADERS, timeout=10)
resp.encoding = "utf-8"
soup = BeautifulSoup(resp.text, "lxml")
articles = []
for card in soup.select(".post-card"):
title_node = card.select_one(".post-title")
link_node = card.select_one("a")
date_node = card.select_one(".post-date")
summary_node = card.select_one(".post-summary")
author_node = card.select_one(".post-author")
if not title_node or not link_node:
continue
articles.append({
"title": title_node.get_text(strip=True),
"url": link_node.get("href"),
"publish_date": date_node.get_text(strip=True) if date_node else "",
"summary": summary_node.get_text(strip=True) if summary_node else "",
"author": author_node.get_text(strip=True) if author_node else "",
})
return articles
if __name__ == "__main__":
data = fetch_articles()
with open("articles.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["title", "url", "publish_date", "summary", "author"])
writer.writeheader()
writer.writerows(data)
print(f"抓取完成:{len(data)} 条")
在AI Studio里新建一个Notebook,把代码放进去运行,看到“抓取完成”的日志,第一版就算通了。但注意,这个阶段只是“能跑”,不代表“跑得对”。AI生成的CSS选择器,比如.post-card,只是根据你给的信息猜的,真实页面可能完全不一样。所以下一步才是重头戏。
3. 解析与反爬:AI 生成的选择器,为什么必须亲手验证
3.1 静态页面的XPath/CSS选择器调校
AI生成的选择器选不中、选多、选错,是最常见的问题。原因很简单:AI没看过真实页面的HTML结构,它只能根据经验猜。以前遇到这种情况,我只能自己对着开发者工具一点点试,现在则变成了“AI猜一个版本 → 我拿真实页面验证 → 不对就把HTML片段喂回去让它重写”。
验证方法其实不难。打开浏览器开发者工具,在目标元素上右键,选“检查”,再在元素上右键复制CSS选择器或完整XPath。把复制出来的东西和AI生成的对一下,通常就能看出问题。比如AI写成.post-card,但真实页面是.article-item,那直接把真实选择器替换进去就行。
还有一类问题是class名称不稳定。现在很多前端框架会动态生成哈希类名,比如.css-1a2b3c,今天能选中,明天就失效。遇到这种情况,我一般会改成用更稳定的属性定位,比如article[data-id],或者先定位整个列表容器再逐项遍历。下面这段代码就是调整后的版本片段:
python复制for card in soup.select("div.blog-list > article.item"):
title = card.select_one("h2.title a")
if title:
print(title.get_text(strip=True), title["href"])
核心思路是:AI负责生成初稿,你负责用真实页面校准。两者配合,解析效率比纯手工高很多。
3.2 动态页面优先找接口,而不是模拟浏览器
很多网站现在的页面都是JavaScript渲染出来的,直接拿requests请求HTML,得到的只是一堆空壳,什么数据都解析不到。遇到这种页面,新手容易一上来就上Selenium模拟浏览器。不是说不行,但代价很高:响应慢、资源占用大、更容易触发对方的风控,而且AI生成的Selenium代码也更容易因为等待时间、元素定位等问题跑挂。
我的做法是先打开开发者工具的Network面板,刷新页面,看有没有返回JSON的XHR接口。绝大多数网站的数据都是通过接口拉回来的,页面只是把JSON渲染成好看的样子。找到接口之后,把接口URL、请求参数和一段返回样例贴给AI,让它直接用requests请求接口解析JSON。这种方式又快又稳。
python复制import requests
api_url = "https://example.com/api/articles"
params = {"page": 1, "pageSize": 20}
resp = requests.get(api_url, params=params, timeout=10)
data = resp.json()
for item in data.get("items", []):
print(item["title"], item["publishTime"])
这种方式下,选择器的问题基本消失了,解析逻辑变成了简单的字段映射。而且接口字段通常是稳定命名的,比HTML的类名可靠得多。
3.3 请求节奏、请求头与合规边界
爬虫能不能稳定跑,很大程度上取决于你的请求节奏。过于礼貌、每秒只请求一次,一万条数据要跑几个小时;过于暴力、一秒钟几十个请求,大概率触发封禁,还可能给对方服务器带来压力。我在AI Studio里常用的办法是让AI生成随机延时,比如这样:
python复制import random
import time
# 每次请求后随机休息1~3秒,模拟真实用户的浏览节奏
time.sleep(random.uniform(1, 3))
请求头方面,至少要带上一个常见的浏览器UA。但不要过度伪装,更不要伪造身份去突破访问限制。如果一个网站通过robots.txt明确声明不允许抓取某个路径,或者需要登录才能看到的内容,那就别碰。我的原则是:只采集公开、合法、无需身份验证的数据;请求频率以不影响目标站正常服务为底线;采集后不把涉及个人隐私的数据直接公开。
4. 数据清洗、去重和落库的自动化
4.1 用AI生成通用清洗函数
抓回来的数据永远不会直接干净。日期格式五花八门、正文里带着HTML标签、栏目节点里混着不可见字符,这些都太常见了。以前这些清洗逻辑要一行一行写,现在只需要把一两条脏数据样例丢给AI,让它总结规则并生成函数。
比如日期可能是“2025年1月5日”“2025-01-05”“05 Jan 2025”三种格式混在一起,AI会生成类似这样的统一函数:
python复制import re
from datetime import datetime
def normalize_date(raw):
if not raw:
return ""
raw = raw.strip()
patterns = [
"%Y年%m月%d日",
"%Y-%m-%d",
"%d %b %Y",
]
for pattern in patterns:
try:
return datetime.strptime(raw, pattern).strftime("%Y-%m-%d")
except ValueError:
continue
return raw
清洗阶段我给AI的自由度最高,因为它不涉及具体页面结构,规则相对通用,生成的函数通常能直接用。
4.2 增量抓取和去重的关键设计
如果只跑一次,去重并不重要。但如果你像我一样设置了每天定时抓取,每次全量重抓会产生大量重复数据,后续分析全是坑。我个人习惯是用URL作为唯一键,维护一个“已采集集合”,每次抓取前先检查当前URL是否已经存在。
如果用SQLite,可以直接靠唯一约束解决。建表时给url加上UNIQUE,插入时用INSERT OR IGNORE,重复数据自然进不来。
python复制import sqlite3
conn = sqlite3.connect("articles.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT UNIQUE,
title TEXT,
publish_date TEXT,
summary TEXT,
author TEXT
)
""")
conn.execute("""
INSERT OR IGNORE INTO articles (url, title, publish_date, summary, author)
VALUES (?, ?, ?, ?, ?, ?)
""", (item["url"], item["title"], item["publish_date"], item["summary"], item["author"]))
conn.commit()
这个方案看着简单,但能解决增量抓取里90%的问题。剩下10%是内容更新了但URL没变的情况,这时候就需要再维护一个updated_at字段,比对文章内容摘要是否变化,按需覆盖更新。
4.3 SQLite够用,什么时候该换MySQL/PG
存储选型这件事,我的经验是先看数据量和并发,再看使用场景。
| 选型 | 适用场景 | 说明 |
|---|---|---|
| CSV | 一次性采集、数据量几千条 | 最简单,Excel能直接打开 |
| SQLite | 个人项目、数据量十万以内 | 单文件、零配置,支持SQL |
| MySQL | 多人协作、需要并发写入 | 安装和维护成本略高 |
| PostgreSQL | 复杂查询、GIS数据、JSON字段多 | 功能最全面,适合数据分析 |
如果你只是自己分析数据,SQLite是最佳选择,一个文件拷到哪里都能用。但如果你要搭一个数据看板给团队用,或者多个采集脚本同时写库,那我建议直接上MySQL或PostgreSQL,省得后面迁移数据。
5. 让爬虫自己跑起来:调度、重试、监控和改版应对
5.1 定时任务在AI Studio里的可行方案
AI Studio的在线Notebook有一个天然限制:它不会像你的电脑一样一直开着。你关了浏览器,进程就断了。所以要想真正实现“数据自己来”,必须把采集脚本以某种方式定时跑起来。
我的做法分三种情况。第一种,平台如果提供定时运行功能,直接把Notebook导出为.py脚本,配置好运行时间和运行环境。第二种,如果你在自己的服务器或电脑上跑,就写个crontab任务:
bash复制0 8 * * * cd /path/to/project && python crawl.py >> crawl.log 2>&1
第三种,如果想在脚本内部自己管理调度,用APScheduler,它会像一个轻量级的常驻程序一样按计划执行任务。
python复制from apscheduler.schedulers.blocking import BlockingScheduler
def job():
print("开始采集任务")
# 这里调用你的采集主函数
scheduler = BlockingScheduler()
scheduler.add_job(job, "cron", hour=8, minute=0)
scheduler.start()
定时任务最怕的不是不执行,而是执行一半挂了,你完全不知情。所以后面两个问题必须一起解决。
5.2 重试、超时与完成通知
网络请求不是每次都成功,目标服务器偶尔超时、偶尔连接重置,太正常了。我的习惯是给请求加一个重试机制,用指数退避的方式,第一次失败等2秒,第二次等4秒,最多试3次。
python复制import time
import requests
def request_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
try:
resp = requests.get(url, headers=headers, timeout=10)
resp.raise_for_status()
return resp
except requests.RequestException as e:
wait = 2 ** attempt
print(f"请求失败,{wait}秒后重试:{e}")
time.sleep(wait)
raise RuntimeError(f"请求最终失败:{url}")
采集完成后,我还会让它通过Webhook往群里发一条消息,内容包括本次采集数量、新增数量、是否有失败记录。这样每天早上打开手机就知道昨晚的任务跑得怎么样,不用登录平台一个个看日志。现在的企业微信、钉钉、飞书都支持简单的Webhook机器人,代码量很小,但回报极高。
5.3 网站一改版,解析规则怎么快速续命
爬虫最怕的就是网站改版。辛辛苦苦跑了一个月的脚本,突然某天开始解析不到数据,或者直接报错。我以前遇到这种情况会对着开发者工具看好久,现在反而淡定多了,因为AI能把改版适配的时间压得很短。
第一步,把报错信息完整复制下来,尤其注意Traceback里指向的是哪个解析步骤。第二步,打开网页源码,复制一段真实页面里包含目标数据的HTML片段。第三步,把报错和HTML一起丢给AI,让它重写解析部分,而不是让它盲改。
前面第3节提到的“接口优先策略”在这里也很有用。如果页面是JS渲染的,优先解析XHR接口;接口通常比HTML稳定得多。改版时HTML可能重写得面目全非,但接口往往只是增减字段,影响范围小很多。
6. 实际跑了一个月后,我想提醒你的几件事
6.1 AI Studio 在线环境的资源限制
在线环境确实方便,但它不是一台永远开着的服务器。我遇到过几次这种坑:采集脚本跑到一半,Notebook会话因为长时间未操作被断开,已经抓了几千条数据,但因为没落盘,全丢了。所以后来我养成了几个习惯:
- 每抓一页就立刻写数据库或CSV,不攒到最后一次性写;
- 采集前先估算总请求数,如果网站页面多,拆成多个任务分批跑;
- 给脚本加断点续采逻辑,重启后从上次失败的位置继续,而不是从头开始。
在线环境适合开发调试和中小规模采集,但如果你要每天稳定跑大量数据,还是把它部署到自己的服务器或者云函数上更靠谱。
6.2 给 AI 贴错误信息,而不是让它盲改
用AI辅助写爬虫,最容易犯的错误是反复说“帮我重写一下”“还是不对”。这就像你去看病,只跟医生说“我不舒服”,却不描述具体症状,医生也只能猜。正确做法是把Traceback、出错的代码片段、以及一小段页面HTML原封不动贴给AI,然后明确告诉它“只修改解析部分,其他逻辑保持不动”。
我自己的经验是,一次只让它改一个问题。如果页面解析和编码都有问题,先解决编码,再解决解析。问题混在一起丢给它,AI容易改一个坏一个。改完后让它解释“改了什么、为什么这么改”,这样你也能逐渐积累自己的排错能力,而不是完全依赖工具。
6.3 爬虫的“度”怎么把握
最后想聊几句听起来像废话但很重要的话:能爬,不等于该爬。我做采集任务前,都会先确认三件事:数据是公开的,站点没有明确禁止自动访问,采集频率不会给对方造成压力。涉及个人隐私的内容、需要登录才能看到的内容、明显是商业数据库的内容,我一律不碰。
这不是唱高调,而是从实用角度考虑。数据采集本来就是为了提高效率,如果因为过度采集导致IP被封、账户受限甚至惹上麻烦,反而是因小失大。合规这条线,任何时候都值得守住。
跑了一段时间之后,我最大的感受是:AI Studio把“会不会写爬虫”这个问题,变成了“会不会把需求说清楚”。以前我花很多时间调环境、记正则、试XPath,现在更多时间花在想清楚要采集哪些字段、怎么验证数据质量、以及守住合规边界。最后分享一个小技巧:我每次做采集都会把提示词和最终能跑的代码存成一个Markdown笔记,内容包括目标URL、字段表、选择器、注意事项。下次遇到结构类似的网站,直接把提示词里的URL和字段替换掉,让AI再生成一版,半小时就能上线一个新的采集任务。这个习惯帮我省下了大量重复劳动,也让你真正拥有一个会不断积累的“私人爬虫助手”。
