使用lxml进行Python网页爬取:Laravel站点登录失败求助
Laravel站点登录爬取失败?试试这几个关键点!
老哥,我之前也踩过Laravel登录爬取的坑,Bitbucket的逻辑相对简单,但Laravel对CSRF防护和会话的处理要严格得多,咱们一步步来解决:
1. 先搞清楚Laravel登录表单的「真实字段」
Laravel默认的登录表单可不是只有账号密码这么简单,你得先抓包看看实际提交的所有字段:
- 打开浏览器开发者工具(F12),进入Network标签,提交登录,找到POST请求的Form Data:
- 肯定有
_token(你说已经拿到了,但要确认是和当前会话绑定的那个) - 可能还有
remember(记住我选项,值可能是on或1) - 字段名可能不是
username,而是email(Laravel默认是邮箱登录) - 个别站点会加
_method字段(值为POST)
- 肯定有
2. 必须用Session保持会话状态
这是最容易忽略的点!requests默认每次请求都是新会话,登录状态根本存不住。你得用requests.Session()来统一管理cookie和会话:
- 拿CSRF Token的请求、提交登录的请求、后续访问页面的请求,全部用同一个Session实例,不然Laravel会认为你是新用户,直接打回登录页。
3. CSRF Token必须和会话绑定
Laravel的CSRF Token是和当前会话的cookie绑定的,你不能先单独发个GET请求拿token,再用新的POST请求提交——必须用同一个Session先访问登录页,拿到token,紧接着用这个Session提交登录。
修复后的示例代码
import requests from lxml import html USERNAME = "你的登录账号" PASSWORD = "你的登录密码" LOGIN_PAGE_URL = "Laravel站点的登录页面URL" TARGET_PAGE_URL = "登录后要访问的页面URL" # 核心:用Session保持会话 session = requests.Session() # 第一步:访问登录页,获取CSRF Token和会话cookie login_response = session.get(LOGIN_PAGE_URL) tree = html.fromstring(login_response.content) # 两种方式拿CSRF Token,选适合你的: # 方式1:从meta标签取(Laravel默认会加这个) csrf_token = tree.xpath('//meta[@name="csrf-token"]/@content')[0] # 方式2:从表单隐藏字段取 # csrf_token = tree.xpath('//input[@name="_token"]/@value')[0] # 第二步:构造登录表单数据,完全对应抓包的字段 login_form_data = { "email": USERNAME, # 改成你抓包看到的字段名,比如"username" "password": PASSWORD, "_token": csrf_token, # 如果抓包有remember字段,加上: # "remember": "on" } # 第三步:模拟浏览器请求头,避免被拦截 headers = { "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", "Referer": LOGIN_PAGE_URL # 很多站点会验证来源页 } # 提交登录请求 login_submit_response = session.post(LOGIN_PAGE_URL, data=login_form_data, headers=headers) # 第四步:验证登录是否成功 result_tree = html.fromstring(login_submit_response.content) # 比如检查页面是否有登录后的标识(比如用户名、欢迎语) welcome_element = result_tree.xpath('//span[@class="user-name"]/text()') if welcome_element: print("登录成功!") # 现在用session访问目标页面,就能拿到登录后的数据了 target_response = session.get(TARGET_PAGE_URL) print("目标页面内容:", target_response.text[:500]) # 打印前500字符 else: print("登录失败,仍在登录页面") # 打印响应内容,看看有没有错误提示(比如CSRF令牌无效、密码错误) print("错误详情:", login_submit_response.text[:1000])
额外排查点
- 如果还是失败,打印
login_submit_response.text,看看页面有没有明确的错误提示(比如「CSRF令牌不匹配」) - 检查是否有验证码:有些Laravel站点会在登录时加验证码,这时候得额外处理验证码识别
- 确认账号密码确实正确:可以手动登录试试,排除凭证问题
内容的提问来源于stack exchange,提问作者Pure Rhymer Organization
相关产品推荐
相关产品推荐

