Python 爬虫——爬虫基础

摘要

本文主要介绍爬虫学习所要掌握的基础知识,主要包括Web开发相关基础知识(Html、Css等)、Python相关基础知识、几个简单的Python库的使用等。还需要一些知识储备,比如:

  • re 模块,python 正则基础;
  • requests,用于获取网页内容,供后续处理;
  • lxml,用于处理 Html文档中的 元素;
  • 常用的爬虫策略与反爬策略;

re 模块

re 模块是python内置的模块,代码都在re.py文件中,是Python用来进行正则处理的,提供了正则表达式的支持,用于字符串的模式匹配、搜索、替换等操作。 如果没有正则基础,在文件的头部有正则表达式最基本的说明,这个更通过网络搜索的结果是一样的,而且每个说明都有例子说明。

常用的正则使用示例

  • 手机号判断
  • 身份证判断
  • 是否包含数字

常用函数

re.match(pattern, string)

从字符串开头匹配模式,如果匹配成功返回匹配对象,否则返回 None,示例如下:

python 复制代码
import re

result = re.match(r'hello', 'hello world')
if result:
    print(result.group())  # 输出: hello

re.search(pattern, string)

在整个字符串中搜索模式,返回第一个匹配的对象。

python 复制代码
import re
result = re.search(r'world', 'hello world')
if result:
    print(result.group()) # 输出: world

re.findall(pattern, string)

返回字符串中所有匹配的子串列表

python 复制代码
import re
result = re.findall(r'\d+', 'abc123def456')
if result:
    print(result.group()) # 输出:[123, 456]

re.finditer(pattern, string)

返回匹配对象的迭代器

python 复制代码
import re
result = re.finditer(r'\d+', 'abc123def456')
if result:
    for match in result:
        print(match.group())


# 输出
# 123 
# 456

re.sub(pattern, repl, string)

替换字符串中匹配的子串。

python 复制代码
import re
result = re.sub(r'\d+', 'NUMBER', 'abc123def456')
print(result)

# 输出:abcNUMBERdefNUMBER

re.split(pattern, string)

根据 pattern 来进行字符串的分割,返回的是列表

python 复制代码
import re
result = re.split(r's+', 'hello word  python')
print(result)

编译正则表达式

re.compile(pattern, flag)

使用 re.compile() 预编译正则表达式,提高重复使用的性能。

python 复制代码
import re

pattern = re.compile(r'\d+')
result = pattern.findall('abc123def456')
print(result)

常用正则匹配模式

模式 说明
. 匹配任意字符(除换行符)
. 匹配字符串开头
$ 匹配字符串结尾
* 匹配前面的字符0次或多次
+ 匹配前面的字符1次或多次
? 匹配前面的字符0次或多次
{n} 匹配前面的字符n次
{n,} 匹配前面的字符至少n次
{n,m} 匹配前面的字符n到m次
[] 字符类,匹配方括号内任意字符
[^] 否定字符类
\d 匹配数字,等价于[0-9]
\D 匹配非数字
\w 匹配字母、数字或下划线
\W 匹配非字母、数字或下划
\s 匹配空白字符
\S 匹配非空白字符

匹配对象方法

匹配 对象值得是调用 re.search(pattern, string) 后返回的Match对象,他有如下方法:

  • group() - 返回匹配的字符串;
  • groups() - 返回所有分组的元组;
  • group(n) - 返回第n个分组;
  • start() - 返回匹配开始位置;
  • end() - 返回匹配结束位置;
  • span() - 返回匹配位置的元组(start, end);

标志参数

可以使用标志位来修改正则表达式的匹配行为,如:

python 复制代码
# re.IGNORECASE 忽略大小写
result = re.search(r'hello', 'Hello World', re.IGNORECASE)

# re.MULTILINE 多行模式
# re.DOTALL 使.匹配包括换行符在内的所有字符
# re.VERBOSE 详细模式,允许写注释

捕获组(Capturing Groups)详解

捕获组是正则表达式中用圆括号 () 包围的子表达式,用于从匹配的文本中提取特定部分。

1. 基本概念

在正则表达式中,当你使用圆括号将一部分模式包围起来时,这部分就成为了一个捕获组。捕获组会"捕获"(保存)匹配该部分的文本,以便后续使用。

2. 示例说明

以你的代码为例:

