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

Python中POST请求与JS动态内容爬取的登录问题

解决方案

方案一:直接模拟浏览器登录操作(推荐)

既然要用Selenium处理动态内容,直接模拟用户填写表单并提交的操作是最稳妥的——全程用同一个浏览器实例,自动维护会话、CSRF token和所有关联的请求上下文,完全避开手动POST的会话不一致问题。

修改后的代码

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Chrome Options
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')

# 初始化普通Selenium驱动(不需要seleniumrequests)
driver = webdriver.Chrome(service=Service('/usr/local/bin/chromedriver'), options=chrome_options)
wait = WebDriverWait(driver, 10)

login_url = 'https://example.com/login'
target_url = 'https://example.com/profile'

try:
    # 打开登录页
    driver.get(login_url)
    
    # 等待并填写用户名、密码
    username_input = wait.until(EC.presence_of_element_located((By.NAME, 'username')))
    password_input = wait.until(EC.presence_of_element_located((By.NAME, 'password')))
    username_input.send_keys('你的用户名')
    password_input.send_keys('你的密码')
    
    # 找到登录按钮并点击(或者直接提交表单)
    login_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'button[type="submit"]')))
    login_button.click()
    
    # 等待登录完成(可通过URL变化或目标元素出现判断)
    wait.until(EC.url_contains(target_url.split('/')[-1]))
    
    # 访问目标页并获取动态内容
    driver.get(target_url)
    wait.until(EC.presence_of_element_located((By.TAG_NAME, 'vue-app')))  # 等待Vue内容加载完成
    page_html = driver.page_source
    print(page_html)
finally:
    driver.quit()

方案二:在Selenium中用JS发送POST请求

如果必须手动发送POST请求,可以利用Selenium的execute_script方法,在浏览器当前会话中执行JavaScript发送AJAX请求——这样请求会自动携带当前浏览器的会话信息,解决token不一致问题。

示例代码

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')

driver = webdriver.Chrome(service=Service('/usr/local/bin/chromedriver'), options=chrome_options)
wait = WebDriverWait(driver, 10)

login_url = 'https://example.com/login'
target_url = 'https://example.com/profile'

try:
    driver.get(login_url)
    
    # 获取页面中的CSRF token
    csrf_token = wait.until(EC.presence_of_element_located((By.NAME, 'user[_csrf_token]'))).get_attribute('value')
    
    # 用JS发送POST请求,保持当前会话
    login_script = f"""
        return fetch('{login_url}', {{
            method: 'POST',
            credentials: 'include',  // 携带当前会话的凭证
            headers: {{
                'Content-Type': 'application/x-www-form-urlencoded'
            }},
            body: new URLSearchParams({{
                'username': '你的用户名',
                'password': '你的密码',
                'user[_csrf_token]': '{csrf_token}'
            }})
        }}).then(response => response.text());
    """
    driver.execute_script(login_script)
    
    # 等待登录生效,再访问目标页
    driver.get(target_url)
    wait.until(EC.presence_of_element_located((By.TAG_NAME, 'vue-app')))
    page_html = driver.page_source
    print(page_html)
finally:
    driver.quit()

原代码无效的原因

seleniumrequests的request方法本质是调用requests库单独发送请求,并没有和Selenium的浏览器会话共享Cookie、Session等上下文——相当于两个完全独立的客户端,所以你获取的CSRF token属于Selenium的会话,而POST请求用的是requests的全新会话,自然会出现token不匹配的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 03:33:12