首页 > 解决方案 > JS无法访问函数内部的全局变量

问题描述

我正在尝试使用 Node 和 Puppeteer 制作一个简单的 webscraper 以获取 reddit 上的帖子标题,但是在仅从一个函数 extractItems() 中访问全局变量 SUBREDDIT_NAME 时遇到问题。它适用于所有其他函数,但对于那个我必须创建一个具有相同值的局部变量才能工作。

我是否完全误解了 Javascript 中的变量范围?

我已经尝试了所有我能想到的方法,唯一可行的方法是在extractItems() 内部创建一个值为“news”的局部变量,否则我什么也得不到。

const fs = require('fs');
const puppeteer = require('puppeteer');
const SUBREDDIT = (subreddit_name) => `https://reddit.com/r/${subreddit_name}/`;
const SUBREDDIT_NAME= "news";


function extractItems() {
  const extractedElements = document.querySelectorAll(`a[href*='r/${SUBREDDIT_NAME}/comments/'] h3`);
  const items = [];
  for (let element of extractedElements) {
    items.push(element.innerText);
  }
  return items;
}

async function scrapeInfiniteScrollItems(
  page,
  extractItems,
  itemTargetCount,
  scrollDelay = 1000,
) {
  let items = [];
  try {
    let previousHeight;5
    while (items.length < itemTargetCount) {
      items = await page.evaluate(extractItems);
      previousHeight = await page.evaluate('document.body.scrollHeight');
      await page.evaluate('window.scrollTo(0, document.body.scrollHeight)');
      await page.waitForFunction(`document.body.scrollHeight > ${previousHeight}`);
      await page.waitFor(scrollDelay);
    }
  } catch(e) { }
  return items;
}

(async () => {
  // Set up browser and page.
  const browser = await puppeteer.launch({
    headless: false,
    args: ['--no-sandbox', '--disable-setuid-sandbox'],
  });
  const page = await browser.newPage();
  page.setViewport({ width: 1280, height: 926 });

  // Navigate to the demo page.
  await page.goto(SUBREDDIT(SUBREDDIT_NAME));

  // Scroll and extract items from the page.
  const items = await scrapeInfiniteScrollItems(page, extractItems, 100);

  // Save extracted items to a file.
  fs.writeFileSync('./items.txt', items.join('\n') + '\n');

  // Close the browser.
  await browser.close();
})();

我期望一个包含 100 个首次找到的标题的文本文件,但它仅在我将 subreddit 硬编码到 extractItems() 函数中时才有效。

标签: javascriptnode.jspuppeteer

解决方案


问题是该extractItems函数被转换为字符串(不处理模板文字)并在没有SUBREDDIT_NAME变量的页面上下文中执行。

您可以通过执行以下操作来解决此问题:

function extractItems(name) {
  const extractedElements = document.querySelectorAll(`a[href*='r/${name}/comments/'] h3`);
  const items = [];
  for (let element of extractedElements) {
    items.push(element.innerText);
  }
  return items;
}

page.evaluate(`(${extractItems})(${SUBREDDIT_NAME})`)

推荐阅读