第1讲 爬虫不是简单的"发请求":一个 HTTP GET 技术原理与请求背后的法律定性

0 阅读7分钟

学习目标

读完这一讲,你能:

  1. curl -v 拆解一个爬虫请求的完整协议栈
  2. 理解同样的 GET 请求,为什么技术上一样,法律上不同
  3. 运行一个"合规探测脚本",自动检查目标站点的法律声明

技术原理

很多教程教爬虫的第一行代码是这样的:

import requests
resp = requests.get('https://测试网站.cn')
print(resp.status_code)

看起来人畜无害。但当你把这行代码放进一个 for 循环里,让它每秒跑十次、一百次,同时把响应存进数据库的时候,这件事的法律性质就变了。

我们用 curl -v 看一个请求的完整链路:

curl -v https://测试网站.cn

输出里你能看到:DNS 解析 → TCP 三次握手 → TLS 握手 → HTTP 请求发送 → 服务器响应 → TCP 连接关闭。整个过程大约几百毫秒。浏览器做这件事和你用 Python 做这件事,在协议层面几乎没有任何区别。都是发一个 HTTP GET 请求,都带了 Host 头,都收到了 200 OK 响应。

区别在哪里?在请求的元数据里。

打开 Chrome DevTools,看一个正常浏览器访问测试网站时的请求头:

GET / HTTP/2
Host: 测试网站.cn
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate, br
Cookie: _ga=...; _gid=...; sessionid=...

这些头部信息在技术上叫"请求元数据",在法律上叫行为证据

User-Agent 声明了你的身份:我是一个 macOS 上的 Chrome 浏览器。Accept-Language 声明了你的语言偏好。Cookie 携带了你的会话状态。服务器根据这些信息,决定给你返回什么内容、要不要让你访问、要不要对你限流。