python 复制代码
content = '''◎译  名 侏罗纪世界:重生/侏罗纪世界4◎片  名 Jurassic World: Rebirth/Jurassic World 4◎年  代 2025◎产  地 美国◎类  别 动作/科幻/惊悚/冒险◎语  言 英语◎字  幕 中英双字◎上映日期 2025-07-02(美国/中国大陆)◎IMDb评分  5.9/10 from 126698 users◎豆瓣评分 5.9/10 from 121885 users◎片  长 134分钟◎导  演 加里斯·爱德华斯 Gareth Edwards◎编  剧 大卫·凯普 David Koepp       迈克尔·克莱顿 Michael Crichton◎主  演 斯嘉丽·约翰逊 Scarlett Johansson       马赫沙拉·阿里 Mahershala Ali       乔纳森·贝利 Jonathan Bailey       鲁伯特·弗兰德 Rupert Friend       艾德·斯克林 Ed Skrein       曼努埃尔·加西亚-鲁尔福 Manuel Garcia-Rulfo       卢娜·布雷斯 Luna Blaise       奥德丽娜·米兰达 Audrina Miranda       大卫·伊亚科诺 David Iacono       贝希尔·西尔万 Bechir Sylvain       菲莉皮娜·维莱芝 Philippine Velge       妮娅姆·芬利 Niamh Finlay       亚当·洛克斯利 Adam Loxley       迪伦·比克尔 Dylan Bickel       朱利安·埃德加 Julian Edgar       乔尼·拉韦尔 Jonny Lavelle◎简  介  故事发生在《侏罗纪世界3》事件的五年后。危在旦夕的恐龙族群生存于孤岛之上,但是它们中却隐藏着能够带来人类医药奇迹的关键基因,为获取神秘基因,一支精英小队潜入恐龙禁地,然而等待他们的却是无法预知的危机和惊天阴谋......侏罗纪世界:重生.2025.BD.1080P.中英双字'''
translated_name = re.search(r'◎译\s*名\s*([^\r\n<◎]+)', content)

正则表达式分解:

  • ◎译 - 匹配字面量"◎译"
  • \s* - 匹配零个或多个空白字符
  • - 匹配字面量"名"
  • \s* - 匹配零个或多个空白字符
  • ([^\r\n<◎]+) - 这是一个捕获组,匹配一个或多个非换行符、非"<"、非"◎"的字符

3. group() 方法的区别

csharp 复制代码
# 假设匹配成功,对于文本 "◎译  名 侏罗纪世界:重生/侏罗纪世界4"

translated_name.group() 或 translated_name.group(0)
# 返回整个匹配的字符串:
# "◎译  名 侏罗纪世界:重生/侏罗纪世界4"

translated_name.group(1)
# 返回第一个捕获组的内容:
# "侏罗纪世界:重生/侏罗纪世界4"

4. 多个捕获组示例

python 复制代码
import re

text = "姓名:张三,年龄:25"
pattern = r"姓名:(\w+),年龄:(\d+)"

match = re.search(pattern, text)
if match:
    print(match.group(0))  # "姓名:张三,年龄:25" (整个匹配)
    print(match.group(1))  # "张三" (第一个捕获组)
    print(match.group(2))  # "25" (第二个捕获组)
    print(match.groups())  # ("张三", "25") (所有捕获组的元组)

5. 非捕获组

如果只想分组但不捕获内容,可以使用 (?:...) 语法:

python 复制代码
# 普通捕获组
pattern1 = r"(https?)://(\w+.com)"
# 非捕获组
pattern2 = r"(?:https?)://(\w+.com)"

text = "https://example.com"
match1 = re.search(pattern1, text)
match2 = re.search(pattern2, text)

# match1.groups() 返回 ("https", "example.com")
# match2.groups() 返回 ("example.com",)

requests

requests首先需要能拿到网页的内容,这需要用到 requests 库,安装requests库后,会自动安装[urllib3](urllib3 2.1.0 documentation)库

复制代码
pip install requests

基础使用方法如下,其他方法看源码无非就是request的调用

ini 复制代码
import requests

response = requests.request()

以下是 Python requests 库的深度解析,作为基于 urllib3 的上层封装,它提供了更人性化的 HTTP 客户端接口:


