使用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()
关键调整点说明
- 异步函数改造:把
def parse改成async def parse,因为Playwright的API都是异步的,必须用await来等待操作完成。 - 获取页面实例:通过
response.meta["playwright_page"]拿到当前正在运行的浏览器页面对象,这才是能执行操作的实例。 - 异步操作等待:所有Playwright的操作(比如
click()、wait_for_response())都要加上await,确保代码按顺序执行,等待操作完成后再继续。 - 资源清理:操作完成后调用
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
相关产品推荐
相关产品推荐

