使用Scrapy爬取需登录网站时出现403错误,代码无法运行求助
分析与修复Scrapy登录返回403的问题
你的代码返回403主要是反爬机制拦截和代码本身的几个细节问题导致的,以下是具体分析和修复方案:
1. 验证码字段未正确处理
代码里g-recaptcha-response填了空格,而Classmates.com的登录页面启用了reCAPTCHA验证,这个字段需要真实有效的验证码响应值才能通过验证。空值或无效值会直接触发403拦截。
临时测试方案:手动在浏览器完成验证码,然后从浏览器的登录请求中复制g-recaptcha-response的真实值填入formdata;生产环境则需要对接验证码识别服务。
2. 默认User-Agent易被识别
Scrapy默认的User-Agent格式为Scrapy/version (+https://scrapy.org),很容易被反爬系统标记为爬虫。需要替换为真实浏览器的User-Agent。
修复方法:
在项目的settings.py中全局设置:
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'
或者在请求中手动指定:
def start_requests(self): yield scrapy.Request( self.login_url, callback=self.login, 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'} )
3. start_urls初始化不符合规范
你在__init__里把start_urls设为字符串,但Scrapy的start_urls预期是列表类型。虽然重写start_requests方法后不会直接触发错误,但建议修正以符合代码规范:
def __init__(self): self.start_urls = [self.login_url]
4. FormRequest表单定位可能出错
FormRequest.from_response默认会自动查找页面第一个表单,如果页面存在多个表单,可能会定位错误。可以通过formid参数明确指定登录表单:
yield FormRequest.from_response( response, formid='login-form', # 精准匹配登录表单的id属性 formdata={ '_csrf': token, 'successUrl': '', # 这里应该是空字符串,而非空格 'g-recaptcha-response': '真实验证码响应值', 'emailOrRegId': 'user@mail.com', 'password': 'some password', 'rememberme': 'yes' }, callback=self.start_scraping, headers={'Referer': self.login_url} # 手动添加Referer头,模拟真实请求逻辑 )
5. 显式传递Cookie增强请求真实性
部分网站会校验Cookie的连贯性,虽然FormRequest.from_response默认会处理,但显式传递第一次访问登录页面获取的Cookie,可以降低被拦截概率:
def login(self, response): token = response.css("form[id*=login-form] input[name*=csrf]::attr(value)").extract_first() yield FormRequest.from_response( response, formid='login-form', formdata={...}, # 你的表单数据 callback=self.start_scraping, cookies=response.cookies # 显式传递Cookie )
修复后的完整代码示例
import scrapy from scrapy import Spider from scrapy.http import FormRequest class HiddenDataLoginSpider(Spider): name = 'images' login_url = 'https://secure.classmates.com/auth/login' def __init__(self): self.start_urls = [self.login_url] def start_requests(self): yield scrapy.Request( self.login_url, callback=self.login, 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' } ) def login(self, response): token = response.css("form[id*=login-form] input[name*=csrf]::attr(value)").extract_first() # 注意:g-recaptcha-response需要替换成真实的验证码响应值 yield FormRequest.from_response( response, formid='login-form', formdata={ '_csrf': token, 'successUrl': '', 'g-recaptcha-response': 'YOUR_RECAPTCHA_RESPONSE', 'emailOrRegId': 'user@mail.com', 'password': 'some password', 'rememberme': 'yes' }, callback=self.start_scraping, headers={ 'Referer': self.login_url, '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' } ) def start_scraping(self, response): # 先检查登录状态 print("响应状态码:", response.status) print("页面标题:", response.css('title::text').get()) print("页面h3元素:", response.css('h3').getall())
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