核心特性

  1. 极简 API 设计

    • 一行代码完成 GET/POST 等操作,无需手动处理 URL 编码、参数拼接

      csharp 复制代码
      import requests
      r = requests.get('https://api.example.com/data', params={'key': 'value'})
  2. 自动内容解析

    • 自动解码响应内容(r.text 根据编码推断字符串,r.json() 直接解析 JSON)

      scss 复制代码
      print(r.json()['result'])  # 直接获取结构化数据
  3. 会话持久化

    • 使用 Session 对象保持 Cookies、头信息、连接池复用

      csharp 复制代码
      with requests.Session() as s:
       s.headers.update({'User-Agent': 'MyApp'})
       s.get('https://example.com/login', auth=('user', 'pass'))
       r = s.post('https://example.com/api', data={'action': 'query'})
  4. SSL 验证与证书控制

    • 默认启用证书验证,支持自定义 CA 包或禁用验证(生产环境慎用)

      csharp 复制代码
      requests.get('https://example.com', verify='/path/to/cert.pem')  # 自定义证书

基础用法示例

GET 请求

ini 复制代码
# 带查询参数 & 自定义头
headers = {'Accept': 'application/json'}
params = {'page': 1, 'limit': 20}
r = requests.get('https://api.example.com/items', 
                params=params, 
                headers=headers)

print(f"状态码: {r.status_code}")
print(f"响应头: {r.headers['Content-Type']}")

POST 请求

ini 复制代码
# 表单提交
data = {'username': 'admin', 'password': 'secret'}
r = requests.post('https://example.com/login', data=data)

# JSON 提交(自动设置 Content-Type)
payload = {'key': 'value'}
r = requests.post('https://example.com/api', json=payload)

# 文件上传(多部分编码)
files = {'file': open('report.pdf', 'rb')}
r = requests.post('https://upload.example.com', files=files)

高级功能

  1. 超时与重试

    ini 复制代码
    from requests.adapters import HTTPAdapter
    from requests.packages.urllib3.util.retry import Retry
    
    session = requests.Session()
    retry = Retry(total=3, backoff_factor=0.3, status_forcelist=[500, 502])
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    
    response = session.get('https://example.com', timeout=(3.05, 27))  # 连接/读取超时
  2. 流式处理大文件

    python 复制代码
    r = requests.get('https://example.com/large-file', stream=True)
    with open('download.zip', 'wb') as f:
       for chunk in r.iter_content(chunk_size=8192): 
           f.write(chunk)
  3. 代理配置

    rust 复制代码
    proxies = {
       'http': 'http://10.10.1.10:3128',
       'https': 'http://user:pass@10.10.1.10:3128',
    }
    requests.get('http://example.com', proxies=proxies)

响应对象关键属性

属性/方法 说明 示例
status_code HTTP 状态码 200
headers 响应头字典 r.headers['Content-Type']
text 解码后的字符串响应体 html = r.text
content 原始字节数据 img_data = r.content
json() 解析 JSON 响应体 data = r.json()
raise_for_status() 非 2xx 状态码时抛出异常 r.raise_for_status()

异常处理

python 复制代码
try:
    r = requests.get('https://example.com', timeout=5)
    r.raise_for_status()  # 自动检查 4xx/5xx 错误
except requests.exceptions.HTTPError as errh:
    print("HTTP 错误:", errh)
except requests.exceptions.ConnectionError as errc:
    print("连接错误:", errc)
except requests.exceptions.Timeout as errt:
    print("超时:", errt)
except requests.exceptions.RequestException as err:
    print("未知请求异常:", err)

最佳实践

  1. 始终使用会话对象 - 提升性能(连接池复用)
  2. 明确超时设置 - 避免阻塞(推荐 timeout=(3.05, 27))
  3. 优先使用 json 参数 - 替代手动序列化
  4. 及时关闭响应 - 使用 with 语句或手动调用 r.close()

与 urllib3 对比

特性 requests urllib3
API 易用性 ⭐⭐⭐⭐⭐ ⭐⭐
连接池自动化 自动管理 需手动配置 PoolManager
流式下载 支持 (stream=True) 原生支持
适用场景 快速开发、REST API 调用 底层协议控制、高性能场景

💡 选择建议 :日常开发首选 requests,需要极致性能或底层控制时使用 urllib3。二者可混合使用(requests 底层依赖 urllib3)。

