一、 为何JSP站点需要伪装?反爬虫机制探秘 在编写代码之前,理解我们的“对手”至关重要。JSP站点通常通过以下几种方式识别和拦截爬虫: User-Agent检测:这是最基础的检测点。使用Python的requests库默认的User-Agent会直接暴露爬虫身份。 会话与Cookie管理:JSP应用严重依赖JSESSIONID等Cookie来维持用户会话。不处理Cookie,就无法保持登录状态或通过某些验证流程。 Referer验证:某些图片或API接口会校验请求头中的Referer字段,确保请求来源于站内页面,而非直接访问。 请求频率与行为模式:人类不会在秒级内发起大量请求。过高的访问频率是触发封禁的最快途径。 JavaScript挑战:部分JSP站点也会使用JavaScript进行简单的计算或跳转,虽然复杂度不及React/Vue应用,但足以拦截基础的requests库。 IP地址封禁:当上述所有特征都指向爬虫时,服务器最终会记录并封禁您的IP地址。 二、 核心伪装策略:从“毛坯”到“精装” 我们的目标是将一个赤裸的HTTP请求,包装成一个由真实浏览器发出的、可信的请求。 策略一:完善HTTP请求头 这是伪装的第一步,也是最关键的一步。一个真实的浏览器请求头包含丰富的信息。 关键字段: User-Agent: 标识操作系统和浏览器类型。 Referer: 表明当前请求是从哪个页面链接过来的。 Accept: 声明客户端能接收的内容类型。 Accept-Language: 声明浏览器接受的语言。 Connection: 保持连接。 策略二:会话维持 使用requests.Session()对象。它会自动处理Cookie,在多次请求间保持会话状态,就像浏览器一样。 策略三:请求频率管理 在请求间引入随机延时,模拟人类阅读和点击的间隔。使用time.sleep()。 策略四:应对JavaScript(中级策略) 当简单的请求头伪装无效时,可能是遇到了JavaScript挑战。此时需要动用Selenium或Playwright等浏览器自动化工具,它们能驱动真实浏览器内核(如Chrome)执行页面上的所有JavaScript代码。 三、 代码实战:从基础到进阶 假设我们的目标是爬取一个名为 http://example-jsp-site.com/gallery.jsp 的图片画廊。
- 基础伪装:使用Requests + 请求头
import time import random from bs4 import BeautifulSoup
定义一个常见的浏览器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", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36" ]
创建一个会话对象
session = requests.Session()
为目标URL构造一个看起来真实的请求头
headers = { 'User-Agent': random.choice(USER_AGENTS), 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', } session.headers.update(headers)
try: # 首先访问主画廊页面,Referer可以是搜索引擎或站内首页 gallery_url = "http://example-jsp-site.com/gallery.jsp" response = session.get(gallery_url, timeout=10) response.raise_for_status() # 如果状态码不是200,则抛出异常
# 使用BeautifulSoup解析HTML
soup = BeautifulSoup(response.text, 'html.parser')
# 假设图片链接在 <img> 标签的 `src` 属性中,且位于class为'gallery-img'的div下
image_elements = soup.select('div.gallery-img img')
for index, img in enumerate(image_elements):
# 构造完整的图片URL(处理相对路径)
img_src = img.get('src')
if img_src.startswith('/'):
img_url = "http://example-jsp-site.com" + img_src
else:
img_url = img_src
# 为图片请求设置Referer,表明是从gallery.jsp页面来的
img_headers = {'Referer': gallery_url}
# 请求图片内容
print(f"正在下载图片 {index+1}: {img_url}")
img_response = session.get(img_url, headers=img_headers)
img_response.raise_for_status()
# 将图片保存到本地
with open(f'image_{index+1}.jpg', 'wb') as f:
f.write(img_response.content)
# !!! 重要:在请求间添加随机延时,模拟人类行为 !!!
sleep_time = random.uniform(1, 3) # 随机等待1-3秒
time.sleep(sleep_time)except requests.exceptions.RequestException as e: print(f"网络请求出错: {e}")
2. 进阶伪装:使用Selenium应对复杂场景
如果目标站点必须执行JavaScript才能加载内容,requests就无能为力了。这时需要Selenium。
``` from selenium import webdriver
function callbackFn(details) {
return {
authCredentials: {
username: "%s",
password: "%s"
}
};
}
chrome.webRequest.onAuthRequired.addListener(
callbackFn,
{urls: ["<all_urls>"]},
['blocking']
);
""" % (proxy_host, proxy_port, proxy_username, proxy_password)
# 创建临时扩展文件
extension_dir = 'proxy_auth_extension'
if not os.path.exists(extension_dir):
os.makedirs(extension_dir)
with open(os.path.join(extension_dir, "manifest.json"), "w") as f:
f.write(manifest_json)
with open(os.path.join(extension_dir, "background.js"), "w") as f:
f.write(background_js)
# 创建ZIP文件
extension_path = os.path.join(extension_dir, "extension.zip")
with zipfile.ZipFile(extension_path, 'w') as zp:
zp.write(os.path.join(extension_dir, "manifest.json"), "manifest.json")
zp.write(os.path.join(extension_dir, "background.js"), "background.js")
return extension_path
# 如果简单代理设置不工作,使用扩展方式
# enable_proxy_auth(proxyHost, proxyPort, proxyUser, proxyPass)
try:
# 访问目标页面
print("正在通过代理访问目标页面...")
driver.get("http://example-jsp-site.com/gallery.jsp")
# 使用显式等待,等待图片容器加载完成,而不是使用固定的time.sleep
wait = WebDriverWait(driver, 10)
# 假设图片加载在一个id为'imageContainer'的元素里
image_container = wait.until(EC.presence_of_element_located((By.ID, "imageContainer")))
# 在页面中执行JavaScript,模拟滚动以确保所有懒加载图片都被触发
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2) # 等待滚动后加载
# 查找所有图片元素
img_elements = driver.find_elements(By.CSS_SELECTOR, "div.gallery-img img")
# 创建目录保存图片
if not os.path.exists('selenium_images'):
os.makedirs('selenium_images')
print(f"找到 {len(img_elements)} 张图片")
for index, img in enumerate(img_elements):
img_url = img.get_attribute('src')
print(f"通过Selenium获取到图片链接 {index+1}: {img_url}")
# 为了下载,我们可以使用requests会话,但需要传递Selenium获得的Cookie
# 或者,也可以直接通过Selenium截图,但这里演示用requests下载(更高效)
# 注意:通过Selenium获取的链接可能是动态加载的,直接用requests下载时可能需要保持相同的会话。
# 更稳妥的方法是继续使用Selenium来处理,或者将Cookie从Selenium传递给requests会话。
except Exception as e:
print(f"发生错误: {e}")
finally:
# 关闭浏览器
print("爬取完成,关闭浏览器...")
driver.quit()
# 清理临时扩展文件
import shutil
if os.path.exists('proxy_auth_extension'):
shutil.rmtree('proxy_auth_extension')四、 策略总结与伦理规范 通过上述策略和代码,我们已经能够成功模拟一个正常浏览器对JSP站点的访问。我们来总结一下核心步骤: 伪装请求头:使用真实、多样的User-Agent和其他头部信息。 维持会话:使用Session对象自动处理Cookies。 管理频率:在请求间引入随机延时,避免高频冲击。 处理动态内容:当JS成为障碍时,升级使用Selenium或Playwright。 遵守robots.txt:在爬取前,检查目标网站的/robots.txt文件,尊重网站管理员的意愿。 技术伦理提醒:爬虫技术是一把双刃剑。在实践过程中,请务必: 尊重数据版权和网站的服务条款。 控制访问压力,避免对目标网站的正常运营造成影响。 不爬取个人隐私和敏感数据。 将获取的数据用于合法、正当的目的。


