Scrapy爬虫返回None值及分页实现问题求助
解决Scrapy爬取one-versus-one.com的两个核心问题
一、数据返回全None的修复方案
无报错但拿不到数据,90%是你在浏览器里看到的DOM是JS渲染后的,而Scrapy默认抓的是服务器返回的原始HTML,或者你的选择器路径写错了。
1. 先确认原始HTML结构
在爬虫的parse方法里加一行,把响应内容存到本地:
def parse(self, response): with open('raw_page.html', 'wb') as f: f.write(response.body) # 你的原有抓取代码...
打开raw_page.html,搜索你要的rank、player等元素。如果找不到,说明数据是JS动态加载的,两种解决办法:
- 用Playwright渲染JS:
先装依赖:pip install scrapy-playwright
然后在settings.py里加配置:
爬虫里启用渲染:DOWNLOAD_HANDLERS = { "http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler", "https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler", } PLAYWRIGHT_LAUNCH_OPTIONS = {"headless": True}def start_requests(self): yield scrapy.Request( url='你的目标排名页面URL', meta={"playwright": True} ) - 直接爬API接口:
打开浏览器F12→Network→XHR,刷新页面,找返回排名数据的接口(一般是JSON格式)。比如找到/api/rankings?page=1这种接口,直接请求它比抓页面高效多了,解析JSON就行。
2. 修正选择器路径
如果原始HTML里有目标元素,那就是你的选择器写得不对。别用绝对XPath(比如/html/body/div[3]/...),改用相对路径,比如:
# 先定位每个排名条目容器 for item in response.xpath('//div[contains(@class, "ranking-item")]'): yield { 'rank': item.xpath('.//span[contains(@class, "rank-num")]/text()').get().strip(), 'player': item.xpath('.//div[@class="player-name"]/text()').get().strip(), 'team': item.xpath('.//div[@class="team-label"]/text()').get().strip(), 'ranking_value': item.xpath('.//span[@class="rank-score"]/text()').get().strip() }
注意开头的.,表示从当前item节点开始查找,不是从根节点找。
二、基于data-page的分页实现
不管是分页按钮还是其他元素带data-page属性,直接提取这个属性值构造下一页URL就行:
1. 爬取所有页码
def parse(self, response): # 先处理当前页数据... # 提取所有带data-page的元素的页码值 all_pages = response.xpath('//*[@data-page]/@data-page').getall() # 去重、转成整数并排序 unique_pages = sorted(set(int(p) for p in all_pages if p.isdigit())) for page_num in unique_pages: # 假设页面URL格式是 https://one-versus-one.com/rankings?page=页码 next_url = f'https://one-versus-one.com/rankings?page={page_num}' # 如果用了Playwright,记得带meta yield scrapy.Request(next_url, meta={"playwright": True}, callback=self.parse)
2. 只爬下一页(避免重复)
如果只有“下一页”按钮,直接提取它的data-page:
def parse(self, response): # 处理当前页数据... next_page_num = response.xpath('//button[text()="Next Page"]/@data-page').get() if next_page_num: next_url = f'https://one-versus-one.com/rankings?page={next_page_num}' yield scrapy.Request(next_url, meta={"playwright": True}, callback=self.parse)
注意事项
- 别爬重复页面:可以用一个集合记录已爬页码,比如在爬虫类里定义
self.crawled_pages = set(),每次请求前判断页码是否在集合里。 - 如果分页是AJAX加载,直接找对应的API接口,比如
https://one-versus-one.com/api/rankings?page={page_num},循环请求接口更稳定。
内容的提问来源于stack exchange,提问作者B.O
相关产品推荐
相关产品推荐

