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采集的核心流程:

  1. 认证与鉴权:API Key、OAuth2.0、JWT。我建议把密钥统一存在配置中心或环境变量里,别硬编码在代码中。
  2. 限流与重试:大部分API都有QPS限制。我习惯用「令牌桶」算法做本地限流,配合指数退避重试策略。
  3. 分页与全量拉取:很多API默认只返回前20条。记得检查是否有 next_page_tokenoffset 参数。
  4. 数据校验与落盘:拿到数据后,先做字段完整性校验,再写入临时表或文件。

代码示例:一个健壮的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 代理池:大规模采集必备。但注意,别用免费代理,那些大多是陷阱。

合规红线(划重点):

行为 风险等级 说明
爬取公开数据(新闻、天气) 低风险 但要注意网站的使用条款
爬取需要登录的数据 中风险 可能违反计算机信息系统安全保护条例
爬取个人隐私数据(手机号、地址) 高风险 涉嫌侵犯公民个人信息罪
绕过反爬机制(破解验证码、模拟登录) 极高风险 可能构成非法获取计算机信息系统数据罪

我的合规检查清单:

  1. 目标数据是否属于「公开信息」?
  2. 网站是否有明确的「禁止爬取」声明?
  3. 爬取的数据是否会涉及第三方权益?
  4. 采集后的数据是否做了脱敏处理?
  5. 是否有法务或合规部门的书面确认?

这五条,有一条不满足,我建议你停下来跟法务聊一聊。

嗯,说到爬虫,我想起一个真实案例。有个同事为了做竞品分析,写了个爬虫去爬竞争对手的商品价格。结果对方网站有反爬,他就用代理IP池加随机UA去绕。最后数据是拿到了,但对方直接报警,因为那些价格数据属于商业机密。所以你看,技术能解决的问题,法律不一定能解决。

最后总结一句:数据采集不是「拿到就行」,而是「合法、合规、高质量地拿到」。下一章咱们聊数据清洗,那才是真正考验耐心的环节。