You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Scrapy爬取带省略号且无href的分页按钮数据?

解决无Href分页及省略号的爬取方案

嘿,我来帮你搞定这个分页爬取的问题!这种不带href的分页按钮,本质都是前端通过动态逻辑加载数据的,咱们一步步拆解解决:

1. 先搞清楚分页的触发逻辑

打开浏览器开发者工具(按F12),切到Network标签,然后手动点击分页按钮(比如第2页、第3页),盯着新出现的请求看:

  • 要么是XHR/fetch类型的AJAX请求,这类请求的URL里一般会带pagepageNum这类参数,返回JSON或者HTML片段;
  • 要么是直接修改了原URL的查询参数(比如原URL是xxx/sale,点第2页后变成xxx/sale?page=2),这种情况最简单,直接构造带参数的URL就行。

针对你爬的Forever21站点,我印象里它的分页就是用URL参数page控制的,你可以手动试试https://www.forever21.com/us/shop/catalog/category/f21/sale?page=2,应该就能打开第2页的内容。

2. 对付分页里的省略号(...)

省略号只是前端隐藏了中间页码,但只要找到了分页参数的规律,完全可以跳过省略号直接构造所有页码的URL:

  • 先找总页数:可以看看页面底部有没有类似“共X页”的提示;或者点击最后一个可见页码(比如你说的5),看看还有没有下一页按钮,没有的话5就是总页数;
  • 更灵活的方式是循环递增page参数,直到请求回来的页面没有商品数据,自动停止爬取,不用提前知道总页数。

3. 修改你的Scrapy代码实现分页

给你改好了代码示例,以URL参数分页的情况为例,两种实现方式都给你写上:

方式1:提前指定总页数(适合已知总页数的情况)

def start_requests(self):
    base_url = 'https://www.forever21.com/us/shop/catalog/category/f21/sale?page={}'
    # 假设总页数是5,直接构造1到5页的URL
    for page in range(1, 6):
        url = base_url.format(page)
        yield scrapy.Request(url, callback=self.parse_2)

def parse_2(self, response):
    for product_item_forever in response.css('div.pi_container'):
        forever_item = {
            'forever-title': product_item_forever.css('p.p_name::text').extract_first(),
            'forever-regular-price': product_item_forever.css('span.p_old_price::text').extract_first(),
            'forever-sale-price': product_item_forever.css('span.p_sale.t_pink::text').extract_first(),
            'forever-photo-url': product_item_forever.css('img::attr(data-original)').extract_first(),
            'forever-description-url': product_item_forever.css('a.item_slider.product_link::attr(href)').extract_first(),
        }
        yield forever_item

方式2:自动翻页(不用提前知道总页数,更灵活)

def start_requests(self):
    # 先请求第1页
    first_page_url = 'https://www.forever21.com/us/shop/catalog/category/f21/sale?page=1'
    yield scrapy.Request(first_page_url, callback=self.parse_2)

def parse_2(self, response):
    # 先检查当前页面有没有商品,没有就直接返回停止爬取
    product_items = response.css('div.pi_container')
    if not product_items:
        return
    
    # 提取商品数据
    for product_item_forever in product_items:
        forever_item = {
            'forever-title': product_item_forever.css('p.p_name::text').extract_first(),
            'forever-regular-price': product_item_forever.css('span.p_old_price::text').extract_first(),
            'forever-sale-price': product_item_forever.css('span.p_sale.t_pink::text').extract_first(),
            'forever-photo-url': product_item_forever.css('img::attr(data-original)').extract_first(),
            'forever-description-url': product_item_forever.css('a.item_slider.product_link::attr(href)').extract_first(),
        }
        yield forever_item
    
    # 构造下一页URL
    current_page = int(response.url.split('page=')[-1])
    next_page_num = current_page + 1
    next_page_url = f'https://www.forever21.com/us/shop/catalog/category/f21/sale?page={next_page_num}'
    # 发送下一页请求
    yield scrapy.Request(next_page_url, callback=self.parse_2)

4. 如果是AJAX动态加载的情况(备用方案)

要是点击分页按钮时,页面没刷新而是发送了AJAX请求,那你需要:

  • 在Network标签里找到那个AJAX请求的URL(比如类似https://www.forever21.com/api/products?sale&page=2);
  • 复制请求的Headers(比如User-Agent、Referer这些,有些站点还需要token);
  • 构造AJAX请求,然后解析返回的JSON数据来提取商品信息(这时候就不能用css选择器,得用response.json()来处理)。

小提醒

  • 爬的时候别太急,设置个DOWNLOAD_DELAY = 2(在settings.py里),避免被站点封IP;
  • scrapy shell 目标URL来测试选择器和URL,调试起来更方便。

内容的提问来源于stack exchange,提问作者Christian Read

火山引擎 最新活动