使用 Scrapy 和 Playwright 无限滚动抓取页面

使用 Scrapy 和 Playwright 无限滚动抓取页面

使用 scrapy 抓取网站时,您很快就会遇到各种需要发挥创意或与要抓取的页面进行交互的场景。其中一种场景是当您需要抓取无限滚动页面时。当您向下滚动页面时,这种类型的网站页面会加载更多内容,就像社交媒体源一样。

抓取这些类型的页面的方法肯定不止一种。我最近解决这个问题的一种方法是继续滚动,直到页面长度停止增加(即滚动到底部)。这篇文章将逐步介绍这个过程。

这篇文章假设您已经设置并运行了一个 scrapy 项目,并且有一个可以修改和运行的 spider。

将 playwright 与 scrapy 结合使用

此集成使用 scrapy-playwright 插件将 playwright for python 与 scrapy 集成。 playwright 是一个无头浏览器自动化库,用于与网页交互并提取数据。

我一直在使用uv进行python包的安装和管理。

然后,我直接使用 uv 的虚拟环境:

uv venv 
source .venv/bin/activate

使用以下命令将 scrapy-playwright 插件和 playwright 安装到您的虚拟环境中:

uv pip install scrapy-playwright

安装您想要与 playwright 一起使用的浏览器。例如,要安装 chromium,您可以运行以下命令:

playwright install chromium

如果需要,您还可以安装其他浏览器,例如 firefox。

注意:以下 scrapy 代码和 playwright 集成仅使用 chromium 进行了测试。

更新settings.py文件或spider中的custom_settings属性以包含download_handlers和playwright_launch_options设置。

# settings.py
twisted_reactor = "twisted.internet.asyncioreactor.asyncioselectorreactor"

download_handlers = {
    "http": "scrapy_playwright.handler.scrapyplaywrightdownloadhandler",
    "https": "scrapy_playwright.handler.scrapyplaywrightdownloadhandler",
}

playwright_launch_options = {
    # optional for cors issues
    "args": [
        "--disable-web-security",
        "--disable-features=isolateorigins,site-per-process",
    ],
    # optional for debugging
    "headless": false,
},

对于 playwright_launch_options,您可以将 headless 选项设置为 false,以打开浏览器实例并观察进程运行。这有利于调试和构建初始抓取器。

处理 cors 问题

我传递了额外的参数来禁用网络安全并隔离来源。当您抓取存在 cors 问题的网站时,这非常有用。

例如,可能会出现由于 cors 导致所需的 javascript 资源未加载或未发出网络请求的情况。如果某些页面操作(例如单击按钮)未按预期工作但其他一切都正常,您可以通过检查浏览器控制台是否有错误来更快地隔离此问题。

"playwright_launch_options": {
    "args": [
        "--disable-web-security",
        "--disable-features=isolateorigins,site-per-process",
    ],
    "headless": false,
}

爬行无限滚动页面

这是一个爬行无限滚动页面的蜘蛛的示例。蜘蛛将页面滚动 700 像素,并等待 750 毫秒以完成请求。蜘蛛将继续滚动,直到到达页面底部,滚动位置在循环过程中不会改变。

我正在使用 custom_settings 修改蜘蛛本身的设置,以将设置保留在一处。您还可以将这些设置添加到settings.py文件中。

# //spiders/infinite_scroll.py

import scrapy

from scrapy.spiders import crawlspider
from scrapy.selector import selector


