首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python爬虫伪装策略:如何模拟浏览器正常访问JSP站点

Python爬虫伪装策略:如何模拟浏览器正常访问JSP站点

原创
作者头像
小白学大数据
发布2025-11-27 16:44:45
发布2025-11-27 16:44:45
500
举报

一、 为何JSP站点需要伪装?反爬虫机制探秘

在编写代码之前,理解我们的“对手”至关重要。JSP站点通常通过以下几种方式识别和拦截爬虫:

  1. User-Agent检测:这是最基础的检测点。使用Python的requests库默认的User-Agent会直接暴露爬虫身份。
  2. 会话与Cookie管理:JSP应用严重依赖JSESSIONID等Cookie来维持用户会话。不处理Cookie,就无法保持登录状态或通过某些验证流程。
  3. Referer验证:某些图片或API接口会校验请求头中的Referer字段,确保请求来源于站内页面,而非直接访问。
  4. 请求频率与行为模式:人类不会在秒级内发起大量请求。过高的访问频率是触发封禁的最快途径。
  5. JavaScript挑战:部分JSP站点也会使用JavaScript进行简单的计算或跳转,虽然复杂度不及React/Vue应用,但足以拦截基础的requests库。
  6. IP地址封禁:当上述所有特征都指向爬虫时,服务器最终会记录并封禁您的IP地址。

二、 核心伪装策略:从“毛坯”到“精装”

我们的目标是将一个赤裸的HTTP请求,包装成一个由真实浏览器发出的、可信的请求。

策略一:完善HTTP请求头

这是伪装的第一步,也是最关键的一步。一个真实的浏览器请求头包含丰富的信息。

关键字段:

  • User-Agent: 标识操作系统和浏览器类型。
  • Referer: 表明当前请求是从哪个页面链接过来的。
  • Accept: 声明客户端能接收的内容类型。
  • Accept-Language: 声明浏览器接受的语言。
  • Connection: 保持连接。
策略二:会话维持

使用requests.Session()对象。它会自动处理Cookie,在多次请求间保持会话状态,就像浏览器一样。

策略三:请求频率管理

在请求间引入随机延时,模拟人类阅读和点击的间隔。使用time.sleep()

策略四:应对JavaScript(中级策略)

当简单的请求头伪装无效时,可能是遇到了JavaScript挑战。此时需要动用SeleniumPlaywright等浏览器自动化工具,它们能驱动真实浏览器内核(如Chrome)执行页面上的所有JavaScript代码。

三、 代码实战:从基础到进阶

假设我们的目标是爬取一个名为 http://example-jsp-site.com/gallery.jsp 的图片画廊。

1. 基础伪装:使用Requests + 请求头
代码语言:javascript
复制
import 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

代码语言:javascript
复制
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
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
import os

# 代理配置信息
proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"

# 配置Chrome选项,使其更接近真实用户
chrome_options = Options()

# 设置代理服务器
proxy_url = f"{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"
chrome_options.add_argument(f'--proxy-server=http://{proxy_url}')

# 可选:无头模式(不显示浏览器界面)
# chrome_options.add_argument("--headless")

# 设置一个常见的用户代理
chrome_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")

# 禁用自动化测试标志,避免被检测为WebDriver
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
chrome_options.add_argument('--disable-blink-features=AutomationControlled')

# 对于需要认证的代理,可以安装扩展来处理认证
from selenium.webdriver.chrome.options import Options as ChromeOptions

# 初始化WebDriver
driver = webdriver.Chrome(options=chrome_options) # 请确保chromedriver在PATH中

# 处理代理认证的替代方案(如果上面的方法不工作)
def enable_proxy_auth(proxy_host, proxy_port, proxy_username, proxy_password):
    """
    通过执行JavaScript来设置代理认证
    这是一个备选方案
    """
    from selenium.webdriver.common.proxy import Proxy, ProxyType
    
    proxy = Proxy()
    proxy.proxy_type = ProxyType.MANUAL
    proxy.http_proxy = f"{proxy_host}:{proxy_port}"
    proxy.ssl_proxy = f"{proxy_host}:{proxy_port}"
    
    # 创建代理认证扩展
    auth_extension_path = create_proxy_auth_extension(proxy_host, proxy_port, proxy_username, proxy_password)
    if auth_extension_path:
        chrome_options.add_extension(auth_extension_path)

def create_proxy_auth_extension(proxy_host, proxy_port, proxy_username, proxy_password):
    """
    创建代理认证扩展
    """
    import zipfile
    import os
    import string
    import random
    
    # 生成扩展的manifest.json
    manifest_json = """
    {
        "version": "1.0.0",
        "manifest_version": 2,
        "name": "Chrome Proxy",
        "permissions": [
            "proxy",
            "tabs",
            "unlimitedStorage",
            "storage",
            "<all_urls>",
            "webRequest",
            "webRequestBlocking"
        ],
        "background": {
            "scripts": ["background.js"]
        },
        "minimum_chrome_version":"22.0.0"
    }
    """
    
    # 生成背景脚本
    background_js = """
    var config = {
            mode: "fixed_servers",
            rules: {
              singleProxy: {
                scheme: "http",
                host: "%s",
                port: parseInt(%s)
              },
              bypassList: ["localhost"]
            }
          };
    
    chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});
    
    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站点的访问。我们来总结一下核心步骤:

  1. 伪装请求头:使用真实、多样的User-Agent和其他头部信息。
  2. 维持会话:使用Session对象自动处理Cookies。
  3. 管理频率:在请求间引入随机延时,避免高频冲击。
  4. 处理动态内容:当JS成为障碍时,升级使用SeleniumPlaywright
  5. 遵守robots.txt:在爬取前,检查目标网站的/robots.txt文件,尊重网站管理员的意愿。

技术伦理提醒:爬虫技术是一把双刃剑。在实践过程中,请务必:

  • 尊重数据版权和网站的服务条款。
  • 控制访问压力,避免对目标网站的正常运营造成影响。
  • 不爬取个人隐私和敏感数据
  • 将获取的数据用于合法、正当的目的

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、 为何JSP站点需要伪装?反爬虫机制探秘
  • 二、 核心伪装策略:从“毛坯”到“精装”
    • 策略一:完善HTTP请求头
    • 策略二:会话维持
    • 策略三:请求频率管理
    • 策略四:应对JavaScript(中级策略)
  • 三、 代码实战:从基础到进阶
    • 1. 基础伪装:使用Requests + 请求头
    • 2. 进阶伪装:使用Selenium应对复杂场景
  • 四、 策略总结与伦理规范
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档