Puppeteer:如何存储会话(包括 cookie、页面状态、本地存储等)并稍后继续?

Roc*_*uts 13 browser cookies session local-storage puppeteer

是否可以使用 Puppeteer 脚本打开页面并与之交互,然后按原样保存该浏览器会话,然后加载另一个脚本并从那里继续?

“浏览器会话”是指当前加载的页面,包括页面状态(DOM 空间和 javascript 变量等)、cookie、本地存储、整个shebang。基本上它需要的一切都在上一个脚本停止的地方继续。

如果没有,那么至少可以导出和导入 cookie 和本地存储吗?因此,我可以重新加载特定页面并继续处理,同时保持任何登录或会话数据完整无缺。

小智 20

我不能肯定,但由于 Puppeteer “只是”Chrome DevTools Protocol (cdp) 的包装器,而 cpd 没有执行您所要求的本机“命令”,因此不可能做到对于整个shebang。

但你有选择。一个不错的选择是为下一个脚本重新使用相同的浏览器。您只需要将“ userDataDir ”选项传递给 puppeteer.launch 命令。例子:puppeteer.launch({ userDataDir: '/tmp/myChromeSession' });。每个使用它的 puppeteer 脚本都将使用相同的浏览器,因此它们将共享“永久”cookie。“会话”cookie(或那些有过期时间的)肯定会被删除,但这是 cookie 应该工作的方式。

关于用户数据目录的摘录

用户数据目录包含配置文件数据,例如历史记录、书签和 cookie,以及其他每个安装的本地状态。

尽管这个参考没有写任何关于 Web 存储的内容,但它也保存在用户数据目录中。所以,使用这个选项你很高兴。我认为是您的情况的最佳选择。

您还有其他选择,例如仅复制 cookie 和存储(localStorage 和 sessionStorage)。

使用 puppeteer 复制 cookie

对于 puppeteer,这个过程是非常痛苦的:你必须指定你想要从中处理 cookie 的每个来源。例如,如果您的网站嵌入了第三方内容,例如 google 登录或跟踪,则您必须从“google.com”、“.google.com”、“www.google.com”等复制 cookie。这非常非常愚蠢而痛苦。无论如何,要复制 cookie 源https://abc,请发出:const abcCookies = await page.cookies('https://a.b.c'); 恢复它们:await page.setCookie(...abcCookies);。由于它们是 json,您可以将它们序列化并保存到磁盘,以便稍后恢复。

使用 CDP 复制 cookie

let { cookies } = await page._client.send('Network.getAllCookies');
Run Code Online (Sandbox Code Playgroud)

参考:Network.getAllCookies

要恢复它们,您可以使用Network.setCookies cdp 方法。同样,您可以序列化这些 cookie 并保存到磁盘以供稍后恢复。

复制存储(localStorage 和 sessionStorage)

您可以通过const ls = await page.evaluate(() => JSON.stringify(localStorage));和转移您自己的原始存储const ss = await page.evaluate(() => JSON.stringify(sessionStorage));。但是,出于安全原因,您无法访问其他源存储。不知道 CDP 等价物,并认为它还不存在。

网页缓存

如果您的站点有 Service Worker,那么它很可能会将内容保存在Web Cache API 上。我不知道保存这些缓存数据是否有意义,但是如果对您很重要,您也可以传输这些缓存,但不能使用 puppeteer apis 或 cdp。您必须自己使用Cache api并使用page.evaluate传输缓存。

索引数据库

如果您想复制 IndexedDB 内容,您可以使用 cdp IndexedDB域方法(如“IndexedDB.requestData”)来获取任何来源的数据,但您不能设置/恢复这些数据。:) 但是,您可以在自己的来源中使用 page.evaluate 以编程方式恢复数据。


mev*_*hee 5

Icrespilho的回答非常有价值。他为读者留下了两个练习,我做了一个:IndexedDB。

复制 IndexedDB

他写:

如果要复制 IndexedDB 内容,可以使用 cdp IndexedDB 域方法(如“IndexedDB.requestData”)来获取任何源的数据,但无法设置/恢复此数据。:) 但是,您可以在自己的源中使用 page.evaluate 以编程方式恢复数据。

我已经将数据读取为:

const indexedDB = await page.evaluate(async () => {
  const result = {};
  const databases = await window.indexedDB.databases();

  const connect = (database) => new Promise(function (resolve, _) {
    const request = window.indexedDB.open(database.name, database.version);
    request.onsuccess = _ => resolve(request.result);
  });

  const getAll = (db, objectStoreName) => new Promise(function (resolve, _) {
    const request = db.transaction([objectStoreName]).objectStore(objectStoreName).getAll();
    request.onsuccess = _ => resolve(request.result);
  });

  for (i = 0; i < databases.length; i++) {
    const db = await connect(databases[i])
    const dbName = db.name;
    result[dbName] = {}
    for (j = 0; j < db.objectStoreNames.length; j++) {
      const objectStoreName = db.objectStoreNames[j];
      result[dbName][objectStoreName] = []
      const values = await getAll(db, objectStoreName);
      result[dbName][objectStoreName] = values;
    }

  }
  return result;
});
Run Code Online (Sandbox Code Playgroud)

我希望这对任何人都有帮助。

  • 您正在阅读 IndexedDB,对吗?你如何设置它? (2认同)