我有一个简单的 puppet 脚本来抓取一个公告网站。我需要获取页面的内容,在我检查了DOM之后,我可以看到所有的内容对于包含链接和文本的div都有相同的类。我如何用循环获取每个div的内容?
这是一个html结构的页面的例子,大约有25个div具有相同的类,每一个都是一个公告。
<div class="container">
<div class="item-card bordertop show-in-related-free-list">
<!-- link and text are nested inside here -->
</div>
</div>
这是我目前拥有的JS代码。我使用headless-recorder-v2 chrome扩展创建了它。
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
headless: false,
slowMo: 300
})
const page = await browser.newPage()
const navigationPromise = page.waitForNavigation()
await page.goto('https://city.example.com/')
await page.setViewport({ width: 1280, height: 607 })
await page.waitForSelector('.bakec > #app > .alert > .btn')
await page.click('.bakec > #app > .alert > .btn')
await page.waitForSelector('.row > .col-md-4:nth-child(1) > .card > .cursor-pointer > .card-title-home')
await page.click('.row > .col-md-4:nth-child(1) > .card > .cursor-pointer > .card-title-home')
await navigationPromise
await page.waitForSelector('#lightbox-vm18 > .modal-dialog > .modal-content > .modal-footer > .btn-primary')
await page.click('#lightbox-vm18 > .modal-dialog > .modal-content > .modal-footer > .btn-primary')
await page.waitForSelector('.bakec > #app > main > .container')
await page.click('.bakec > #app > main > .container')
await page.waitForSelector('#app > main > .container > .item-card:nth-child(3) > .item-container')
// Here I want to loop over announces and store each link and title inside an array
//await page.click('#app > main > .container > .item-card:nth-child(3) > .item-container')
//await navigationPromise
//await browser.close()
更新
我在我的脚本中添加了这几行代码。我可以得到一个包含所需元素的数组,但我如何循环它们,是foreEach
循环还是需要使用for
循环??
const nodes = await page.$$('.item-heading > .item-title > a')
const announces = []
nodes.forEach( (el) => {
let href = el.getProperty('href')
announces.push(href)
})
console.log(announces);
如果我尝试循环nodes
变量,就会得到一个这样的数组
[
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }, Promise { <pending> },
Promise { <pending> }
]
2条答案
按热度按时间yqyhoc1h1#
您可以使用
page.$$(selector)
来获取与给定CSS选择器匹配的所有元素。然后循环遍历元素并检索属性
innerHTML
以获取每个div的内容(elementHandle.getProperty(propertyName))。5gfr0r5j2#
el.getProperty
返回一个你需要等待的promise。你可以使用console.log(await Promise.all(announces))
来并行等待它们,或者编写一个for .. of
循环来顺序运行promise。有关详细信息,请参阅Using async/await with a forEach loop。一般来说,除非你需要在数组上调度可信事件,否则避免使用元素句柄,因为它们本质上是活泼的,比
evaluate
家族调用更难使用。下面是一个使用
page.$$eval
从多个元素中获取文本的示例:这适用于任何属性。如果您正在查找
href
s,您可以将.textContent
替换为.href
或.getProperty("href")
:不要忘记
waitForSelector
,如果元素是在页面加载后由JS添加的。关于你的代码的更多评论:
goto
已经在等待导航了,所以这看起来是多余的,或者可能是有缺陷的。在触发导航的单击旁边设置一个新的导航,而不是在goto
之前。await
多次执行相同的导航可能并不像你想象的那样--把它们当作一次性的。finally
块关闭浏览器资源,以便在出现错误时进行正确的清理。