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

使用Scrapy结合Playwright-Python爬取Booking.com时触发TypeError错误求助

Scrapy结合Playwright-Python爬取Booking.com时触发TypeError错误求助

嘿,我一眼就看出问题所在啦——你在parse方法里直接调用了Playwright的Page类来执行locator方法,但locator是实例方法,得用已经打开的页面实例才能调用,不能直接拿类来用!

错误原因详解

你写的Page.locator("xpath=//*[@class='e1793b8db2'][1]").click()这行代码,Page是Playwright的类,不是当前正在运行的浏览器页面实例。类方法调用的时候缺少了实例这个必要参数,所以才会抛出missing 1 required positional argument: 'selector'的错误(本质是缺少了实例本身的self参数)。

修正后的完整代码

我帮你把代码调整好了,关键是要从response.meta里拿到Scrapy Playwright帮你创建的页面实例,而且因为Playwright的操作都是异步的,parse方法要改成异步函数:

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy_playwright.page import PageMethod


class BookingSpider(scrapy.Spider):
    name = 'booking'
    start_urls = ["https://www.booking.com/hotel/it/hotelnordroma.en-gb.html?aid=304142&checkin=2025-04-15&checkout=2025-04-16#map_opened-map_trigger_header_pin"]

    def start_requests(self):
        yield scrapy.Request(
            self.start_urls[0],
            meta={
                "playwright": True,
                "playwright_include_page": True,
                "playwright_page_methods": [
                    PageMethod("wait_for_selector", ".e1793b8db2")
                ]
            }
        ) 
    
    async def parse(self, response):         
        # 从response.meta中获取实际的页面实例
        page = response.meta["playwright_page"]
        
        # 异步点击目标按钮
        await page.locator("xpath=//*[@class='e1793b8db2'][1]").click()
        
        # 等待AJAX响应完成(这里可以根据实际接口调整判断条件)
        # 比如等待包含某个关键词的响应,或者等待页面元素更新
        await page.wait_for_response(lambda r: "ajax" in r.url and r.status == 200)
        
        # 获取点击后的页面内容(如果需要AJAX返回的原始数据,可以用response对象的json()等方法)
        updated_html = await page.content()
        with open("copy.txt", "w", encoding="utf-8") as file:
            file.write(updated_html)
        
        # 记得关闭页面,避免资源泄漏
        await page.close()
    
process = CrawlerProcess()
process.crawl(BookingSpider)
process.start()

关键调整点说明

  1. 异步函数改造:把def parse改成async def parse,因为Playwright的API都是异步的,必须用await来等待操作完成。
  2. 获取页面实例:通过response.meta["playwright_page"]拿到当前正在运行的浏览器页面对象,这才是能执行操作的实例。
  3. 异步操作等待:所有Playwright的操作(比如click()、wait_for_response())都要加上await,确保代码按顺序执行,等待操作完成后再继续。
  4. 资源清理:操作完成后调用await page.close()关闭页面,避免浏览器进程堆积占用资源。

额外提示

  • 如果需要获取AJAX返回的原始数据,可以在wait_for_response后拿到响应对象,比如:
    ajax_response = await page.wait_for_response(lambda r: "your_ajax_endpoint" in r.url)
    ajax_data = await ajax_response.json()
    # 处理AJAX数据
    
  • 确保你的选择器是正确的,有时候页面元素的class可能会动态变化,建议用更稳定的定位方式(比如结合ID、属性等)。

备注:内容来源于stack exchange,提问作者Mojsa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:54:32