class infinitepagespider(crawlspider):
    """
    spider to crawl an infinite scroll page
    """

    name = "infinite_scroll"

    allowed_domains = [""]
    start_urls = [""]

    custom_settings = {
        "twisted_reactor": "twisted.internet.asyncioreactor.asyncioselectorreactor",
        "download_handlers": {
            "https": "scrapy_playwright.handler.scrapyplaywrightdownloadhandler",
            "http": "scrapy_playwright.handler.scrapyplaywrightdownloadhandler",
        },
        "playwright_launch_options": {
            "args": [
                "--disable-web-security",
                "--disable-features=isolateorigins,site-per-process",
            ],
            "headless": false,
        },
        "log_level": "info",
    }

    def start_requests(self):
        yield scrapy.request(
            url=f"{self.start_urls[0]}",
            meta=dict(
                playwright=true,
                playwright_include_page=true,
            ),
            callback=self.parse,
        )


    async def parse(
        self,
        response,
    ):
        page = response.meta["playwright_page"]
        page.set_default_timeout(10000)

        await page.wait_for_timeout(5000)
            try:
                last_position = await page.evaluate("window.scrolly")

                while true:
                    # scroll by 700 while not at the bottom
                    await page.evaluate("window.scrollby(0, 700)")
                    await page.wait_for_timeout(750) # wait for 750ms for the request to complete
                    current_position = await page.evaluate("window.scrolly")

                    if current_position == last_position:
                        print("reached the bottom of the page.")
                        break

                    last_position = current_position

            except exception as error:
                print(f"error: {error}")
                pass

            print("getting content")
            content = await page.content()

            print("parsing content")
            selector = selector(text=content)

            print("extracting links")
            links = selector.xpath("//a[contains(@href, '//')]//@href").getall()

            print(f"found {len(links)} links...")

            print("yielding links")

            for link in links:
                yield {"link": link}


我了解到的一件事是,没有两个页面或站点是相同的,因此您可能需要调整滚动量和等待时间以考虑页面以及网络往返中的任何延迟以完成请求。您可以通过检查滚动位置和完成请求所需的时间以编程方式动态调整此值。

在页面加载时,我等待资源加载和页面渲染的时间稍长一些。 playwright 页面被传递到response.meta 对象中的解析回调方法。这用于与页面交互并滚动页面。这是在 scrapy.request 参数中使用 playwright=true 和 playwright_include_page=true 选项指定的。

def start_requests(self):
    yield scrapy.request(
        url=f"{self.start_urls[0]}",
        meta=dict(
            playwright=true,
            playwright_include_page=true,
        ),
        callback=self.parse,
    )

此蜘蛛将使用 page.evaluate 和scrollby() javascript 方法将页面滚动 700 像素,然后等待 750 毫秒以完成请求。然后,将 playwright 页面内容复制到 scrapy 选择器,并从页面中提取链接。然后,这些链接将被传送到 scrapy 管道以继续处理。

无限滚动scrapy剧作家

对于页面请求开始加载重复内容的情况,可以添加一个检查,看看内容是否已经加载完毕,然后跳出循环。或者,如果您知道滚动加载的数量,则可以添加一个计数器,以便在一定数量的滚动加上/减去缓冲区后跳出循环。

单击元素即可无限滚动

页面也可能有一个可以滚动到的元素(即“加载更多”),该元素将触发下一组内容的加载。您可以使用 page.evaluate 方法滚动到该元素,然后单击它以加载下一组内容。

...

try:
    while True:
        button = page.locator('//button[contains(., "Load more")]')
        await button.wait_for()

        if not button:
            print("No 'Load more' button found.")
            break

        is_disabled = await button.is_disabled()
        if is_disabled:
            print("Button is disabled.")
            break

        await button.scroll_into_view_if_needed()
        await button.click()
        await page.wait_for_timeout(750)

except Exception as error:
    print(f"Error: {error}")
    pass

...

当您知道页面有一个将加载下一组内容的按钮时,此方法非常有用。您还可以使用此方法单击其他元素,这将触发下一组内容的加载。如果按钮或元素在页面上不可见,则scroll_into_view_if_needed 方法会将按钮或元素滚动到视图中。这是其中一种场景,您需要使用 headless=false 仔细检查页面操作,以查看在运行完整爬网之前是否单击了按钮以及是否按预期加载了内容。

注意:如上所述,确认页面资源(.js)正确加载并且正在发出网络请求,以便按钮(或元素)已安装并可点击。

总结

网络爬行是一个具体情况具体分析的情况,您将需要调整代码以适应您要抓取的页面。上面的代码是让您使用 scrapy 和 playwright 爬行无限滚动页面的起点。

希望这可以帮助您解除封锁! ?

订阅通过电子邮件获取我的最新内容-> newsletter