urllib3

urllib3 是 Python 中一个功能强大且用户友好的 HTTP 客户端库,专注于提供线程安全的连接池、文件上传、重试机制等高级功能。以下是关键特性详解:


核心特性

  1. 线程安全 & 连接池

    • 自动管理连接复用,显著减少 TCP 三次握手开销

    • 支持 HTTPConnectionPoolHTTPSConnectionPool 管理不同主机的连接

      ini 复制代码
      import urllib3
      http = urllib3.PoolManager(num_pools=5)  # 控制连接池数量
  2. 重试机制

    ini 复制代码
    from urllib3.util import Retry
    retries = Retry(total=3, backoff_factor=0.5, status_forcelist=[500, 502])
    http = urllib3.PoolManager(retries=retries)  # 自动重试失败请求
  3. SSL/TLS 安全

    • 默认启用证书验证,支持自定义 CA 证书

      ini 复制代码
      http = urllib3.PoolManager(ca_certs='/path/to/certs.pem')

典型使用场景

  • GET 请求

    lua 复制代码
    resp = http.request('GET', 'https://api.example.com/data')
    print(resp.status, resp.data.decode('utf-8'))
  • POST 表单 & JSON

    ini 复制代码
    resp = http.request('POST', 'https://api.example.com/submit',
                        fields={'name': 'Alice', 'age': 30})  # 表单提交
    # 或发送 JSON
    import json
    resp = http.request('POST', 'https://api.example.com/submit',
                        body=json.dumps({'data': 'test'}).encode('utf-8'),
                        headers={'Content-Type': 'application/json'})
  • 文件上传

    csharp 复制代码
    with open('file.txt', 'rb') as f:
        resp = http.request('POST', 'https://upload.example.com',
                            fields={'file': ('filename.txt', f.read())})

常见对象介绍

以下是 urllib3 库中核心类的详细说明,掌握这些类能更好地控制 HTTP 请求行为:


1. PoolManager

  • 功能:全局入口类,管理所有 HTTP/HTTPS 连接池

  • 关键作用

    • 自动创建和维护 HTTPConnectionPool/HTTPSConnectionPool
    • 控制最大连接池数量 (num_pools)
    • 处理跨主机的连接复用
  • 典型用法

    ini 复制代码
    http = urllib3.PoolManager(
        num_pools=10,  # 最大连接池数量
        maxsize=5,     # 每个池最大连接数
        block=True     # 连接不足时是否阻塞等待
    )

2. HTTPConnectionPool

  • 功能:管理特定主机的 HTTP 连接池

  • 核心特性

    • 同一主机复用 TCP 连接(减少握手开销)
    • 支持连接存活时间 (maxsize + block 参数)
  • 手动使用示例

    ini 复制代码
    pool = urllib3.HTTPConnectionPool('example.com', maxsize=5)
    resp = pool.request('GET', '/api/data')

3. Retry

  • 功能:定义请求失败时的重试策略

  • 可配置参数

    ini 复制代码
    Retry(
        total=3,                 # 最大总重试次数
        connect=2,               # 连接错误重试次数
        read=2,                  # 读取超时重试次数
        status_forcelist=[502],  # 强制重试的 HTTP 状态码
        backoff_factor=0.5       # 重试间隔算法因子
    )
  • 高级用法

    ini 复制代码
    from urllib3.util import Retry
    retry = Retry(raise_on_status=False)  # 不抛出状态码异常

4. ProxyManager

  • 功能:通过代理服务器发送请求

  • 特性

    • 支持 HTTP/HTTPS/SOCKS 代理
    • 自动处理代理认证
  • 示例

    ini 复制代码
    proxy = urllib3.ProxyManager(
        'http://user:pass@proxy.example.com:8080/',
        num_pools=5
    )
    resp = proxy.request('GET', 'http://target-site.com')

5. Response

  • 功能:封装 HTTP 响应数据

  • 关键属性

    bash 复制代码
    resp.status        # 状态码 (200)
    resp.headers       # 响应头 (CaseInsensitiveDict)
    resp.data          # 原始字节数据
    resp.reason        # 状态说明 ('OK')
  • 最佳实践

    python 复制代码
    with http.request('GET', url, preload_content=False) as resp:
        for chunk in resp.stream(1024):  # 流式读取大响应
            process(chunk)

