
Python爬虫进阶的核心在于突破限制与架构设计。这不仅仅是发送一个requests.get()而是涉及到网络协议、浏览器渲染、数据流控制和反爬对抗。1. 异步并发与速率控制性能瓶颈突破当需要采集百万级数据时同步IO会成为瓶颈。进阶需要使用asyncioaiohttp但直接暴力并发会瞬间被Ban因此必须引入令牌桶算法控制速率。pythonimport asyncio import aiohttp from asyncio import Semaphore class AsyncRateLimiter: 滑动窗口速率控制器令牌桶变种 def __init__(self, rate, per): self.semaphore Semaphore(rate) # 最大并发数 self.interval per / rate # 每次请求间隔 async def acquire(self): await self.semaphore.acquire() asyncio.create_task(self._release()) async def _release(self): await asyncio.sleep(self.interval) self.semaphore.release() async def fetch(session, url, limiter): await limiter.acquire() async with session.get(url) as resp: return await resp.text() # 运行逻辑每秒最多50个请求且严格间隔0.02秒2. 应对复杂JavaScript渲染Pyppeteer 底层控制对于SPA应用Selenium太慢。进阶使用pyppeteer无头Chrome的Python异步接口。高级技巧是拦截请求和注入JS来绕过检测。pythonimport asyncio from pyppeteer import launch async def smart_render(): browser await launch(headlessTrue, args[--no-sandbox]) page await browser.newPage() # 1. 拦截网络请求阻塞图片和字体大幅提速 await page.setRequestInterception(True) page.on(request, lambda req: asyncio.ensure_future( req.abort() if req.resourceType in [image, font, media] else req.continue_() )) # 2. 在页面上下文中覆写WebDriver检测属性 await page.evaluateOnNewDocument( Object.defineProperty(navigator, webdriver, { get: () undefined }); window.chrome { runtime: {} }; ) await page.goto(https://target.com, {waitUntil: networkidle2}) # 3. 等待特定元素出现比time.sleep智能 await page.waitForSelector(#data-loaded, {timeout: 10000}) content await page.content() await browser.close() return content3. 深度指纹对抗TLS 指纹伪装服务端不仅看User-Agent还通过JA3指纹检测Python的urllib3/requests库特征。进阶必须使用curl_cffi模拟真实浏览器的TLS握手。pythonfrom curl_cffi import requests # 冒充 Chrome 110 的 TLS 指纹和 HTTP/2 优先级设置 response requests.get( https://httpbin.io/headers, impersonatechrome110, # 这一行关键伪造底层加密套件 timeout30 ) # 若结合代理需额外处理代理头的转发 proxies {http: socks5://127.0.0.1:1080, https: socks5://127.0.0.1:1080} response requests.get(https://target.com, impersonateedge101, proxiesproxies)4. 增量式去重与布隆过滤器大规模存储优化当数据量达到千万级用Redis Set存储URL会耗尽内存。使用布隆过滤器Scalable Bloom Filter只存指纹允许极低误判率大幅节省空间。pythonfrom pybloom_live import ScalableBloomFilter # 自动扩容的布隆过滤器误判率 0.001% url_bloom ScalableBloomFilter(modeScalableBloomFilter.SMALL_SET_GROWTH) def is_duplicate(url): # 只存 URL 的哈希指纹不存原文 if url in url_bloom: return True url_bloom.add(url) return False # 在异步管道中的使用 async def save_item(item): fingerprint f{item[title]}_{item[publish_date]} if not is_duplicate(fingerprint): await db.insert(item) # 异步写入数据库5. 动态代理池与重试中间件高可用架构进阶不是简单地用proxies参数而是构建中间件自动检测代理失效并切换。通过装饰器实现熔断重试。pythonimport random from functools import wraps from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception def proxy_retry_middleware(func): wraps(func) retry( stopstop_after_attempt(3), waitwait_exponential(multiplier1, min2, max10), retryretry_if_exception(lambda e: 403 in str(e) or Timeout in str(e)) ) async def wrapper(*args, **kwargs): # 从队列中取出可用代理通过Redis维护高可用池 proxy await get_available_proxy() kwargs[proxy] fhttp://{proxy} try: return await func(*args, **kwargs) except Exception as e: # 标记代理失效从池中移除 await mark_proxy_dead(proxy) raise e # 抛出让 tenacity 重试 return wrapper6. 分布式调度器去中心化协调使用Redis Lua脚本实现原子性的任务分发避免多台爬虫服务器抢占同一个任务导致重复。lua-- acquire_task.lua local key KEYS[1] local task redis.call(rpop, key) -- 从右端取 if task then redis.call(lpush, processing_queue, task) -- 放入处理中队列 redis.call(expire, processing_queue, 600) -- 超时回收 end return taskpythonimport redis r redis.Redis(hostlocalhost, decode_responsesTrue) # Python 调用 Lua 实现原子操作 sha r.script_load( local task redis.call(rpop, KEYS[1]) if task then redis.call(lpush, processing, task) end return task ) task_data r.evalsha(sha, 1, task_queue)总结进阶思维导图层面初级做法进阶做法并发ThreadPoolExecutorasyncio 令牌桶限流渲染time.sleep硬等waitForSelector 请求拦截反爬换 UA/加延时TLS指纹篡改 JS注入存储MySQL 全量存储布隆过滤器 增量更新架构单机运行Lua原子任务 代理中间件