首页 > 解决方案 > 如何模拟按下按钮以继续使用 Scrapy 抓取更多元素

问题描述

在这个页面(https://www.realestate.com.kh/buy/)上,我设法抓取了一个广告列表,并使用以下代码单独解析它们的内容:

import scrapy

class scrapingThings(scrapy.Spider):
    name = 'scrapingThings'
    # allowed_domains = ['https://www.realestate.com.kh/buy/']
    start_urls = ['https://www.realestate.com.kh/buy/']

    def parse(self, response):
        ads = response.xpath('//*[@class="featured css-ineky e1jqslr40"]//a/@href')
        c = 0
        for url in ads:
            c += 1
            absolute_url = response.urljoin(url.extract())
            self.item = {}
            self.item['url'] = absolute_url

            yield scrapy.Request(absolute_url, callback=self.parse_ad, meta={'item': self.item})

    def parse_ad(self, response):

        # Extract things

        yield {
            # Yield things
        }

但是,我想自动从一个页面切换到另一个页面,以获取所有可用的广告(不仅在第一页上,而且在所有页面上)。我猜,通过模拟按下此屏幕截图中显示的 1、2、3、4、...、50 个按钮:

在此处输入图像描述

Scrapy甚至可以做到这一点吗?如果是这样,如何实现这一目标?

标签: scrapy

解决方案


是的,这是可能的。让我向您展示两种方法:

您可以让您的蜘蛛选择按钮,获取@href它们的值,构建一个 [完整] URL 并yield作为新请求。这是一个例子:

def parse(self, response):
    ....
    href = response.xpath('//div[@class="desktop-buttons"]/a[@class="css-owq2hj"]/following-sibling::a[1]/@href').get()
    req_url = response.urljoin(href)
    yield Request(url=req_url, callback=self.parse_ad)
  • 示例中的选择器将始终返回@href下一页按钮的 (它只返回一个值,如果您在第 2 页,则返回@href第 2 页的)
  • 在这个页面中,href是一个相对的url,所以我们需要使用response.urljoin()方法来构建一个完整的url。它将使用响应作为基础。
  • 我们yield一个新的请求,响应会在你确定的回调函数中解析。
  • 这将要求您的回调函数始终产生对下一页的请求。所以这是一个递归解决方案。

一种更简单的方法是仅观察 href 的模式并手动处理yield所有请求。每个按钮都有一个href,"/buy/?page={nr}"其中{nr}是页数,se可以任意更改这个nr值并一次产生所有请求。

def parse(self, response):
    ....
    nr_pages = response.xpath('//div[@class="desktop-buttons"]/a[@class="css-1en2dru"]//text()').getall()
    last_page_nr = int(nr_pages[-1])
    for nr in range(2, last_page_nr + 1):
        req_url = f'/buy/?page={nr}'
        yield Request(url=response.urljoin(req_url), callback=self.parse_ad)
  • nr_pages返回所有按钮的数量
  • last_page_nr选择最后一个数字(这是最后一个可用页面
  • 我们在 2 到值last_page_nr在这种情况下为 50)之间的范围内循环,并且在每个循环中我们请求一个新页面(对应于数字)。
  • 这样,您可以在您的方法中发出所有请求,并在没有递归调用的情况下parse解析响应。parse_ad

最后我建议你看一下scrapy教程,它涵盖了几种常见的scraping场景。


推荐阅读