6. 异常类

类名 触发场景 处理建议
HTTPError HTTP 状态码异常 (4xx/5xx) 检查 resp.status
MaxRetryError 超过最大重试次数 检查网络或调整 Retry 配置
TimeoutError 连接/读取超时 优化 timeout 参数
SSLError SSL 证书验证失败 检查证书路径或禁用验证

类协作流程

graph TD A[PoolManager] -->|创建| B(HTTPConnectionPool) B -->|处理请求| C{是否成功?} C -->|失败| D[Retry 策略] D -->|重试| B C -->|成功| E[Response 对象]

掌握这些类的用法,可以更精细地控制连接管理、错误处理等底层细节,适合需要高性能 HTTP 客户端的场景。


高级配置

ini 复制代码
# 超时控制(连接/读取)
http.request(..., timeout=urllib3.Timeout(connect=2.0, read=10.0))

# 代理设置
http = urllib3.ProxyManager('http://proxy.example.com:8080/')

# 自定义头信息
headers = {'User-Agent': 'MyApp/1.0'}
http.request(..., headers=headers)

异常处理

python 复制代码
try:
    resp = http.request(...)
except urllib3.exceptions.HTTPError as e:
    print("HTTP 错误:", e)
except urllib3.exceptions.MaxRetryError:
    print("超过最大重试次数")

性能优化建议

  1. 连接复用 - 始终通过 PoolManager 实例发起请求
  2. 超时设置 - 避免因网络问题阻塞进程
  3. 限制连接池大小 - 防止占用过多系统资源
  4. 及时释放响应体 - 使用 resp.release_conn() 或上下文管理器

与标准库对比

特性 urllib3 标准库 urllib
连接池管理 ✅ 自动复用 ❌ 无
重试机制 ✅ 可定制策略 ❌ 需手动实现
SSL 验证 ✅ 默认开启 ❌ 需复杂配置

💡 适用场景 :需精细控制 HTTP 行为时选择 urllib3,快速开发可考虑 requests(基于 urllib3 的上层封装)

lxml

lxml是一个功能丰富并易于使用的用来处理xml或HTML文件的库。作为高效处理 XML/HTML 文档的利器,其底层基于 C 语言库 libxml2/libxslt,兼具高性能与丰富功能:


核心特性

  • 闪电解析速度:比纯 Python 解析库快 5-20 倍
  • XPath 1.0/2.0 支持:精准定位文档节点
  • HTML 容错处理:自动修复残缺标签(类似浏览器行为)
  • 内存友好:支持增量解析大文件

安装与基础用法

bash 复制代码
pip install lxml  # 安装

解析 XML

ini 复制代码
from lxml import etree

xml = """
<bookstore>
  <book category="web">
    <title lang="en">XQuery Kick Start</title>
    <author>James McGovern</author>
    <year>2003</year>
    <price>40.00</price>
  </book>
</bookstore>
"""

root = etree.fromstring(xml)  # 解析字符串
print(root.tag)  # 输出根节点标签名: bookstore

# 或解析文件
tree = etree.parse('data.xml')
root = tree.getroot()

核心模块详解

1. ElementTree API

  • 节点操作

    ini 复制代码
    # 遍历子节点
    for child in root:
        print(child.tag, child.attrib)
    
    # 获取第一个 book 节点
    first_book = root.find('book')  
    # 获取所有 price 节点
    prices = root.findall('.//price')  
    
    # 修改节点内容
    first_book.find('price').text = "49.99"
  • 构建 XML

    ini 复制代码
    root = etree.Element("root")
    child = etree.SubElement(root, "child")
    child.set("id", "123")
    child.text = "文本内容"
    print(etree.tostring(root, pretty_print=True).decode())

2. XPath 数据提取

ini 复制代码
# 选择所有价格超过 30 的书籍标题
titles = root.xpath('//book[price>30]/title/text()')

# 带命名空间的 XPath(常见于 XML 文档)
ns = {'ns': 'http://example.com/ns'}
elements = root.xpath('//ns:element', namespaces=ns)

# 获取属性值
langs = root.xpath('//title/@lang')

3. HTML 解析模块

ini 复制代码
from lxml.html import fromstring

broken_html = "<div><p>未闭合标签"
doc = fromstring(broken_html)  # 自动修复结构

