如何使用Node.js、Axios和Cheerio遍历表格获取日落时间数据
问题
我一整天都在开发网页爬虫,从目标网站获取日期和日落时间。目前已能爬取并显示表格第一行的日期和时间,但刚接触Node.js、Axios和Cheerio,不知道如何遍历整个表格。当前JSON结果只有一个对象,我希望遍历表格后让每一行都成为独立对象,示例如下:
[ { "day": "Tue, Nov 1", "time": "5:59:57 pm" }, { "day": "Tue, Nov 2", "time": "5:55:37 pm" }, { "day": "Tue, Nov 3", "time": "5:42:47 pm" } ]
以下是我目前实现爬取第一行的后端代码:
app.get('/results', function (req, res) { axios(url) .then(response => { const html = response.data const $ = cheerio.load(html) const days = [] $('#month', html).each(function () { const day = $('.number', '.day').prop('innerText') const time = $('.sunset', '.day').prop('innerText') days.push({ day, time }) }) res.json(days) }) .catch(err => console.log(err)) })
前端显示代码:
const feedDisplay = document.querySelector('#feed') fetch('http://localhost:8000/results') .then(response => { return response.json() }) // .then(data => console.log(data)) .then(data => { data.forEach(daysaray => { const dayItem = `<div><h3>` + daysaray.day +`</h3><p>` + daysaray.time +`</div>` feedDisplay.insertAdjacentHTML("beforeend", dayItem) }) }) .catch(err => console.log(err))
补充:目标表格的HTML结构如下:
<table id="month"> <col> <col> <col> <col> <col> <col> <col> <col> <col> <col> <col> <col> <tbody><tr class="headers"> <th rowspan="2">Day</th> <th rowspan="2">Twilight start</th> <th rowspan="2">Sunrise</th> <th rowspan="2">Sunset</th> <th rowspan="2">Twilight end</th> <th rowspan="2">Day length</th> <th rowspan="2">Solar noon</th> <th colspan="2">Nautical twilight</th> <th colspan="2">Astronomical twilight</th> </tr> <tr class="headers"> <th>Start</th> <th>End</th> <th>Start</th> <th>End</th> </tr> <tr class="day" rel="2022-11-01"> <th><span class="number">Tue, Nov 1</span></th> <td>7:19:52 am</td> <td><span class="sunrise" title="Sunrise time 2022-11-01 in Portland, Multnomah County, Oregon, USA">7:49:10 am</span></td> <td><span title="Sunset time 2022-11-01 in Portland, Multnomah County, Oregon, USA" class="sunset">5:59:22 pm</span></td> <td>6:28:40 pm</td> <td>10:10:12</td> <td>12:54:16 pm</td> <td>6:44 am</td> <td>7:03 pm</td> <td>6:10 am</td> <td>7:38 pm</td> </tr> <tr class="day" rel="2022-11-02"> <th><span class="number">Wed, Nov 2</span></th> <td>7:21:11 am</td> <td><span class="sunrise" title="Sunrise time 2022-11-02 in Portland, Multnomah County, Oregon, USA">7:50:33 am</span></td> <td><span title="Sunset time 2022-11-02 in Portland, Multnomah County, Oregon, USA" class="sunset">5:57:57 pm</span></td> <td>6:27:19 pm</td> <td>10:07:24</td> <td>12:54:15 pm</td> <td>6:46 am</td> <td>7:02 pm</td> <td>6:11 am</td> <td>7:36 pm</td> </tr> <!-- 剩余表格行省略 --> </tbody></table>
解决方案
问题出在后端代码的遍历逻辑上——你现在是对整个表格(#month)进行遍历,而不是遍历表格里的每一行(tr.day)。修改方法如下:
修正后端代码
将遍历的选择器改为#month tr.day,并在每次迭代中通过$(this)获取当前行,再在该行内查找对应的日期和日落时间元素:
app.get('/results', function (req, res) { axios(url) .then(response => { const html = response.data const $ = cheerio.load(html) const days = [] // 遍历每个class为day的表格行 $('#month tr.day').each(function () { // $(this)指向当前行,在当前行内查找元素 const day = $(this).find('.number').text().trim() const time = $(this).find('.sunset').text().trim() days.push({ day, time }) }) res.json(days) }) .catch(err => console.log(err)) })
关键说明
- 选择器调整:
$('#month tr.day')会选中表格内所有带有day类的数据行,而非整个表格。 - 元素查找范围:
$(this).find('.number')仅在当前行内查找日期元素,避免全局查找导致重复获取第一行数据的问题。 trim()处理:移除文本内容前后的空格,确保数据整洁。
前端代码优化(可选)
使用模板字符串简化HTML拼接,提升代码可读性:
const feedDisplay = document.querySelector('#feed') fetch('http://localhost:8000/results') .then(response => response.json()) .then(data => { data.forEach(item => { const dayItem = `<div><h3>${item.day}</h3><p>${item.time}</p></div>` feedDisplay.insertAdjacentHTML("beforeend", dayItem) }) }) .catch(err => console.log(err))
修改后,后端会返回包含所有日期和日落时间的数组,前端可正确渲染每一条数据。
内容的提问来源于stack exchange,提问作者Tyson Biegler
相关产品推荐
相关产品推荐