现在看一个典型爬虫的请求头:

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept': 'text/html,application/xhtml+xml,*/*;q=0.8',
}
resp = requests.get('https://example.com', headers=headers)

这个 User-Agent 是从网上抄的,目的是让服务器以为这是一个正常浏览器。但你的请求行为暴露了你——每秒十次、请求间隔固定到毫秒级、从不点击内链、从来不加载 CSS 和 JS。服务器端的反爬系统一眼就能识别出来。

然后服务器可能会返回 429(Too Many Requests),可能会封禁你的 IP,可能会弹出验证码。这时候如果你选择:换代理 IP、继续请求、破解验证码——你就从技术上的"自动化访问",滑向了法律上的"突破安全措施"。


真实判例

上海晟品网络科技有限公司案,(2017)京0108刑初2384号,北京海淀区人民法院2017年11月判决。

被告单位晟品公司,被告人张某、宋某、侯某某、郭某。案情是:用爬虫技术抓取字节跳动服务器中的视频数据。技术手段包括:伪造 device_id 绕过服务器的身份校验,伪造 User-Agent 和 IP 地址绕过访问频率限制。

法院认定:被告人采用"其他技术手段",获取计算机信息系统中存储的数据,造成被害单位经济损失两万元,构成非法获取计算机信息系统数据罪

两万元的经济损失——技术服务费。换来的是几个人的刑事案底。

这个案子的核心争议点是:抓取的视频数据是公开的,普通用户不登录也能看到。被告人辩护说,这和用户用浏览器看视频没有区别。法院没有采纳这个辩护理由。

法院的认定逻辑是:

  1. 目标网站设置了身份校验(device_id 验证)和频率限制(IP 限流)
  2. 被告人伪造了身份信息,绕过了这些措施
  3. 绕过措施的行为 = "采用其他技术手段"
  4. 经济损失超过一万元 = 情节严重
  5. 罪名成立

这个逻辑链条里,数据是不是公开的,在定罪环节没有被考虑。法院更关注的是手段,不是对象


法律分析

刑法第285条第二款:

违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。

"采用其他技术手段"是这里的关键。司法解释没有穷尽列举,但司法实践中已经形成了相对稳定的认定范围:

  • 破解密码或身份验证
  • 伪造身份标识(device_idUser-Agent、IP 地址)
  • 绕过访问频率限制
  • 利用系统漏洞

伪造 User-Agent 在技术人眼里就是改一个字符串。但在法庭上,这个字符串是你"身份声明"的一部分。你把"我是 Python requests"改成了"我是 Chrome 浏览器"——这是虚假身份声明。再结合你绕过了频率限制这个事实,法院就会认定你有"突破安全措施"的主观故意。


实战输出:合规探测脚本

以下是一个可以直接运行的脚本,输入 URL 后自动检查目标站点的 robots.txt、响应头安全策略、页面法律声明:

#!/usr/bin/env python3
"""
爬虫合规探测脚本 v1.0
用法: python crawler_legal_check.py https://example.com
"""
import sys
import urllib.robotparser
from urllib.parse import urlparse, urljoin
import requests

def check_robots_txt(base_url):
    """检查并解析 robots.txt"""
    parsed = urlparse(base_url)
    robots_url = f"{parsed.scheme}://{parsed.netloc}/robots.txt"
    rp = urllib.robotparser.RobotFileParser(robots_url)
    try:
        rp.read()
        print(f"\n[+] robots.txt 找到: {robots_url}")
        # 检查是否允许通用爬虫
        can_fetch = rp.can_fetch('*', '/')
        print(f"    是否允许根路径抓取: {'是' if can_fetch else '否'}")
        # 获取 crawl-delay
        delay = rp.crawl_delay('*')
        if delay:
            print(f"    建议抓取间隔: {delay} 秒")
        return rp
    except Exception as e:
        print(f"\n[-] robots.txt 读取失败: {e}")
        return None

def check_security_headers(url):
    """检查响应头中的安全策略"""
    try:
        resp = requests.get(url, timeout=10, headers={
            'User-Agent': 'CrawlerLegalCheck/1.0 (+https://your-site.com/bot)'
        })
        print(f"\n[+] HTTP 响应状态: {resp.status_code}")
        # 检查关键响应头
        headers_of_interest = [
            'X-Robots-Tag',
            'X-Frame-Options',
            'Content-Security-Policy',
            'X-RateLimit-Limit',
            'Retry-After',
        ]
        for h in headers_of_interest:
            val = resp.headers.get(h)
            if val:
                print(f"    {h}: {val}")
        return resp.text
    except Exception as e:
        print(f"\n[-] 请求失败: {e}")
        return None

def check_page_legal_notice(html):
    """扫描页面中的法律声明关键词"""
    if not html:
        return
    keywords = [
        '爬虫', 'spider', 'crawler', 'robots',
        '禁止', '未经授权', '用户协议', '服务条款',
        '数据抓取', '数据爬取', '自动化访问'
    ]
    found = []
    html_lower = html.lower()
    for kw in keywords:
        if kw in html_lower:
            found.append(kw)
    if found:
        print(f"\n[!] 页面中发现法律相关关键词: {', '.join(found)}")
        print("    ⚠ 建议仔细阅读目标站点的用户协议和法律声明")
    else:
        print(f"\n[+] 页面中未发现明显的爬虫限制声明")

def main():
    if len(sys.argv) < 2:
        print("用法: python crawler_legal_check.py <URL>")
        sys.exit(1)
    url = sys.argv[1]
    print(f"=== 爬虫合规探测: {url} ===")
    rp = check_robots_txt(url)
    html = check_security_headers(url)
    check_page_legal_notice(html)
    print("\n=== 探测完成 ===")
    print("建议: 在正式抓取前,务必阅读目标站点的 robots.txt 和用户协议")

if __name__ == '__main__':
    main()

运行示例:

python crawler_legal_check.py https://测试网站.cn

输出会告诉你:

  1. 目标站点有没有 robots.txt,允不允许抓取
  2. HTTP 响应头里有没有安全策略或限流声明
  3. 页面内容里有没有"禁止爬虫"之类的法律关键词

这个脚本的法律价值在于:它留下了合规审查的记录。如果你后来因爬虫问题被调查,能证明你在抓取之前做过合规检查,是一个对你有利的证据。