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
相关产品推荐
相关产品推荐

