1. 为什么需要多线程爬虫?
当我们需要从网站上抓取大量数据时,单线程爬虫就像一个人挨家挨户敲门收集信息,效率极其低下。我去年接手的一个电商价格监控项目就遇到了这个问题——单线程爬取5000个商品页面需要近2小时,完全无法满足业务需求。
多线程爬虫的核心价值在于并发处理能力。通过创建多个工作线程,我们可以同时向不同服务器发起请求,就像组建了一个高效的采集小队。在实际测试中,合理的多线程配置可以将爬取速度提升10-20倍。但要注意,线程数并非越多越好,后面我会详细解释这个"甜蜜点"的选择策略。
重要提示:在开始多线程爬虫前,请务必确认目标网站的robots.txt协议,避免因高频请求导致IP被封禁。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Python多线程实现方案对比
2.1 threading模块基础用法
Python标准库中的threading是最基础的多线程实现方式。下面是一个典型的生产者-消费者模型实现:
python复制import threading
import queue
class SpiderThread(threading.Thread):
def __init__(self, url_queue):
super().__init__()
self.url_queue = url_queue
def run(self):
while True:
try:
url = self.url_queue.get(timeout=3)
self.process_page(url)
except queue.Empty:
break
def process_page(self, url):
# 实际的爬取逻辑
print(f"Processing {url}")
url_queue = queue.Queue()
for url in urls:
url_queue.put(url)
threads = []
for i in range(5): # 创建5个工作线程
t = SpiderThread(url_queue)
t.start()
threads.append(t)
for t in threads:
t.join()
这种方式的优点是实现简单,但存在明显的GIL(全局解释器锁)限制,当线程执行CPU密集型任务时,性能提升有限。
2.2 concurrent.futures线程池
Python 3.2引入的concurrent.futures提供了更高级的抽象:
python复制from concurrent.futures import ThreadPoolExecutor
import requests
def fetch(url):
resp = requests.get(url)
return resp.text
with ThreadPoolExecutor(max_workers=8) as executor:
futures = {executor.submit(fetch, url): url for url in urls}
for future in concurrent.futures.as_completed(futures):
url = futures[future]
try:
data = future.result()
# 处理数据
except Exception as e:
print(f"{url} generated an exception: {e}")
线程池自动管理线程生命周期,通过max_workers参数控制并发度,特别适合I/O密集型任务。
2.3 异步IO方案(aiohttp)
对于超高并发的场景,asyncio + aiohttp组合能突破线程数的限制:
python复制import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
return await asyncio.gather(*tasks)
results = asyncio.run(main())
这种方案在测试中可以达到每秒上千请求的处理能力,但编程模型相对复杂,需要理解协程和事件循环机制。
3. 关键参数调优实战
3.1 线程数设置黄金法则
经过大量实测,我发现最优线程数遵循这个公式:
code复制最优线程数 = min(目标网站容忍度, CPU核心数 × (1 + 平均等待时间/平均计算时间))
其中:
- 目标网站容忍度:通过测试获取,一般中小型网站建议5-10
- 平均等待时间:从发起请求到收到响应的时间
- 平均计算时间:解析响应内容的时间
例如我的开发环境:
- 4核CPU
- 平均等待时间:1.2秒(网络延迟)
- 平均计算时间:0.3秒(页面解析)
计算得出:4 × (1 + 1.2/0.3) = 20
但实际测试发现目标网站在并发15时开始出现拒绝服务,因此最终设置为12。
3.2 超时与重试机制
健壮的爬虫必须处理网络不确定性:
python复制from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10))
def fetch_with_retry(url):
try:
resp = requests.get(url, timeout=(3.05, 10))
resp.raise_for_status()
return resp
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
raise
这里使用了tenacity库实现:
- 最多重试3次
- 等待时间指数增长(4s, 8s, 10s)
- 连接超时3.05秒,读取超时10秒
4. 反爬虫对抗策略
4.1 请求头精细化配置
很多网站会检测User-Agent等头信息:
python复制headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'en-US,en;q=0.5',
'Referer': 'https://www.google.com/',
'DNT': '1'
}
建议维护一个User-Agent池,随机选择不同浏览器版本。
4.2 IP轮换方案
当检测到IP被封时,可以:
- 使用付费代理服务(注意选择支持HTTPS的)
- 自建代理池(需要多台服务器)
- Tor网络(速度较慢)
python复制proxies = {
'http': 'http://user:pass@proxy_ip:port',
'https': 'http://user:pass@proxy_ip:port'
}
response = requests.get(url, proxies=proxies)
5. 性能监控与调试
5.1 实时监控看板
使用prometheus_client实现监控:
python复制from prometheus_client import start_http_server, Counter, Gauge
REQUESTS_TOTAL = Counter('requests_total', 'Total requests')
FAILED_REQUESTS = Counter('failed_requests', 'Failed requests')
QUEUE_SIZE = Gauge('queue_size', 'URL queue size')
def worker():
while True:
url = queue.get()
QUEUE_SIZE.dec()
try:
fetch(url)
REQUESTS_TOTAL.inc()
except:
FAILED_REQUESTS.inc()
启动监控服务器:
python复制start_http_server(8000)
5.2 日志结构化处理
使用structlog增强日志可读性:
python复制import structlog
logger = structlog.get_logger()
def fetch(url):
try:
logger.info("fetch_start", url=url)
# ...请求逻辑
logger.info("fetch_success", url=url, status=resp.status_code)
except Exception as e:
logger.error("fetch_failed", url=url, error=str(e))
raise
输出示例:
json复制{
"event": "fetch_success",
"url": "https://example.com",
"status": 200,
"timestamp": "2023-07-20T14:23:01Z"
}
6. 数据存储优化
6.1 批量写入策略
避免频繁的数据库写入操作:
python复制from itertools import islice
def batch_insert(data_iterable, batch_size=100):
while True:
batch = list(islice(data_iterable, batch_size))
if not batch:
break
# 执行批量插入
db.bulk_insert(batch)
6.2 内存缓存应用
使用cachetools减少重复请求:
python复制from cachetools import TTLCache
cache = TTLCache(maxsize=1000, ttl=3600)
@cached(cache)
def fetch_with_cache(url):
return requests.get(url).content
7. 异常处理全集
7.1 网络异常分类处理
python复制try:
response = requests.get(url, timeout=10)
except requests.exceptions.Timeout:
logger.warning("Request timeout", url=url)
except requests.exceptions.SSLError:
logger.error("SSL verification failed", url=url)
except requests.exceptions.ProxyError:
logger.error("Proxy configuration error")
except requests.exceptions.RequestException as e:
logger.error("Request failed", error=str(e))
7.2 页面解析容错
使用lxml解析时的容错处理:
python复制from lxml import html, etree
def safe_parse(content):
try:
return html.fromstring(content)
except etree.ParserError:
logger.warning("Failed to parse HTML", content=content[:200])
return None
8. 分布式扩展方案
当单机性能达到瓶颈时,可以考虑:
- 使用Celery分布式任务队列
- 采用Scrapy-Redis架构
- 自建任务调度中心
python复制# Celery任务示例
@app.task(bind=True, max_retries=3)
def fetch_task(self, url):
try:
return fetch(url)
except Exception as e:
self.retry(exc=e, countdown=2 ** self.request.retries)
9. 法律与伦理边界
开发爬虫时必须注意:
- 遵守robots.txt协议
- 不抓取个人隐私数据
- 控制请求频率(建议≥1秒/次)
- 尊重网站的服务条款
可以在代码中加入强制延迟:
python复制import time
class PoliteDownloader:
def __init__(self, delay=1.0):
self.delay = delay
self.last_request = 0
def fetch(self, url):
elapsed = time.time() - self.last_request
if elapsed < self.delay:
time.sleep(self.delay - elapsed)
self.last_request = time.time()
return requests.get(url)
10. 完整项目架构示例
一个生产级爬虫的典型结构:
code复制/scraper
├── core/
│ ├── downloader.py # 下载器组件
│ ├── parser.py # 解析器组件
│ └── pipeline.py # 数据存储组件
├── utils/
│ ├── logger.py # 日志配置
│ └── proxy.py # 代理管理
├── config.py # 配置文件
├── scheduler.py # 任务调度
└── main.py # 入口文件
在main.py中初始化各组件:
python复制from concurrent.futures import ThreadPoolExecutor
from .core.downloader import PoliteDownloader
from .core.pipeline import DatabasePipeline
def run_spider():
downloader = PoliteDownloader(delay=1.5)
pipeline = DatabasePipeline()
with ThreadPoolExecutor(max_workers=8) as executor:
futures = []
for url in generate_urls():
future = executor.submit(
process_page,
downloader=downloader,
pipeline=pipeline,
url=url
)
futures.append(future)
for future in concurrent.futures.as_completed(futures):
try:
future.result()
except Exception as e:
logger.error("Task failed", error=str(e))
def process_page(downloader, pipeline, url):
html = downloader.fetch(url)
data = parse_page(html)
pipeline.save(data)
11. 性能对比测试数据
在我的MacBook Pro (M1 Pro, 32GB)上测试不同方案的吞吐量:
| 方案 | 线程数 | 请求数 | 耗时(s) | 成功率 | QPS |
|---|---|---|---|---|---|
| 单线程 | 1 | 100 | 58.3 | 100% | 1.7 |
| threading | 5 | 100 | 12.1 | 100% | 8.3 |
| ThreadPoolExecutor | 10 | 100 | 6.4 | 98% | 15.6 |
| aiohttp | 100 | 100 | 1.2 | 95% | 83.3 |
注意:aiohttp的高并发会触发网站防御机制,实际项目中需要平衡速度和稳定性。
12. 资源清理策略
长时间运行的爬虫需要注意:
- 连接池管理
- 文件描述符泄漏
- 内存泄漏检测
使用resource模块监控:
python复制import resource
def memory_usage():
return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024 # MB
def check_resources():
logger.info(
"Resource usage",
memory=memory_usage(),
fd_count=len(os.listdir('/proc/self/fd'))
)
13. 浏览器自动化集成
对于JavaScript渲染的页面,可以结合Selenium:
python复制from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
options = ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
try:
driver.get(url)
WebDriverWait(driver, 10).until(
lambda d: d.find_element(By.CSS_SELECTOR, ".content")
)
html = driver.page_source
finally:
driver.quit()
14. 动态代理验证系统
实现自动化的代理检测:
python复制def validate_proxy(proxy):
try:
start = time.time()
resp = requests.get(
'https://httpbin.org/ip',
proxies={'https': proxy},
timeout=5
)
latency = time.time() - start
return latency < 2 and resp.json().get('origin') in proxy
except:
return False
15. 智能限速算法
根据响应情况动态调整请求频率:
python复制class AdaptiveRateLimiter:
def __init__(self, initial_rate=1.0):
self.rate = initial_rate
self.last_update = time.time()
def adjust(self, success):
now = time.time()
elapsed = now - self.last_update
if elapsed > 30: # 每30秒调整一次
if success:
self.rate = min(10.0, self.rate * 1.2)
else:
self.rate = max(0.5, self.rate * 0.8)
self.last_update = now
def get_delay(self):
return 1.0 / self.rate
16. 验证码处理方案
遇到验证码时可以:
- 使用第三方打码平台
- 机器学习自动识别(Tesseract等)
- 人工干预接口
python复制def handle_captcha(image_data):
# 方法1:调用打码平台
captcha_text = dama2.decode(image_data)
# 方法2:本地识别
# import pytesseract
# captcha_text = pytesseract.image_to_string(image_data)
return captcha_text
17. 数据去重策略
使用Bloom filter高效去重:
python复制from pybloom_live import ScalableBloomFilter
bf = ScalableBloomFilter(initial_capacity=1000000, error_rate=0.001)
def is_duplicate(url):
if url in bf:
return True
bf.add(url)
return False
18. 断点续爬实现
记录爬取状态以便恢复:
python复制import pickle
class CrawlState:
def __init__(self, state_file='crawl_state.pkl'):
self.state_file = state_file
self.visited_urls = set()
self.pending_urls = queue.Queue()
self._load()
def _load(self):
try:
with open(self.state_file, 'rb') as f:
data = pickle.load(f)
self.visited_urls = data['visited']
for url in data['pending']:
self.pending_urls.put(url)
except FileNotFoundError:
pass
def save(self):
data = {
'visited': self.visited_urls,
'pending': list(self.pending_urls.queue)
}
with open(self.state_file, 'wb') as f:
pickle.dump(data, f)
19. 微服务化部署
使用FastAPI暴露爬虫接口:
python复制from fastapi import FastAPI
app = FastAPI()
crawler = Crawler()
@app.post("/crawl")
async def start_crawl(config: CrawlConfig):
task_id = str(uuid.uuid4())
asyncio.create_task(crawler.run(task_id, config))
return {"task_id": task_id}
@app.get("/status/{task_id}")
async def get_status(task_id: str):
return crawler.get_status(task_id)
20. 机器学习增强
使用NLP处理非结构化数据:
python复制from transformers import pipeline
extractor = pipeline("text-classification", model="bert-base-uncased")
def extract_info(text):
results = extractor(text[:512], truncation=True)
return max(results, key=lambda x: x['score'])
21. 移动端API抓取
使用mitmproxy捕获手机流量:
python复制from mitmproxy import http
class MobileAPIInterceptor:
def request(self, flow: http.HTTPFlow):
if "api.mobile.app" in flow.request.pretty_host:
print(f"Intercepted API call: {flow.request.url}")
# 可以修改请求或响应
22. 无头浏览器集群
使用playwright管理多个浏览器实例:
python复制from playwright.async_api import async_playwright
async def run_browser_cluster(urls):
async with async_playwright() as p:
browsers = [await p.chromium.launch() for _ in range(3)]
page_tasks = []
for browser in browsers:
page = await browser.new_page()
page_tasks.append(page.goto(urls.pop()))
await asyncio.gather(*page_tasks)
# 处理页面内容...
23. 云端部署方案
使用Docker打包爬虫:
dockerfile复制FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
Kubernetes部署配置示例:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: web-scraper
spec:
replicas: 3
selector:
matchLabels:
app: scraper
template:
metadata:
labels:
app: scraper
spec:
containers:
- name: scraper
image: your-repo/web-scraper:latest
resources:
limits:
cpu: "1"
memory: "512Mi"
24. 监控告警系统
集成Prometheus + Alertmanager:
python复制from prometheus_client import Gauge
from prometheus_client.twisted import MetricsResource
from twisted.web.server import Site
from twisted.web.resource import Resource
ALERTS = Gauge('scraper_alerts', 'Active alert count', ['severity'])
class AlertingSystem:
def check_conditions(self):
if error_rate > 0.1:
ALERTS.labels(severity='critical').inc()
send_alert("High error rate detected!")
25. 成本控制策略
爬虫运营成本主要包括:
- 服务器费用
- 代理IP费用
- 存储费用
优化建议:
- 使用spot实例(AWS/GCP)
- 按需调整爬取频率
- 压缩存储数据
python复制def cost_aware_scheduler():
while True:
current_hour = datetime.now().hour
if 2 <= current_hour <= 6: # 凌晨时段
run_at_full_capacity()
else:
run_at_reduced_rate()
26. 数据质量监控
实现自动化的数据校验:
python复制from pandas import DataFrame
def validate_data(df: DataFrame):
report = {
'missing_values': df.isnull().sum().to_dict(),
'duplicates': df.duplicated().sum(),
'outliers': detect_outliers(df)
}
if report['missing_values'] or report['duplicates'] > len(df)*0.05:
alert_data_quality_issue(report)
27. 爬虫模式识别防御
防止被识别为爬虫的技巧:
- 随机化鼠标移动轨迹
- 模拟人类阅读模式(滚动停顿)
- 随机化请求间隔
python复制import numpy as np
def human_like_delay():
base = 1.0
randomness = np.random.normal(0, 0.3)
return max(0.5, base + randomness)
def random_scroll(page):
scroll_steps = np.random.randint(3, 7)
for _ in range(scroll_steps):
page.evaluate(f"window.scrollBy(0, {np.random.randint(200, 500)})")
time.sleep(human_like_delay())
28. 法律文书自动生成
对于合规需求,自动生成爬取日志:
python复制from jinja2 import Template
LEGAL_TEMPLATE = """
数据采集报告
采集时间: {{timestamp}}
目标网站: {{domain}}
采集范围: {{scope}}
数据用途: {{purpose}}
"""
def generate_report(**kwargs):
template = Template(LEGAL_TEMPLATE)
return template.render(
timestamp=datetime.now().isoformat(),
**kwargs
)
29. 跨语言协作方案
当需要与其他语言集成时:
python复制import subprocess
def call_java_parser(html_file):
result = subprocess.run(
['java', '-jar', 'html-parser.jar', html_file],
capture_output=True,
text=True
)
return result.stdout
30. 持续集成实践
GitLab CI配置示例:
yaml复制stages:
- test
- deploy
scraper_test:
stage: test
image: python:3.9
script:
- pip install -r requirements.txt
- pytest tests/
rules:
- changes:
- scraper/**
production_deploy:
stage: deploy
image: python:3.9
script:
- ansible-playbook deploy.yml
when: manual
only:
- main
31. 移动端适配采集
使用设备模拟参数:
python复制mobile_emulation = {
"deviceMetrics": {"width": 360, "height": 640, "pixelRatio": 3.0},
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X)"
}
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
32. 自动化测试体系
爬虫核心测试用例:
python复制@pytest.mark.asyncio
async def test_fetch_success():
with aioresponses() as m:
m.get('http://test.com', payload={'ok': True})
result = await fetch('http://test.com')
assert result == {'ok': True}
def test_parser():
html = "<div class='price'>$19.99</div>"
assert parse_price(html) == 19.99
33. 文档自动化生成
使用Sphinx生成API文档:
python复制"""
:param url: 要抓取的URL地址
:type url: str
:param retries: 重试次数,默认3次
:type retries: int
:return: 页面HTML内容
:rtype: str
:raises RequestException: 当请求失败时抛出
"""
def fetch_page(url, retries=3):
# 实现代码
34. 安全加固措施
关键安全配置:
python复制# 禁用不安全的协议
import urllib3
urllib3.disable_warnings()
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += ':HIGH:!DH:!aNULL'
# 安全cookie处理
session = requests.Session()
session.cookies.set(secure=True, httponly=True, samesite='Lax')
35. 性能瓶颈分析
使用cProfile定位问题:
python复制import cProfile
def run_with_profiling():
profiler = cProfile.Profile()
profiler.enable()
# 运行爬虫主逻辑
main()
profiler.disable()
profiler.dump_stats('scraper.prof')
# 使用snakeviz可视化分析
# pip install snakeviz
# snakeviz scraper.prof
36. 动态配置加载
使用Hydra管理配置:
python复制from omegaconf import DictConfig
import hydra
@hydra.main(config_path="conf", config_name="config")
def main(cfg: DictConfig):
print(f"Using user agent: {cfg.user_agent}")
print(f"Proxy enabled: {cfg.proxy.enabled}")
if __name__ == "__main__":
main()
37. 地理位置模拟
修改时区和语言设置:
python复制from selenium.webdriver import ChromeOptions
options = ChromeOptions()
options.add_argument('--lang=ja-JP')
options.add_argument('--timezone=Asia/Tokyo')
38. 浏览器指纹混淆
使用undetected-chromedriver:
python复制import undetected_chromedriver as uc
driver = uc.Chrome(
headless=False,
use_subprocess=True,
version_main=94
)
39. 数据加密存储
使用cryptography加密敏感数据:
python复制from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher = Fernet(key)
encrypted = cipher.encrypt(b"secret_data")
decrypted = cipher.decrypt(encrypted)
40. 智能调度算法
基于网站响应动态调整优先级:
python复制class SmartScheduler:
def __init__(self):
self.url_weights = defaultdict(lambda: 1.0)
def update_weight(self, url, response_time, success):
if success:
self.url_weights[url] = max(0.1, 1.0 / response_time)
else:
self.url_weights[url] *= 0.8
def get_next_url(self):
return max(self.url_weights, key=self.url_weights.get)
41. 容器化调试技巧
使用VS Code远程调试:
json复制// launch.json
{
"name": "Python: Remote Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app"
}]
}
42. 内存优化策略
使用生成器减少内存占用:
python复制def stream_parse(html_iterable):
for html in html_iterable:
yield parse(html)
# 使用示例
for data in stream_parse(fetch_pages()):
process(data)
43. 自动化部署脚本
使用Fabric实现一键部署:
python复制from fabric import task
@task
def deploy(c):
c.run('git pull origin main')
c.run('docker-compose build')
c.run('docker-compose up -d')
c.run('docker system prune -f')
44. 多阶段数据处理
使用Ray实现分布式处理:
python复制import ray
@ray.remote
def parse_page(html):
# 解析逻辑
return data
# 主程序
ray.init()
result_ids = [parse_page.remote(html) for html in htmls]
results = ray.get(result_ids)
45. 可视化监控大屏
使用Grafana展示关键指标:
python复制from grafana_api.grafana_face import GrafanaFace
grafana = GrafanaFace(auth='admin:admin', host='localhost:3000')
dashboard = {
"title": "Scraper Metrics",
"panels": [
{
"title": "Request Rate",
"type": "graph",
"targets": [{
"expr": "rate(requests_total[1m])",
"legendFormat": "{{instance}}"
}]
}
]
}
grafana.dashboard.update_dashboard(dashboard)
46. 自动化测试数据生成
使用Faker创建测试用例:
python复制from faker import Faker
fake = Faker()
def generate_test_urls(count=100):
domains = [fake.domain_name() for _ in range(5)]
return [
f"https://{fake.random_element(domains)}/{fake.uri_path()}"
for _ in range(count)
]
47. 多协议支持实现
处理不同协议的统一接口:
python复制class ProtocolHandler:
def __init__(self):
self.handlers = {
'http': self._handle_http,
'https': self._handle_http,
'ftp': self._handle_ftp
}
def handle(self, url):
protocol = url.split('://')[0]
handler = self.handlers.get(protocol)
if handler:
return handler(url)
raise ValueError(f"Unsupported protocol: {protocol}")
48. 自动化文档抓取
递归抓取网站文档:
python复制def crawl_sitemap(start_url, max_depth=3):
visited = set()
queue = [(start_url, 0)]
while queue:
url, depth = queue.pop(0)
if depth > max_depth or url in visited:
continue
visited.add(url)
html = fetch(url)
yield html
# 提取新链接
for link in extract_links(html):
if link.startswith('http'):
queue.append((link, depth + 1))
49. 智能缓存策略
使用Redis实现分布式缓存:
python复制import redis
from pickle import dumps, loads
r = redis.Redis(host='localhost', port=6379)
def cached_fetch(url, expire=3600):
cache_key = f"page:{hash(url)}"
cached = r.get(cache_key)
if cached:
return loads(cached)
content = fetch(url)
r.setex(cache_key, expire, dumps(content))
return content
50. 终极性能优化组合
经过多年实践,我发现最高效的Python爬虫架构组合是:
- aiohttp 作为HTTP客户端
- uvloop 加速事件循环
- orjson 解析JSON
- lxml 解析HTML
- asyncpg 存储到PostgreSQL
启动脚本示例:
python复制import asyncio
import uvloop
from aiohttp import ClientSession
async def main():
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
async with ClientSession() as session:
# 主爬取逻辑
pass
if __name__ == '__main__':
asyncio.run(main())
这个组合在我的基准测试中可以达到单机每秒处理1500+请求的性能,同时保持较低的CPU和内存占用。关键在于充分利用异步I/O和高效的基础库,避免Python GIL的限制。
