Scrapy分页执行但所有页面均返回第一页数据问题排查
问题排查与修复方案
我帮你梳理了代码里的几个核心问题,这应该就是导致所有页面返回第一页数据、数据异常的原因:
1. 重复使用同一个Item对象,导致数据被覆盖
你在parse方法开头就创建了一个HotelAbbasiItem实例,然后在循环里反复给这个实例的字段赋值并yield。因为Python里对象是引用传递的,每次yield的都是同一个Item对象,最后所有输出的Item都会被最后一次循环的赋值覆盖,看起来就像所有数据都是第一页的最后一条。
修复方法:把Item的创建放到for循环内部,每次循环都生成新的实例:
def parse(self,response): all_div_parts = response.css('div.hotels-community-tab-common-Card__section--4r93H') for part in all_div_parts: # 每次循环新建一个Item对象 items = HotelAbbasiItem() reviewer = part.css('a.social-member-event-MemberEventOnObjectBlock__member--35-jC::text').extract() DateOfReview = part.css('span::text').extract() Nationality = part.css('span.small::text').extract() Contribution = part.css('span.social-member-MemberHeaderStats__bold--3z3qh::text').extract() ReviewText = part.css('q.location-review-review-list-parts-ExpandableReview__reviewText--gOmRC>span::text').extract() Rating = part.css('div.location-review-review-list-parts-RatingLine__bubbles--GcJvM>span::attr(class)').extract() items['reviewer'] = reviewer items['DateOfReview'] = DateOfReview items['Nationality'] = Nationality items['Contribution'] = Contribution items['ReviewText'] = ReviewText items['Rating'] = Rating yield items # 翻页逻辑后续修改
2. 翻页选择器错误+反爬机制,导致重复获取第一页
你提到所有页面都返回第一页数据,主要有两个可能:
- 你当前的翻页选择器
div.is-centered>a.primary无法正确定位到TripAdvisor的下一页按钮,导致提取的链接是当前页或者为空,反复请求第一页; - TripAdvisor的反爬机制识别了你的爬虫,把所有请求都重定向回第一页。
修复翻页选择器
TripAdvisor的下一页按钮标准选择器是a.nav.next::attr(href),替换原有的翻页逻辑:
# 替换原翻页代码 next_page = response.css('a.nav.next::attr(href)').extract_first() if next_page: next_page_url = response.urljoin(next_page) # 添加浏览器请求头,避免被反爬识别 yield scrapy.Request( url=next_page_url, callback=self.parse, headers={ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } )
反爬优化建议
TripAdvisor反爬很严格,建议额外做这些设置:
- 在
settings.py里添加DOWNLOAD_DELAY = 2,控制请求频率,避免被封禁; - 长期爬取的话,可以考虑使用代理IP,或者启用Scrapy的Cookies中间件保持会话;
- 尽量使用
extract_first(default='')替代extract()获取单值数据,避免Item里出现空列表,比如:reviewer = part.css('a.social-member-event-MemberEventOnObjectBlock__member--35-jC::text').extract_first(default='')
内容的提问来源于stack exchange,提问作者Hny