# CSS 选择器
links = doc.cssselect('a.external')  
for link in links:
    print(link.get('href'), link.text_content())

# 表单操作(自动化测试常用)
form = doc.forms[0]
form.fields = {'user': 'admin', 'pass': 'secret'}
submit_url = form.action  # 获取表单提交地址

性能优化技巧

  1. 增量解析大文件

    ini 复制代码
    context = etree.iterparse('large.xml', events=('end',), tag='item')
    for event, elem in context:
       process(elem)
       elem.clear()  # 及时清理已处理节点
  2. 预编译 XPath

    ini 复制代码
    find_title = etree.XPath('//title/text()')
    titles = find_title(root)  # 复用编译后的表达式
  3. 禁用无用功能

    ini 复制代码
    parser = etree.XMLParser(remove_blank_text=True, recover=True)  # 忽略空白/错误恢复
    tree = etree.parse('data.xml', parser)

常见问题处理

编码问题

ini 复制代码
# 强制指定输入输出编码
parser = etree.XMLParser(encoding='gbk')
tree = etree.parse('gbk_data.xml', parser=parser)
output = etree.tostring(tree, encoding='utf-8')

处理 CDATA

ini 复制代码
# 创建 CDATA 节点
cdata = etree.CDATA('<不可转义的内容>')
elem.append(cdata)

错误捕获

python 复制代码
from lxml.etree import XMLSyntaxError

try:
    etree.parse('invalid.xml')
except XMLSyntaxError as e:
    print(f"解析错误: {e.message} (行 {e.position[0]})")

与 BeautifulSoup 对比

特性 lxml BeautifulSoup
解析速度 ⭐⭐⭐⭐⭐ (C 扩展) ⭐⭐ (纯 Python)
HTML 容错 自动修复 依赖解析器 (如 html5lib)
XPath 支持 原生支持 需第三方库 (lxml 驱动)
内存占用 低 (SAX 模式) 较高 (DOM 树)
学习曲线 中等 简单

典型应用场景

  1. 爬虫数据提取:XPath + HTML 解析快速抽取结构化数据
  2. XML 配置文件处理:验证/修改符合 Schema 的配置文件
  3. Web 模板引擎:结合 XSLT 转换生成动态页面
  4. 大数据处理:流式解析 GB 级 XML 文件

扩展功能

ini 复制代码
# XSLT 转换(需 xslt 文件)
transform = etree.XSLT(etree.parse('style.xsl'))
result = transform(tree)
print(str(result))

# Schema 验证
schema = etree.XMLSchema(file='schema.xsd')
if schema.validate(tree):
    print("文档有效")

💡 最佳实践 :优先使用 XPath 而非逐层遍历,结合 lxml.html 处理网页抓取,对性能敏感场景启用解析器优化参数。

常用的爬虫策略和反爬策略

以下是爬虫策略与反爬策略的深度解析及攻防实战指南,结合技术实现与合规建议:


一、常用爬虫策略(攻击方)

1. 基础请求优化

  • 请求头伪装

    csharp 复制代码
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Referer': 'https://www.example.com/',
        'Accept-Language': 'zh-CN,zh;q=0.9'
    }
    requests.get(url, headers=headers)
  • Cookie 管理

    使用 requests.Session() 自动保持会话,或手动更新 cookies

2. 动态内容处理

  • Headless 浏览器

    使用 Selenium/Puppeteer 渲染 JavaScript:

    scss 复制代码
    from selenium.webdriver import ChromeOptions
    options = ChromeOptions()
    options.add_argument('--headless')  # 无头模式
    driver = webdriver.Chrome(options=options)
    driver.get(url)
    print(driver.page_source)
  • API 逆向工程

    通过浏览器开发者工具分析 XHR/Fetch 请求,直接调用数据接口

3. 分布式架构

  • IP 代理池

    集成付费/免费代理服务,实现 IP 轮换:

    rust 复制代码
    proxies = {
        'http': 'http://10.10.1.10:3128',
        'https': 'http://user:pass@10.10.1.10:3128'
    }
    requests.get(url, proxies=proxies)
  • 消息队列调度

    使用 Redis/RabbitMQ 分配任务,实现多节点协同抓取

