You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django视图间对象传递及LinkedIn登录验证码交互实现问题

解决Django视图中LinkedIn登录验证码Checkpoint的交互问题

你的核心问题在于:每次请求verify_linkedin视图时都会创建一个全新的LinkedinScraper实例,当第一次请求触发checkpoint返回表单后,原来的WebDriver实例已经被销毁;用户提交验证码时,新创建的LinkedinScraper根本不在checkpoint页面,自然无法完成验证。

WebDriver实例本身不能序列化,没法直接存在Django的session里,但我们可以通过以下两种方案解决这个状态保持的问题:


方案一:使用远程ChromeDriver复用会话

这是最可靠的方案,因为它允许跨请求复用同一个浏览器实例。

步骤1:启动远程ChromeDriver服务

先在服务器上启动一个远程ChromeDriver服务(确保已安装Chrome和对应版本的ChromeDriver):

chromedriver --port=9515 --url-base=/wd/hub

步骤2:修改LinkedinScraper类支持远程连接

更新你的Webscraper后端代码,让它可以从session中读取已有的会话ID,复用浏览器实例:

from selenium.webdriver.remote.webdriver import WebDriver
from selenium import webdriver

class LinkedinScraper(WebScraper):
    def __init__(self, session_id=None, command_executor="http://localhost:9515/wd/hub", headless=True, **kwargs):
        super().__init__()
        if session_id:
            # 复用已存在的浏览器会话
            self.driver = WebDriver(command_executor=command_executor, desired_capabilities={})
            self.driver.close()  # 关闭默认新建的空白窗口
            self.driver.session_id = session_id
        else:
            # 创建新的浏览器实例
            options = webdriver.ChromeOptions()
            if headless:
                options.add_argument("--headless=new")
            options.add_argument("--no-sandbox")
            options.add_argument("--disable-dev-shm-usage")
            # 添加UA模拟真实浏览器,避免被LinkedIn检测
            options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36")
            self.driver = webdriver.Remote(command_executor=command_executor, options=options)
        self.data = {}
        self.pause = 10
        self.retries = 0
        self.max_retries = 3

    # 保留原有的login_to_linkedin和authenticate_linkedin_login方法

步骤3:修改Django视图复用会话

更新verify_linkedin视图,将WebDriver的会话ID存在用户的session中,实现跨请求复用:

def verify_linkedin(request):
    # 从session获取已有的浏览器会话ID
    session_id = request.session.get('linkedin_driver_session_id')
    ln = LinkedinScraper(session_id=session_id)

    if request.method == "POST":
        # 用户提交验证码,执行验证逻辑
        form = VerifyLinkedinForm(request.POST)
        if form.is_valid():
            pin_code = form.cleaned_data['verification_key']
            try:
                ln.authenticate_linkedin_login(pin_code)
                # 登录成功,清理session并关闭浏览器
                request.session.pop('linkedin_driver_session_id', None)
                ln.driver.quit()
                return redirect("home")
            except Exception as e:
                ln.driver.quit()
                return HttpResponse(f"<h1>验证失败:{str(e)}</h1>")
    else:
        # 首次请求,尝试自动登录
        login_success = ln.login_to_linkedin(
            username=os.getenv("LINKEDIN_USERNAME"),
            password=os.getenv("LINKEDIN_PASSWORD")
        )
        if login_success:
            # 无验证直接登录成功,清理资源
            ln.driver.quit()
            return HttpResponse("<h1>You are verified</h1>")
        else:
            # 触发checkpoint,保存会话ID到session
            request.session['linkedin_driver_session_id'] = ln.driver.session_id
            form = VerifyLinkedinForm()
            context = {"form": form}
            return render(request, "linkedin_verify.html", context)

方案二:保存浏览器状态(Cookie + 当前URL)

如果不想依赖远程ChromeDriver服务,可以在第一次触发checkpoint时,把浏览器的Cookie和当前URL存在session里,提交验证码时重新初始化WebDriver并恢复状态:

修改LinkedinScraper类添加状态保存/恢复方法

class LinkedinScraper(WebScraper):
    # 保留原有的__init__、login_to_linkedin、authenticate_linkedin_login方法

    def save_state(self):
        """保存当前浏览器的关键状态(Cookie + 页面URL)"""
        return {
            'cookies': self.driver.get_cookies(),
            'current_url': self.driver.current_url
        }

    def restore_state(self, state):
        """恢复之前的浏览器状态"""
        self.driver.get(state['current_url'])
        for cookie in state['cookies']:
            # 处理SameSite属性的兼容性问题
            if 'sameSite' in cookie and cookie['sameSite'] not in ['Strict', 'Lax', 'None']:
                cookie['sameSite'] = 'Lax'
            self.driver.add_cookie(cookie)
        # 重新加载页面确保Cookie生效
        self.driver.get(state['current_url'])

修改Django视图使用状态保存逻辑

def verify_linkedin(request):
    if request.method == "POST":
        form = VerifyLinkedinForm(request.POST)
        if form.is_valid():
            pin_code = form.cleaned_data['verification_key']
            # 恢复之前保存的浏览器状态
            ln = LinkedinScraper()
            state = request.session.get('linkedin_login_state')
            if not state:
                return HttpResponse("<h1>会话已过期,请重新尝试登录</h1>")
            ln.restore_state(state)
            try:
                ln.authenticate_linkedin_login(pin_code)
                request.session.pop('linkedin_login_state', None)
                ln.driver.quit()
                return redirect("home")
            except Exception as e:
                ln.driver.quit()
                return HttpResponse(f"<h1>验证失败:{str(e)}</h1>")
    else:
        ln = LinkedinScraper()
        login_success = ln.login_to_linkedin(
            username=os.getenv("LINKEDIN_USERNAME"),
            password=os.getenv("LINKEDIN_PASSWORD")
        )
        if login_success:
            ln.driver.quit()
            return HttpResponse("<h1>You are verified</h1>")
        else:
            # 保存状态到session,然后关闭当前实例
            request.session['linkedin_login_state'] = ln.save_state()
            ln.driver.quit()
            form = VerifyLinkedinForm()
            context = {"form": form}
            return render(request, "linkedin_verify.html", context)

关键注意事项

  1. 会话过期处理:给session设置合理的过期时间(比如10分钟),避免无效的状态占用资源。
  2. 资源清理:无论登录成功还是失败,一定要调用driver.quit()关闭浏览器实例,防止内存泄漏。
  3. 反爬规避:LinkedIn对自动化工具检测严格,除了添加UA,还可以尝试禁用自动化标识:
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option('useAutomationExtension', False)
    

内容的提问来源于stack exchange,提问作者pAulseperformance

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 11:17:40