数据采集策略:结构化数据采集、非结构化数据采集、API数据采集、爬虫基础与伦理
数据采集,说白了就是给AI找吃的。没有数据,再牛的模型也是空壳。我见过太多团队,模型架构抄得飞起,结果卡在数据采集这一步,一卡就是几个月。
这一章,咱们把四种主流采集策略掰开揉碎讲清楚。嗯,都是我在项目里踩过坑、填过土之后沉淀下来的经验。
一、结构化数据采集
结构化数据,就是那种规规矩矩躺在数据库里的东西。行是行,列是列,像Excel表格一样整齐。
最常见的来源:
- 关系型数据库(MySQL、PostgreSQL、Oracle)
- 数据仓库(Snowflake、Redshift、BigQuery)
- 业务系统导出的CSV/Excel文件
采集方式:
- 全量采集:一次性把整张表拉过来。适合小表或首次初始化。
- 增量采集:只拿新增或变更的数据。靠时间戳或自增ID做标记。
- CDC(Change Data Capture):监听数据库的binlog,实时捕获变更。适合高实时性场景。
我的习惯:做增量采集时,千万别只依赖时间戳。我曾经遇到一个系统,时间戳精度只到秒,同一秒内写入两条数据,第二条就漏了。后来我改成「时间戳 + 自增ID」双字段兜底,再也没丢过数据。
代码示例:Python + MySQL 增量采集
import pymysql
import pandas as pd
def incremental_fetch(last_id, last_time):
conn = pymysql.connect(host='localhost', user='root', password='pass', db='ai_platform')
sql = """
SELECT * FROM user_behavior
WHERE (create_time > %s) OR (create_time = %s AND id > %s)
ORDER BY create_time, id
LIMIT 10000
"""
df = pd.read_sql(sql, conn, params=(last_time, last_time, last_id))
conn.close()
return df
二、非结构化数据采集
非结构化数据,就是那些「不听话」的数据。文本、图片、音频、视频……没有固定格式,处理起来麻烦得多。
常见类型与采集要点:
| 数据类型 | 采集方式 | 注意事项 |
|---|---|---|
| 文本(PDF/Word/HTML) | 解析库提取(PyPDF2、python-docx、BeautifulSoup) | 编码问题、表格结构丢失 |
| 图片 | HTTP下载 + 哈希去重 | 分辨率、格式统一、版权 |
| 音频 | 流式录制或文件批量导入 | 采样率统一、降噪预处理 |
| 视频 | ffmpeg抽帧 + 音频分离 | 存储成本、关键帧提取策略 |
避坑指南:我曾经处理一批PDF合同,用PyPDF2解析出来全是乱码。折腾了两天才发现,那些PDF是扫描件,根本不是文本PDF。后来老老实实先调OCR接口,再解析。记住:先搞清楚文件「真实格式」,再选工具。
三、API数据采集
API采集,就是跟第三方系统「对话」。你发请求,它给数据。现在大部分SaaS平台都提供RESTful API或GraphQL接口。
核心要点:
- 认证方式:、OAuth 2.0、JWT。别把密钥硬编码在代码里,用环境变量或密钥管理服务。
- 限流处理:大部分API都有速率限制(Rate Limit)。我习惯用「令牌桶」算法做本地限流,配合指数退避重试。
- 分页策略:游标分页优于偏移分页。偏移分页在数据量大时性能急剧下降。
- 数据一致性:API返回的数据可能有时延。做增量同步时,加一个「数据时间窗口」做缓冲。
代码示例:带限流的API采集
import time
import requests
from ratelimit import limits, sleep_and_retry
@sleep_and_retry
@limits(calls=100, period=60) # 每分钟最多100次
def fetch_api_data(url, headers, params):
resp = requests.get(url, headers=headers, params=params, timeout=30)
if resp.status_code == 429:
retry_after = int(resp.headers.get('Retry-After', 5))
time.sleep(retry_after)
return fetch_api_data(url, headers, params)
resp.raise_for_status()
return resp.json()
个人经验:有一次对接某社交平台的API,文档说限流是「每小时1000次」。结果上线第一天,跑了半小时就被封了。后来一查,人家是按「每个Access 」算的,不是按「每个IP」。嗯,读文档一定要读到「小字」部分。
四、爬虫基础与伦理
爬虫,就是自己动手写程序抓网页数据。听起来很酷,但坑也多。
爬虫基础流程:
- 发送请求:用requests或aiohttp模拟浏览器访问。
- 解析响应:HTML用BeautifulSoup或lxml,JSON直接解析。
- 数据提取:CSS选择器或XPath定位目标元素。
- 数据存储:写入数据库或文件。
- 异常处理:网络超时、IP被封、验证码……
反爬应对策略:
- 设置合理的User-Agent和Referer
- 使用代理IP池,轮换出口
- 控制请求频率,加随机延时
- 处理JavaScript渲染的页面,用Selenium或Playwright
伦理与法律红线:爬虫不是想爬就爬的。我见过有同行因为爬取竞品价格数据,被起诉赔了几十万。记住三条底线:
1. 遵守robots.txt协议
2. 不爬取个人隐私数据(手机号、身份证、密码)
3. 不破坏目标网站的正常服务(别把人家的服务器爬挂了)
1. 遵守robots.txt协议
2. 不爬取个人隐私数据(手机号、身份证、密码)
3. 不破坏目标网站的正常服务(别把人家的服务器爬挂了)
代码示例:简单爬虫框架
import requests
from bs4 import BeautifulSoup
import time
import random
def crawl_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
try:
resp = requests.get(url, headers=headers, timeout=10)
resp.encoding = resp.apparent_encoding
soup = BeautifulSoup(resp.text, 'lxml')
# 提取数据逻辑
titles = soup.select('h2.article-title')
return [t.get_text(strip=True) for t in titles]
except Exception as e:
print(f'抓取失败: {url}, 错误: {e}')
return []
# 控制频率
time.sleep(random.uniform(1, 3))
五、四种策略如何选?
你想想看,实际项目中往往不是只用一种策略。我通常这样判断:
- 有数据库权限 → 结构化采集(最快最稳)
- 有开放API → API采集(最规范)
- 只有网页 → 爬虫(最后的选择)
- 文件散落各处 → 非结构化采集
说白了,能走API就别爬,能连数据库就别绕弯。数据采集的终极目标不是「拿到数据」,而是「稳定、合规、可复用地拿到数据」。
核心原则:采集策略的选择,取决于数据源的「可控程度」和「更新频率」。可控程度高、更新频繁的,优先走API或CDC;可控程度低、一次性采集的,爬虫也能凑合。但不管选哪种,先把「数据血缘」和「采集日志」做好——出了问题,你能快速定位是采集层的问题,还是上游的问题。