使用PhantomJS自动化测试LinkedIn时出现“Can't find variable: Map”错误
问题:PhantomJS自动化LinkedIn登录时出现"Can't find variable: Map"错误
我尝试用PhantomJS对LinkedIn执行自动化测试,流程是登录网站、进入联系人页面并导出所有联系人。但输入登录信息提交表单后,页面无法完成加载,报错Can't find variable: Map。我自己的代码里从来没用到过名为Map的变量,完全不知道问题出在哪。
以下是我的测试代码:
var page = require('webpage').create(); function login(){ page.evaluate(function() { document.querySelector("#session_key-login").value="my_login"; document.querySelector("#session_password-login").value="my_pass"; document.querySelector("#btn-primary").click(); }); } page.open("https://www.linkedin.com/uas/login", function(status){ // page.settings.resourceTimeout = 10000; console.log(page.title); login(); setTimeout(function() { console.log(page.title); page.render("test.png"); phantom.exit(); }, 10000); });
解决方案
嘿,这个问题我之前也帮别人排查过,根源其实不在你的代码里,是PhantomJS本身的锅!
PhantomJS已经停止维护好多年了,它用的是非常老旧的WebKit内核(大概相当于Chrome 49的水平),而现在LinkedIn的页面早就用上了ES6+的新特性,其中就包括Map这个内置对象——旧内核根本不认识它,所以页面加载到一半就报错卡住了。
给你两个可行的解决方向,优先推荐第一个:
1. 换成更现代的无头浏览器(强烈推荐)
现在主流的无头浏览器是Puppeteer(基于Chrome/Chromium)或者Playwright(支持Chrome、Firefox、Edge),它们对ES6+特性的支持拉满,完全能适配LinkedIn的现代页面,而且API比PhantomJS更顺手。
用Puppeteer重写你的登录代码大概是这样的:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://www.linkedin.com/uas/login'); // 填写登录信息 await page.type('#session_key-login', 'my_login'); await page.type('#session_password-login', 'my_pass'); // 点击登录按钮 await page.click('#btn-primary'); // 等待页面跳转完成(比setTimeout精准多了) await page.waitForNavigation(); console.log(await page.title()); await page.screenshot({ path: 'test.png' }); await browser.close(); })();
2. 给PhantomJS打ES6补丁(仅临时应急)
如果实在没办法换工具,那只能给PhantomJS注入Map的polyfill,让它假装认识这个新对象。你可以在页面初始化的时候注入补丁代码:
修改你的代码如下:
var page = require('webpage').create(); // 在页面初始化时注入Map的polyfill page.onInitialized = function() { page.evaluate(function() { if (typeof Map === 'undefined') { // 这里用一个简化版的Map实现,实际可能需要更完整的(比如core-js里的) window.Map = function() { this._storage = {}; this.set = function(key, value) { this._storage[JSON.stringify(key)] = value; }; this.get = function(key) { return this._storage[JSON.stringify(key)]; }; this.has = function(key) { return JSON.stringify(key) in this._storage; }; // 还需要实现delete、clear、forEach等方法才能满足LinkedIn的需求 }; } }); }; function login(){ page.evaluate(function() { document.querySelector("#session_key-login").value="my_login"; document.querySelector("#session_password-login").value="my_pass"; document.querySelector("#btn-primary").click(); }); } page.open("https://www.linkedin.com/uas/login", function(status){ console.log(page.title); login(); setTimeout(function() { console.log(page.title); page.render("test.png"); phantom.exit(); }, 10000); });
不过要提醒你,这个简化版补丁可能撑不住LinkedIn复杂的页面逻辑,后续大概率还会遇到其他ES6特性不支持的问题,所以还是尽早换工具更省心。
内容的提问来源于stack exchange,提问作者Sofian Lechani
相关产品推荐
相关产品推荐

