一、核心理念:为什么不能"一把梭"?
在做出选择之前,我们必须理解两者的工作原理。
1. Requests:纯粹的网络请求库
- 本质:模拟HTTP请求,直接与服务器交互。它轻量、高效,一个请求一个响应,干净利落。
- 请求头处理 :你可以通过
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">headers</font>参数完全、精确地控制 发送给服务器的每一个请求头。无论是<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">User-Agent</font>,<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Cookie</font>,<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Referer</font>,还是自定义的认证头,都可以轻松设置。 - 优势:速度极快,资源消耗低,是处理大规模数据采集的首选。
- 劣势 :无法执行JavaScript。对于依赖JS渲染的动态网页,
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Requests</font>获取到的HTML源码是不完整的。
2. Selenium:浏览器自动化工具
- 本质:启动并控制一个真实的浏览器(如Chrome, Firefox)。你看到的是什么,它获取的就是什么。
- 请求头处理 :在初始阶段,你可以通过
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">ChromeOptions.add_argument()</font>来设置一些基本的请求头,如<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">--user-agent</font>。对于更精细的请求头控制,则需要借助更高级的CDP 或浏览器插件/中间件,过程相对繁琐。 - 优势:能完美渲染JavaScript,模拟所有用户交互行为(点击、输入、滚动等)。
- 劣势:速度慢,资源消耗巨大(CPU和内存),容易被网站通过浏览器指纹识别。
二、决策时刻:何时用Requests?何时切Selenium?
基于以上理解,我们可以得出清晰的决策逻辑图:
坚定不移地使用 Requests:
- 目标数据在页面初始HTML中,无需JS加载。
- 网站主要通过请求头(如
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Authorization</font>,<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Tokens</font>)进行反爬,你需要精确伪造。 - 需要进行高频、快速的API接口调用。
果断切换至 Selenium:
- 目标数据由JavaScript动态渲染/异步加载(如通过Ajax)。
- 需要与页面进行复杂交互后才能获取数据(如登录、翻页、下拉)。
- 网站使用了复杂的浏览器环境检测。
混合策略的精髓:
用Selenium做"钥匙",用Requests做"收割机" 。让Selenium去完成那些需要浏览器环境才能完成的"脏活累活"(如登录、获取Cookie、触发JS),然后将其获得的关键身份凭证(如Cookies)和构造好的请求头,交给高效的Requests去进行大规模的数据请求。
三、实战构建:混合爬虫处理需要登录的网站
假设我们要爬取一个网站<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">https://example.com/data</font>,该网站需要登录,且数据列表由JS渲染。
我们的策略是:
- 使用
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Selenium</font>模拟登录,获取登录后的Cookies和关键请求头。 - 将这些Cookies和请求头移植到
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Requests</font>的会话中。 - 使用
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Requests</font>去请求数据API,高效获取数据。
步骤1:使用Selenium完成登录
python
plain
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
def login_with_selenium():
"""使用Selenium模拟登录,并返回关键的Cookies和User-Agent"""
print("启动Selenium进行登录...")
# 配置浏览器选项(可选:无头模式)
options = webdriver.ChromeOptions()
# options.add_argument('--headless') # 生产环境可开启
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36')
driver = webdriver.Chrome(options=options)
try:
# 访问登录页面
driver.get('https://example.com/login')
# 显式等待,找到用户名和密码输入框
username_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "username"))
)
password_input = driver.find_element(By.ID, "password")
# 输入凭据并提交
username_input.send_keys("your_username")
password_input.send_keys("your_password")
driver.find_element(By.ID, "login-btn").click()
# 等待登录成功,例如等待某个登录后才出现的元素
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "user-dashboard"))
)
print("登录成功!")
# 关键步骤:获取登录后的Cookies和浏览器实际的User-Agent
cookies = driver.get_cookies()
user_agent = driver.execute_script("return navigator.userAgent;")
return cookies, user_agent
finally:
# 关闭浏览器
driver.quit()
# 执行登录函数
selenium_cookies, selenium_user_agent = login_with_selenium()
步骤2:将Selenium的"状态"移植到Requests
python
plain
import requests
def create_requests_session(cookies, user_agent):
"""创建一个携带了Selenium状态的Requests会话"""
session = requests.Session()
# 1. 设置User-Agent
session.headers.update({
'User-Agent': user_agent,
# 可以在这里添加其他在Selenium中观察到的固定请求头
'Referer': 'https://example.com/',
'Accept': 'application/json, text/plain, */*' # 根据实际情况修改
})
# 2. 处理Cookies:将Selenium的cookies格式转换为Requests可用的格式
requests_cookies = {}
for cookie in cookies:
requests_cookies[cookie['name']] = cookie['value']
# 将cookies更新到会话中
session.cookies.update(requests_cookies)
return session
# 创建混合爬虫会话
hybrid_session = create_requests_session(selenium_cookies, selenium_user_agent)
步骤3:使用Requests进行高效数据爬取
现在,我们可以用这个<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">hybrid_session</font>去请求数据接口了。这个接口可能是一个返回JSON的API。
python
plain
dimport requests
# 代理配置信息
proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"
def create_requests_session_with_proxy(cookies, user_agent):
"""创建一个携带了Selenium状态和代理配置的Requests会话"""
session = requests.Session()
# 设置代理
proxies = {
'http': f'http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}',
'https': f'http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}'
}
session.proxies.update(proxies)
# 设置User-Agent和其他请求头
session.headers.update({
'User-Agent': user_agent,
'Referer': 'https://example.com/',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Connection': 'keep-alive'
})
# 处理Cookies
requests_cookies = {}
for cookie in cookies:
requests_cookies[cookie['name']] = cookie['value']
session.cookies.update(requests_cookies)
return session
# 使用带代理的Session创建函数
hybrid_session_with_proxy = create_requests_session_with_proxy(selenium_cookies, selenium_user_agent)
def fetch_data_with_proxy_session(session):
"""使用已经配置好代理的会话请求数据"""
api_url = "https://example.com/api/data-list"
try:
# 直接使用session,代理已经在session中配置好了
response = session.get(api_url, timeout=30)
response.raise_for_status()
data = response.json()
print(f"成功获取到 {len(data.get('items', []))} 条数据。")
for item in data['items']:
print(f"处理数据: {item['id']} - {item['title']}")
return data
except requests.exceptions.RequestException as e:
print(f"请求数据时发生错误: {e}")
return None
# 执行数据抓取
data = fetch_data_with_proxy_session(hybrid_session_with_proxy)
四、策略进阶与注意事项
- 请求头同步 :除了
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">User-Agent</font>和<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Cookies</font>,确保其他重要请求头(如<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Referer</font>,<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Accept-Language</font>等)在<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Requests</font>会话中也保持一致。使用浏览器的开发者工具(Network面板)仔细检查。 - 会话保持 :
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Requests.Session()</font>对象会自动处理Cookies的更新。如果后续请求会更新Cookies,这个会话会保持住状态。 - 错误处理与重试 :在
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">fetch_data_with_requests</font>函数中,加入重试机制。如果请求失败(可能是Cookie过期),可以触发一个信号,让混合爬虫重新执行<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">login_with_selenium</font>流程。 - 性能对比:在同一任务上,混合爬虫的速度通常比纯Selenium方案快5-10倍甚至更多,因为避免了所有浏览器的渲染开销。
结论
构建混合爬虫的核心思想是扬长避短,物尽其用 。通过理解<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Requests</font>和<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Selenium</font>在处理请求头和页面渲染上的根本差异,我们能够做出最明智的技术选型。
**<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Requests</font>**是你的特种部队,精准、高效,负责主要的数据攻坚任务。**<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Selenium</font>**是你的工程兵,能处理复杂地形(JS交互),为特种部队扫清障碍(获取认证信息)。