无法抓取网站最内层页面标题,Promise使用问题求助
问题根源
你的脚本只返回第一个标题就卡住,核心问题是Promise的resolve在循环里被提前触发,且未正确处理多异步请求的并发逻辑:
getInnerLinks只创建了一个Promise,但循环中第一个请求完成就调用了resolve,Promise一旦进入resolved状态就不会再变更,剩余请求的结果根本没被收集,导致办公点链接只存了第一个页面的数据。FetchTitle同理,第一个请求拿到标题就直接resolve,后续请求完全没被处理,脚本输出第一个标题后就无后续逻辑,看起来像是"卡住"。- 全局数组
landing_page_links和inner_page_links会导致多次运行时数据污染,应该在函数内部声明。
修复后的代码
用util.promisify把callback风格的request转成Promise版本,配合Promise.all处理多异步请求:
const request = require('request'); const cheerio = require('cheerio'); const { promisify } = require('util'); // 把request转换为Promise版本,适配async/await const requestPromise = promisify(request); const link = 'https://egpostal.com/en/p/all'; const base_link = 'https://egpostal.com/en/'; const getLinks = async () => { const { html } = await requestPromise(link); const $ = cheerio.load(html); const landingPageLinks = []; $('.table tbody tr').each(function() { landingPageLinks.push(base_link + $(this).find("a").attr("href")); }); return landingPageLinks; }; const getInnerLinks = async (links) => { // 每个链接的请求包装成Promise,用Promise.all等待所有请求完成 const linkPromises = links.map(async (url) => { const { html } = await requestPromise(url); const $ = cheerio.load(html); const innerLinks = []; $('.table tbody tr').each(function() { innerLinks.push(base_link + $(this).find("a").attr("href")); }); return innerLinks; }); // 把二维数组扁平化为一维数组,得到所有办公点链接 const allInnerLinksArrays = await Promise.all(linkPromises); return allInnerLinksArrays.flat(); }; const fetchTitles = async (links) => { const titlePromises = links.map(async (url) => { const { html } = await requestPromise(url); const $ = cheerio.load(html); return $(".home-title > h2").eq(0).text().trim(); }); // 等待所有标题抓取完成,返回标题数组 return Promise.all(titlePromises); }; // 执行流程 getLinks() .then(landingLinks => getInnerLinks(landingLinks)) .then(innerLinks => fetchTitles(innerLinks)) .then(titles => { console.log('所有抓取到的标题:'); titles.forEach((title, index) => { console.log(`${index + 1}. ${title}`); }); }) .catch(err => console.error('执行出错:', err));
关键改动说明
- 用
util.promisify转换request,配合async/await让异步逻辑更直观,避免callback嵌套。 - 每个函数内部声明数组,彻底避免全局变量的数据污染问题。
- 用
Promise.all批量处理多异步请求,确保所有请求完成后再返回结果,不会提前触发resolve。 fetchTitles现在返回所有页面的标题数组,而非单个标题。- 增加全局错误捕获,方便排查请求或解析过程中的问题。
内容的提问来源于stack exchange,提问作者robots.txt
相关产品推荐
相关产品推荐

