第13讲 晟品案 vs 元光案:两个"爬虫入刑"标杆的深度技术复盘

0 阅读4分钟

学习目标

跟随架构师律师马原的脚步读完这一讲,你能:

  1. 理解两个标杆案件的技术差异和法律后果
  2. 掌握"经济损失"的计算方法论
  3. 学会给自己的爬虫行为做法律体检

技术原理

晟品案技术还原

被告单位:上海晟品网络科技有限公司

目标:字节跳动服务器的视频数据

技术手段:

# 技术还原(基于判决书描述)

# 1. 伪造 device_id 绕过身份校验
fake_device_id = generate_random_device_id()
headers['X-Device-Id'] = fake_device_id

# 2. 伪造 User-Agent 伪装成浏览器
headers['User-Agent'] = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1)...'

# 3. 伪造 IP 地址绕过频率限制
# 通过代理池轮换 IP
proxy = get_next_proxy()

# 4. 发送请求获取视频数据
resp = requests.get(
    'https://api.example.com/videos',
    headers=headers,
    proxies={'http': proxy}
)

法院认定的关键事实:

  • "伪造 device_id 绕过服务器的身份校验"
  • "伪造 User-Agent 及 IP 地址绕过访问频率限制"
  • "造成被害单位经济损失两万元"

元光案技术还原

被告单位:武汉元光科技有限公司

目标:竞争对手"酷米客"的实时公交数据

技术手段:

元光做的是公交数据 APP。为了提升自己 APP 的数据质量,他们去爬了竞争对手酷米客的实时公交数据。技术上也是爬虫,但具体手段判决书披露较少,已知的是"通过技术手段绕过酷米客的反爬措施"。

两个案子的核心差异:

维度晟品案元光案
数据类型公开视频实时公交数据
突破措施User-Agent、device_id、IP 伪造反爬措施(具体不明)
经济损失2万元未公开
刑期1-2年缓刑3年缓刑(法定代表人)
社会影响被媒体广泛报道相对低调

法律分析

"公开数据入刑"的争议

晟品案最大的争议点是:视频内容是公开的,普通用户不登录也能看到。为什么公开数据也能入刑?

法院的逻辑是:数据是不是公开的,不影响"侵入"的认定。关键看的是手段——你有没有突破安全措施。

这个逻辑在学术界有很多批评。西南政法大学石经海教授在《北京理工大学学报》发表文章,认为将爬取公开数据认定为侵犯数据保密性,是把数据安全法益错误定位为"数据载体保护",会加重数据犯罪的口袋化趋势。

但司法实践的趋势是:手段优先于对象。你伪造了身份,绕过了限制,就是"侵入"。数据公不公开,是量刑时的参考因素,不是定罪的决定因素。

经济损失的计算

两高司法解释:造成经济损失一万元以上,达到非法获取计算机信息系统数据罪的立案标准。

"经济损失"包括:

  • 恢复系统、加固安全的费用
  • 调查取证的费用
  • 因数据被非法获取造成的直接经济损失

晟品案的经济损失只有两万元——技术服务费。这个金额在刑事犯罪里算很低的,但已经足够立案。

我做辩护的时候,会逐项审查经济损失的构成。安全加固费用是不是"必要"的?律师费和鉴定费是不是"合理"的?把这些水分挤掉,有时候能把经济损失打到立案标准以下。


实战输出:爬虫行为法律体检模板

"""
爬虫行为法律体检
给你的爬虫做一次全面的法律风险评估
"""

class CrawlerLegalCheckup:
    def __init__(self, crawler_config):
        self.config = crawler_config
        self.findings = []
        self.recommendations = []
    
    def check_authentication(self):
        """检查身份认证相关行为"""
        if self.config.get('forges_user_agent'):
            self.findings.append("伪造 User-Agent")
            self.recommendations.append("改用诚实身份声明,包含真实联系信息")
        
        if self.config.get('forges_device_id'):
            self.findings.append("伪造设备标识")
            self.recommendations.append("停止伪造设备标识,考虑使用官方API")
        
        if self.config.get('uses_proxy_rotation'):
            self.findings.append("使用代理IP轮换")
            self.recommendations.append("确保代理来源合法,保留代理服务商协议")
    
    def check_rate_limiting(self):
        """检查频率限制相关行为"""
        freq = self.config.get('requests_per_second', 1)
        if freq > 10:
            self.findings.append(f"请求频率过高 ({freq} req/s)")
            self.recommendations.append("降低频率至人类正常浏览水平 (< 1 req/s)")
        
        if not self.config.get('respects_crawl_delay'):
            self.findings.append("不遵守 Crawl-delay")
            self.recommendations.append("解析并遵守目标站点的 robots.txt Crawl-delay")
    
    def check_data_scope(self):
        """检查数据获取范围"""
        if self.config.get('fetches_personal_info'):
            self.findings.append("获取个人信息")
            self.recommendations.append("立即停止,评估是否触犯侵犯公民个人信息罪")
        
        if self.config.get('fetches_copyrighted_content'):
            self.findings.append("获取受著作权保护的内容")
            self.recommendations.append("获得授权或转型为分析服务")
    
    def check_business_model(self):
        """检查业务模式"""
        if self.config.get('business_model') == 'aggregation':
            self.findings.append("聚合展示模式")
            self.recommendations.append("评估是否构成实质性替代,考虑转型为分析服务")
        
        if self.config.get('business_model') == 'resale':
            self.findings.append("数据转售模式")
            self.recommendations.append("极高风险,建议立即停止")
    
    def run_checkup(self):
        print("=== 爬虫行为法律体检 ===\n")
        
        self.check_authentication()
        self.check_rate_limiting()
        self.check_data_scope()
        self.check_business_model()
        
        if self.findings:
            print(f"发现 {len(self.findings)} 项风险行为:")
            for i, finding in enumerate(self.findings, 1):
                print(f"\n{i}. ⚠ {finding}")
                print(f"   建议: {self.recommendations[i-1]}")
        else:
            print("✅ 未发现明显风险行为")
        
        return len(self.findings) == 0

# 使用示例
checkup = CrawlerLegalCheckup({
    'forges_user_agent': True,
    'forges_device_id': False,
    'uses_proxy_rotation': True,
    'requests_per_second': 15,
    'respects_crawl_delay': False,
    'fetches_personal_info': False,
    'fetches_copyrighted_content': True,
    'business_model': 'aggregation',
})
checkup.run_checkup()