如何在Playwright JS测试中遍历指定类的多组dt/dd元素?
问题:Playwright JS抓取网页dt/dd数据不全的解决方法
问题背景
需要抓取目标网站中多个i_d类div内的所有dt和dd对应文本,当前代码仅能获取每组的第一个dt/dd项(Series),需修改代码获取完整的Series、Catalog Codes、Variants信息。
网页HTML结构
<div class="pl-it"> <div class="i_d"> <dl> <dt class>Series: <dd> <a href=".....">Province A</a> </dd> </dt> <dt class>Catalog Codes: <dd> <strong>Mi</strong> <strong>CA 1x,</strong> "ca 17" </dd> </dt> <dt class>Variants: <dd><strong><a>Click to see variants</a></strong></dd> </dt> </dl> </div> <div class="i_d"> <dl> <dt class>Series: <dd> <a href=".....">Province B</a> </dd> </dt> <dt class>Catalog Codes: <dd> <strong>Fu</strong> <strong>DE 2x,</strong> "pa 21" </dd> </dt> <dt class>Variants: <dd><strong><a>Click to see variants</a></strong></dd> </dt> </dl> </div> </div>
当前代码
const { test, expect } = require('@playwright/test'); test('homepage has Playwright in title and get started link linking to the intro page', async ({ page }) => { await page.goto('https://colnect.com/en/stamps/list/country/38-Canada'); await expect(page.locator('div#pageContent h1')).toContainText('Stamp catalog › Canada › Stamps') const books = await page.$$eval('div.i_d', all_items => { const data =[]; all_items.forEach(book => { const label = book.querySelector('dt')?.innerText; const name = book.querySelector('dd')?.innerText; data.push({ label, name}); }) return data; }); console.log(books); });
当前输出
[ { label: 'Series:', name: 'Province A' }, { label: 'Series:', name: 'Province B' }, ]
预期输出
Series: Province A Catalog Codes: Mi CA 1x, ca17 Variants: Click to see variants Series: Province B Catalog Codes: Fu DE 2x, pa21 Variants: Click to see variants
解决方案
修改$$eval内的处理逻辑,遍历每个i_d下的所有dt元素,并匹配对应的dd内容,最后整理成预期格式输出。
修改后的代码
const { test, expect } = require('@playwright/test'); test('scrape full stamp details', async ({ page }) => { await page.goto('https://colnect.com/en/stamps/list/country/38-Canada'); await expect(page.locator('div#pageContent h1')).toContainText('Stamp catalog › Canada › Stamps') const items = await page.$$eval('div.i_d', allItems => { return allItems.map(item => { const details = []; // 获取当前item下的所有dt元素 const dts = item.querySelectorAll('dt'); dts.forEach(dt => { // 获取dt的文本并去除多余空格 const label = dt.innerText.trim(); // 获取当前dt下的dd元素文本,处理多余空格和换行 const value = dt.querySelector('dd')?.innerText.replace(/\s+/g, ' ').trim() || ''; details.push(`${label} ${value}`); }); // 将当前item的所有详情用换行连接,不同item之间留空行 return details.join('\n'); }).join('\n\n'); }); console.log(items); });
代码说明
- 原代码使用
querySelector只会获取第一个匹配的dt和dd,改为querySelectorAll遍历所有dt元素。 - 对每个dt,获取其内部的dd元素文本,用
replace(/\s+/g, ' ')合并多余的空格和换行,保证输出格式整洁。 - 将每个
i_d下的所有dt/dd对拼接成字符串,不同i_d的内容之间添加空行,最终输出符合预期格式的结果。
内容的提问来源于stack exchange,提问作者user9847788
相关产品推荐
相关产品推荐