以上就是使用 Scrapy 和 Playwright 无限滚动抓取页面的详细内容,更多请关注昆居客【www.kunjuke.com】。

相关推荐:

支付宝“花呗崩了”登上热搜,账单页面无法正常显示

感谢网友 浮沉若梦、软媒用户1238620、缘分缔造者、会弹琴的九号、叫咩好 的线索投递! 7 月 8 日消息,今晚有用户在社交媒体上称在支付宝花呗还款时发现还款页面无法正常打开。有用户花呗页面显示:因机构维护,账单暂时无法查看。随后词条“花呗崩了”登上热搜。截至发稿,支付宝官方暂未对此作出回应。支付宝客服回应称,反馈的问题支付宝已收到并在紧急处理中,请稍后再试,对由此带来的不便深表歉意。

谷歌浏览器怎么抓取网络请求?_抓包分析必备的谷歌浏览器技巧【抓包】

Chrome开发者工具Network面板可抓包HTTP/HTTPS请求:打开检查→切Network→开Preserve log→筛XHR/Fetch→查Headers与Response→硬刷清缓存。 如果您需要捕获网页与服务器之间传输的HTTP/HTTPS请求数据,以便分析接口行为、调试前端逻辑或构建爬虫,谷歌浏览器内置的开发者工具可直接完成抓包任务。以下是具体操作步骤: 一、打开开发者工具并进入...

PDF24提取页面功能在哪 PDF24文件处理操作方法【技巧】

PDF24的“提取页面”功能可免费快速提取指定页码生成新PDF,支持桌面版与网页版,提供缩略图预览和逗号分隔的页码输入(如3,7,12),操作简单无需注册。 想从几十页的PDF里快速挑出第3、第7、第12页单独保存成新文件,又不想装一堆软件或注册账号,PDF24的“提取页面”功能就是最直接的解法——它不锁免费页数、支持逗号分隔的不连续页码输入、桌面版和网页版都自带缩略图预览,操作完立刻生成独立PD...

百度浏览器网页视频怎么下载到本地_百度自带视频抓取保存工具使用

百度浏览器支持多种网页视频下载方法:1. 视频频道内用“视频下载”入口;2. 非聚合页悬停触发或手动唤出嗅探浮窗;3. 安装FVD Download插件增强兼容性;4. 从缓存目录手动提取已加载视频并重命名后缀为.mp4。 你想把百度浏览器里正在看的网页视频保存到手机本地,方便离线反复观看或剪辑使用,不用第三方APP也能实现——百度浏览器自带的视频下载功能已稳定支持主流网页视频流识别与直存。 用内...

CodeBuddy怎么生成前端页面代码?

Figma设计稿转前端代码有四种方法:一、Figma MCP插件直连生成,通过CodeBuddy与Figma MCP协议实现像素级还原;二、上传设计图由NL2Code解析生成,依赖视觉逆向建模;三、自然语言指令驱动构建,直接输入功能需求生成可运行代码;四、基于已有代码智能扩增,AI理解上下文生成风格一致新模块。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1...
· AI · 295239

PDF怎么把横向页面改成纵向 旋转PDF特定页面并保存

必须用Adobe Acrobat DC或Pro:1. 打开文件→2. 点击“组织页面”→3. 单击选中横页缩略图→4. 点击“旋转”选顺/逆时针90°直至文字竖直→5. 按Ctrl+S保存,写入/Rotate属性实现永久竖向。 打开PDF时发现某一页横着显示,文字需要歪头才能看清,而你只想改这一页的方向,让内容竖向排布并永久保存,不改动其他页面。 用Adobe Acrobat DC精准调整单页方向...

宙斯浏览器如何开启高帧率模式_宙斯浏览器120Hz网页丝滑滚动

宙斯浏览器需手动启用高帧率模式:先确认系统开启120Hz刷新率,再通过zeus://flags启用High-Performance Compositing、设Maximum Frame Rate为120、开启Display Refresh Rate Synchronization,并关闭UI动画与干扰扩展,最后重启验证。 您在使用宙斯浏览器时发现网页滚动生硬、存在卡顿感或帧率明显低于设备屏幕原生刷...