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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:27:45