4. 反反爬绕过技术

  • 验证码破解
    商用方案:接入打码平台(如超级鹰)
    自研方案:CNN 训练识别简单验证码
  • TLS 指纹伪装
    使用 curl_cffi 等库模拟浏览器 TLS 指纹

5. 数据清洗与存储

  • 去重策略
    Bloom Filter 过滤已抓取 URL
    数据指纹比对(MD5 等)
  • 异构数据存储
    结构化数据存 MySQL/PostgreSQL
    非结构化数据存 MongoDB/MinIO

二、主流反爬策略(防御方)

1. 基础特征检测

  • 流量特征阻断

    • 短时间高频访问(如 >100 次/分钟)
    • 非常规 User-Agent 格式
    • 缺失 Referer/Accept-Language 头
  • 防御代码示例(Node.js):

    kotlin 复制代码
    if(req.headers['user-agent'].includes('Python-urllib')) {
        return res.status(403).send('Bot detected!');
    }

2. 高级行为分析

  • 鼠标轨迹检测
    通过 JavaScript 监控用户操作模式
  • 页面停留时间
    正常用户访问间隔 >3 秒,爬虫往往连续请求
  • Honeypot 陷阱
    隐藏不可见链接(CSS: display:none),捕获点击者

3. 动态防护体系

  • 加密参数

    使用前端生成 _tokensign 等加密校验参数

    ini 复制代码
    # 爬虫需逆向生成算法
    token = hashlib.md5(f"{timestamp}secret_key".encode()).hexdigest()
  • API 限速

    令牌桶算法控制接口调用频次:

    python 复制代码
    from flask_limiter import Limiter
    limiter = Limiter(key_func=get_remote_address)
    @app.route("/api", methods=["GET"])
    @limiter.limit("10/minute")  # 限速

4. 深度学习对抗

  • 用户行为建模
    收集点击流数据,训练 LSTM 模型识别机器行为
  • 动态挑战响应
    随机触发验证码(滑块、点选等)

三、攻防成本对比表

策略 爬虫方成本 防御方成本 突破难度
User-Agent 检测
IP 代理池 ⭐⭐
验证码识别 ⭐⭐⭐⭐
TLS 指纹验证 ⭐⭐⭐⭐
行为模式分析 极高 极高 ⭐⭐⭐⭐⭐

四、合规建议

  1. 遵守 robots.txt

    python 复制代码
    from urllib.robotparser import RobotFileParser
    rp = RobotFileParser()
    rp.set_url('https://example.com/robots.txt')
    rp.read()
    if rp.can_fetch('MyBot', url):
       # 执行抓取
  2. 控制请求频率

    添加随机延迟(2-10 秒)

    lua 复制代码
    import random, time
    time.sleep(random.uniform(1, 3))
  3. 数据使用授权

    优先使用官方 API(如 Twitter API、Facebook Graph API)


五、未来趋势

  • AI 驱动攻防:GAN 生成对抗网络制造拟人流量
  • 区块链溯源:爬虫行为上链存证
  • 边缘计算防护:Cloudflare Workers 等边缘节点实时拦截

掌握这些策略需要持续关注最新反爬技术演进,建议定期研究:

  • 浏览器 DevTools 协议更新
  • WebAssembly 反混淆技术
  • Web 标准(如 Privacy Sandbox)的影响
相关推荐
wdfk_prog3 小时前
Python脚本深度解析:实现基于YMODEM的单片机固件自动化升级
python·单片机·自动化
萧鼎4 小时前
深入解析 Python 的 pytun 库:虚拟网络接口与隧道技术实战指南
服务器·网络·python
西猫雷婶4 小时前
pytorch基本运算-分离计算
人工智能·pytorch·python·深度学习·神经网络·机器学习
数新网络4 小时前
PyTorch
人工智能·pytorch·python
自信的小螺丝钉4 小时前
【大模型手撕】pytorch实现LayerNorm, RMSNorm
人工智能·pytorch·python·归一化·rmsnorm·layernorm
深耕AI4 小时前
PyTorch图像预处理:ToTensor()与Normalize()的本质区别
人工智能·pytorch·python
鲸屿1955 小时前
python之socket网络编程
开发语言·网络·python
里昆5 小时前
【AI】Tensorflow在jupyterlab中运行要注意的问题
人工智能·python·tensorflow
AI视觉网奇5 小时前
pycharm 最新版上一次编辑位置
python