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

Scrapy登录失效、无状态提示及页面爬取保存异常求助

问题分析与解决方案

从你的日志和代码来看,核心问题有两个:登录逻辑完全没有被执行,以及文件名生成逻辑导致文件被覆盖。我们一步步来拆解解决:

1. 登录逻辑未触发的核心原因:方法名拼写错误

Scrapy Spider中用来生成初始请求的标准方法是start_requests()(注意是复数形式),但你的代码里写的是start_request()(单数)——这个方法Scrapy根本不会主动调用!

所以你的登录流程完全没启动,爬虫直接走了start_urls里的请求,结果index.php因为未登录被302重定向到login.php,之后只是被动爬取了登录页和注册页的链接,根本没尝试执行登录操作,自然不会输出登录状态的日志。

2. 仅生成一个文件的原因:文件名提取逻辑不合理

你的parse_item方法里用response.url.split("/")[-2]生成文件名,比如http://145.100.108.148/login2/login.php和http://145.100.108.148/login2/register.php的split("/")[-2]都是login2,这就导致两个页面会写入同一个文件,后面的内容直接覆盖前面的,最后只剩一个文件。


修正后的完整代码

from scrapy.http import Request, FormRequest
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

class TestSpider(CrawlSpider):
    name = 'testspider'
    login_page = 'http://145.100.108.148/login2/login.php'
    # 暂时留空start_urls,避免未登录时请求index.php被重定向
    start_urls = []
    rules = (
        Rule(LinkExtractor(allow=r'.*'), callback='parse_item', follow=True),
    )
    login_user = 'test@hotmail.com'
    login_pass = 'test'

    def start_requests(self):
        """This function is called before crawling starts"""
        yield Request(url=self.login_page, callback=self.login)

    def login(self, response):
        """Generate a login request"""
        return FormRequest.from_response(
            response,
            formdata={
                'email': self.login_user,
                'pass': self.login_pass
            },
            callback=self.check_login_response
        )

    def check_login_response(self, response):
        """Check the response returned by a login request to see if we are successfully logged in"""
        if b"Dashboard" in response.body:
            self.logger.info("successfully logged in. Let's start crawling!")
            # 登录成功后,发起对目标页面的请求,此时会携带登录后的Cookie
            yield Request(url='http://145.100.108.148/login2/index.php')
        else:
            self.logger.info("NOT LOGGED IN :(")
            # 登录失败时主动关闭爬虫,方便排查问题
            self.crawler.engine.close_spider(self, "Login failed with provided credentials")

    def parse_item(self, response):
        """Save pages to disk"""
        self.logger.info('Hi, this is an item page! %s', response.url)
        # 修改文件名生成逻辑,用URL的最后一段作为标识,避免覆盖
        page_name = response.url.split("/")[-1]
        filename = f'scraped-{page_name}'
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)

关键修改点说明

  • 把start_request()改成start_requests(),确保Scrapy会调用你的登录初始化逻辑
  • 留空start_urls,避免未登录时就请求index.php被强制重定向
  • 登录成功后手动生成对index.php的请求,此时请求会携带登录后的认证Cookie,能正常访问目标页面
  • 调整文件名生成逻辑,用URL的最后一段(如login.php、index.php)作为文件名的一部分,彻底解决文件覆盖问题
  • 登录失败时添加了主动关闭爬虫的逻辑,方便快速定位登录失败的问题

预期效果

运行修正后的代码,你会在日志中看到successfully logged in. Let's start crawling!的提示,同时会生成三个独立的文件:scraped-index.php、scraped-login.php、scraped-register.php,分别对应三个页面的内容,爬虫也会带着认证会话正常爬取所有允许的链接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:18:33