URCloud

/ 0评 / 21/ 最后更新:2021-12-06
puppeteer爬虫400,412错误

需求场景

最近发现一直爬取的网站升级了,无法通过request模块简单获取了。考虑到其实自己爬取的数据访问量并不大,实际也就我一个人偶尔访问一下,不会是因为我的爬取而去更新反爬虫机制,猜测是其他原因导致了网站升级了反爬虫机制。

解决过程

通过postman测试,可以发现一直返回412错误,后来在postman中携带了cookie,发现可以正常访问,所以通过在request请求中注入了我自己的cookie解决了问题。后来发现还是too young啊,cookie是有时效性的,一段时间后就会消失。于是想到可以通过puppeteer爬取而不是request,可奇怪的问题出现了,puppeteer访问居然显示400,搜了一大圈可以很确定是网站的反爬虫机制才会出现这个情况,参见puppeteer get 400 Error,这个机制有点666啊,一直以为puppeteer是万能的大招,后来通过搜索反爬虫机制,了解到识别puppeteer和普通chrome的大致原理,参见浏览器如何识别selenium及爬虫如何绕过反爬,到这里就很清楚了,我们需要改变puppeteer的默认参数来模拟真实的浏览器,搜索到puppeteer相关的代码,参见puppeteer无头模式下反反爬配置集合,后来在实际测试中,我需要爬取的网站只要删除默认的webdriver字段即可,并没有那么高级。

核心代码

const browser = await puppeteer.launch({
      args: ['--no-sandbox', '--disable-setuid-sandbox']
    });
    const page = await browser.newPage();
    await page.evaluateOnNewDocument(() => { //在每个新页面打开前执行以下脚本
        const newProto = navigator.__proto__;
        delete newProto.webdriver;  //删除navigator.webdriver字段
        navigator.__proto__ = newProto;
        window.chrome = {};  //添加window.chrome字段,为增加真实性还需向内部填充一些值
        window.chrome.app = {"InstallState":"hehe", "RunningState":"haha", "getDetails":"xixi", "getIsInstalled":"ohno"};
        window.chrome.csi = function(){};
        window.chrome.loadTimes = function(){};
        window.chrome.runtime = function(){};
        Object.defineProperty(navigator, 'userAgent', {  //userAgent在无头模式下有headless字样,所以需覆写
            get: () => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36",
        });
        Object.defineProperty(navigator, 'plugins', {  //伪装真实的插件信息
            get: () => [{"description": "Portable Document Format",
                        "filename": "internal-pdf-viewer",
                        "length": 1,
                        "name": "Chrome PDF Plugin"}]
        });
        Object.defineProperty(navigator, 'languages', { //添加语言
            get: () => ["zh-CN", "zh", "en"],
        });
        const originalQuery = window.navigator.permissions.query; //notification伪装
        window.navigator.permissions.query = (parameters) => (
        parameters.name === 'notifications' ?
        Promise.resolve({ state: Notification.permission }) :
        originalQuery(parameters)
        );
    })
    await page.goto('')
21

Leave a Reply

Your email address will not be published.