共计 2857 个字符,预计需要花费 8 分钟才能阅读完成。
背景痛点:新手常见问题
刚接触爬虫时,最常见的问题包括:

- IP 封禁 :频繁请求导致服务器封锁 IP
- 反爬机制 :遇到验证码、动态加载等反爬策略
- 数据解析失败 :HTML 结构变化导致提取失败
- 法律风险 :不了解 robots.txt 规则可能违法
这些问题往往让初学者感到挫败。下面我们就从工具选择开始,一步步解决这些问题。
技术对比:选择合适的爬虫工具
不同的爬虫工具适用于不同场景:
- Requests+BeautifulSoup:适合简单静态页面,学习曲线平缓
- Scrapy:适合中大型项目,自带异步处理和管道功能
- Puppeteer:适合需要渲染 JavaScript 的动态页面
对于初学者,建议从 Requests 开始,因为它最基础也最容易理解。
核心实现:构建基础爬虫
1. 基本爬虫框架
import requests
from bs4 import BeautifulSoup
from typing import Optional
def fetch_page(url: str, headers: Optional[dict] = None) -> Optional[str]:
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
return response.text
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
return None
def parse_html(html: str) -> list:
soup = BeautifulSoup(html, 'html.parser')
# 使用 CSS 选择器提取数据
items = soup.select('.item')
return [item.text.strip() for item in items]
# 使用示例
headers = {'User-Agent': 'Mozilla/5.0'}
html = fetch_page('https://example.com', headers)
if html:
data = parse_html(html)
print(data)
2. 关键技巧
- Header 伪装 :轮换 User-Agent 模拟不同浏览器
user_agents = ['Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'AppleWebKit/537.36 (KHTML, like Gecko)',
'Chrome/91.0.4472.124 Safari/537.36'
]
headers = {'User-Agent': random.choice(user_agents)}
- 动态延迟 :避免固定间隔被识别
import time
import random
time.sleep(random.uniform(1, 3)) # 1- 3 秒随机延迟
- XPath 解析 :当 CSS 选择器不够用时
from lxml import etree
tree = etree.HTML(html)
titles = tree.xpath('//div[@class="title"]/text()')
避坑指南
1. 遵守 robots.txt
在爬取前先检查目标网站的 robots.txt 文件:
import urllib.robotparser
rp = urllib.robotparser.RobotFileParser()
rp.set_url('https://example.com/robots.txt')
rp.read()
if rp.can_fetch('*', 'https://example.com/target_page'):
# 允许爬取
else:
# 禁止爬取
2. 代理 IP 验证
使用代理前要做有效性检查:
def check_proxy(proxy: str) -> bool:
try:
response = requests.get(
'https://httpbin.org/ip',
proxies={'http': proxy, 'https': proxy},
timeout=5
)
return response.status_code == 200
except:
return False
3. 数据去重
使用数据库唯一索引或内存去重:
import hashlib
seen = set()
def is_duplicate(item: str) -> bool:
item_hash = hashlib.md5(item.encode()).hexdigest()
if item_hash in seen:
return True
seen.add(item_hash)
return False
安全考量
1. 采集频率控制
根据网站规模调整请求间隔:
# 小型网站: 3- 5 秒 / 请求
# 中型网站: 5-10 秒 / 请求
# 大型网站: 10-30 秒 / 请求
# 动态计算间隔
base_interval = 3 # 基础间隔 (秒)
page_size = 100 # 预估页面大小 (KB)
interval = base_interval + (page_size / 100)
2. 敏感数据过滤
使用正则表达式过滤隐私信息:
import re
def filter_sensitive(text: str) -> str:
# 过滤手机号
text = re.sub(r'1[3-9]\d{9}', '[PHONE]', text)
# 过滤身份证
text = re.sub(r'[1-9]\d{5}(18|19|20)\d{2}[0-9Xx]', '[ID]', text)
return text
性能优化建议
- 连接复用 :使用 Session 对象保持连接
session = requests.Session()
# 多次请求会自动复用 TCP 连接
- 异步 IO:提高爬取效率
import aiohttp
import asyncio
async def async_fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
- 增量爬取 :只抓取更新的内容
# 记录最后爬取时间
last_crawl_time = datetime.now() - timedelta(days=1)
扩展思考:分布式爬虫架构
当单机爬虫无法满足需求时,可以考虑:
- 主从架构 :一个主节点分配任务,多个从节点执行爬取
- 消息队列 :使用 RabbitMQ/Kafka 管理任务队列
- 去重中心 :Redis 集群存储全局去重集合
- 代理池 :独立维护代理 IP 资源池
总结
构建稳定爬虫需要关注多个方面:从基础的请求封装、数据解析,到反反爬策略、性能优化,再到合规性和安全性。建议初学者先从小规模爬取开始,逐步增加复杂度。记住:好的爬虫应该像绅士一样礼貌,只拿允许拿的数据,不影响网站正常运行。
随着经验积累,你可以尝试更高级的技术,如 Selenium 模拟浏览器、Scrapy-Redis 分布式架构等。但核心原则始终不变:高效、稳定、合规。
正文完
