3、数据采集:内部数据源识别、外部数据源接入、API数据采集、爬虫策略与合规
数据采集这件事,说白了就是给项目找「食材」。我见过太多项目,算法模型调得再漂亮,最后因为数据源没搞定,整个项目直接烂尾。所以这一章,咱们把数据采集的四个核心环节掰开揉碎讲清楚。
3.1 内部数据源识别:先别急着往外跑
很多人一上来就想着去外面找数据,其实公司内部的数据往往是最值钱的。我个人习惯,接手一个项目后,第一件事不是写代码,而是拿着小本本去各个部门串门。
内部数据源通常藏在哪?
- 业务数据库:MySQL、Oracle、PostgreSQL,存着订单、用户、交易记录。这是最核心的资产。
- 日志系统:Nginx访问日志、应用日志、用户行为埋点。我在项目中遇到过,有一次做用户流失预测,业务库里的数据只有注册信息,真正有价值的是埋点日志里的点击流数据。
- 数据仓库/数据湖:如果公司有数仓,那恭喜你,很多脏活已经有人干完了。但要注意,数仓里的数据通常是聚合过的,有时候粒度不够细。
- 文件服务器/共享目录:Excel报表、CSV导出、PDF报告。嗯,这里要注意,这些非结构化数据往往被忽视,但里面可能藏着业务部门手工维护的「独家数据」。
我的小技巧:先画一张「数据地图」,把每个数据源的位置、负责人、更新频率、数据量级都列出来。这张图比任何代码都重要。
3.2 外部数据源接入:借力打力
内部数据不够用怎么办?那就得从外面找。外部数据源接入,我把它分成三类:
| 类型 | 典型例子 | 接入方式 | 注意事项 |
|---|---|---|---|
| 开放数据集 | 政府公开数据、行业报告 | HTTP下载、FTP同步 | 数据质量参差不齐,需要大量清洗 |
| 商业数据服务 | 天眼查、高德地图、气象数据 | API接口、SDK集成 | 按调用量收费,注意预算控制 |
| 合作方数据 | 上下游企业、联盟成员 | 数据库直连、文件交换 | 数据安全协议、脱敏要求 |
我曾经对接过一个气象数据服务商,对方给的API文档写得像天书,返回的JSON字段名全是缩写。后来我写了个适配层,把字段名映射成中文,团队其他人看着才不懵。说白了,外部数据接入不只是技术活,更是沟通活。
3.3 API数据采集:最优雅的方式
API采集,是数据工程师的「体面活」。不用跟反爬斗智斗勇,不用考虑IP被封,只要按文档调接口就行。但这里有几个坑,我踩过,你们别踩。
API采集的核心流程:
- 认证与鉴权:API Key、OAuth2.0、JWT。我建议把密钥统一存在配置中心或环境变量里,别硬编码在代码中。
- 限流与重试:大部分API都有QPS限制。我习惯用「令牌桶」算法做本地限流,配合指数退避重试策略。
- 分页与全量拉取:很多API默认只返回前20条。记得检查是否有
next_page_token或offset参数。 - 数据校验与落盘:拿到数据后,先做字段完整性校验,再写入临时表或文件。
代码示例:一个健壮的API采集模板
import requests
import time
from tenacity import retry, stop_after_attempt, wait_exponential
class APICollector:
def __init__(self, api_key, base_url):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({"Authorization": f"Bearer {api_key}"})
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def fetch_page(self, endpoint, params=None):
response = self.session.get(f"{self.base_url}/{endpoint}", params=params)
response.raise_for_status()
return response.json()
def collect_all(self, endpoint, page_size=100):
all_data = []
page_token = None
while True:
params = {"page_size": page_size}
if page_token:
params["page_token"] = page_token
data = self.fetch_page(endpoint, params)
all_data.extend(data.get("items", []))
page_token = data.get("next_page_token")
if not page_token:
break
time.sleep(0.5) # 限流,每秒最多2次请求
return all_data
避坑指南:我曾经对接一个金融数据API,对方文档说「返回JSON格式」,结果某天突然返回了XML。从那以后,我每次采集都会加一个响应格式校验,发现异常立刻告警。
3.4 爬虫策略与合规:别把自己送进去
爬虫这块,技术难度其实不大,真正难的是合规。我见过有人因为爬虫被发律师函,也见过整个团队因为数据合规问题被约谈。所以这一节,咱们重点聊「怎么安全地爬」。
爬虫策略的核心原则:
- 尊重 robots.txt:这是最基本的礼貌。我习惯在爬虫启动前先解析目标网站的 robots.txt,把禁止爬取的路径自动过滤掉。
- 控制频率:别把人家服务器打挂了。我一般设置每次请求间隔 1-3 秒,高峰期甚至拉到 5 秒以上。
- User-Agent 伪装:别用默认的 Python-urllib,容易被封。用常见的浏览器 UA,或者随机轮换。
- IP 代理池:大规模采集必备。但注意,别用免费代理,那些大多是陷阱。
合规红线(划重点):
| 行为 | 风险等级 | 说明 |
|---|---|---|
| 爬取公开数据(新闻、天气) | 低风险 | 但要注意网站的使用条款 |
| 爬取需要登录的数据 | 中风险 | 可能违反计算机信息系统安全保护条例 |
| 爬取个人隐私数据(手机号、地址) | 高风险 | 涉嫌侵犯公民个人信息罪 |
| 绕过反爬机制(破解验证码、模拟登录) | 极高风险 | 可能构成非法获取计算机信息系统数据罪 |
我的合规检查清单:
- 目标数据是否属于「公开信息」?
- 网站是否有明确的「禁止爬取」声明?
- 爬取的数据是否会涉及第三方权益?
- 采集后的数据是否做了脱敏处理?
- 是否有法务或合规部门的书面确认?
这五条,有一条不满足,我建议你停下来跟法务聊一聊。
嗯,说到爬虫,我想起一个真实案例。有个同事为了做竞品分析,写了个爬虫去爬竞争对手的商品价格。结果对方网站有反爬,他就用代理IP池加随机UA去绕。最后数据是拿到了,但对方直接报警,因为那些价格数据属于商业机密。所以你看,技术能解决的问题,法律不一定能解决。
最后总结一句:数据采集不是「拿到就行」,而是「合法、合规、高质量地拿到」。下一章咱们聊数据清洗,那才是真正考验耐心的环节。