nodejs + puppeteer 模拟淘宝登录并采集数据


熟悉puppeteer模块时做的小demo,代码十分简单易懂,分享给大家交流学习,请勿恶意抓取或做违反国家政策的行为。

 

一、前期准备工作

        首先需要安装nodejs,并初始化一个项目,安装puppeteer模板以及log4js日志模板并保存。

   npm install puppeteer --save-dev

   npm install log4js --save-dev

 

二、先引用模块并定义相关变量以及日志配置

 1 var puppeteer = require('puppeteer');
 2 var log4js = require('log4js');
 3 var logger = log4js.getLogger();
 4 // 结果集合
 5 var resultList = [];
 6 // 采集最大页码
 7 var maxPage = 10;
 8 // 当前采集页码
 9 var nowPage = 1;
10 
11 
12 log4js.configure({
13     appenders: {
14         xcLogFile: {
15             type: "dateFile",
16             filename: __dirname + '/logs/log4js.log',//您要写入日志文件的路径
17             //compress: true,//(默认为false) - 在滚动期间压缩备份文件(备份文件将具有.gz扩展名)
18             pattern: "-yyyy-MM-dd-hh",//(可选,默认为.yyyy-MM-dd) - 用于确定何时滚动日志的模式。格式:.yyyy-MM-dd-hh:mm:ss.log
19             encoding: 'utf-8',//default "utf-8",文件的编码
20             maxLogSize: 2048000 //文件最大存储空间,当文件内容超过文件存储空间会自动生成一个文件xxx.log.1的序列自增长的文件
21         },
22         xcLogConsole: {
23             type: 'console'
24         }
25     },
26     categories: {
27         default: {
28             appenders: ['xcLogFile'],
29             level: 'all'
30         },
31         xcLogFile: {
32             appenders: ['xcLogFile'],
33             level: 'all'
34         },
35         xcLogConsole: {
36             appenders: ['xcLogConsole'],
37             level: log4js.levels.ALL
38         }
39     }
40 })
41 logger.level = 'debug';

 

 三、实现淘宝模拟登录

  
   需要特别说明的是其中有一步跳过 selenium检测机制的代码,是十分重要的,如果没加将会无限循环验证码。

await page.evaluate(async () => {
  Object.defineProperty(navigator, 'webdriver', { get: () => false }) })

const action = (async () => {
    // 定义浏览器无头模式、分辨率以及关闭沙盒模式等等。
    const browser = await puppeteer.launch({
        headless: false,
        defaultViewport: {
            width: 1300,
            height: 900
        },
        args: ['--no-sandbox', '--disable-setuid-sandbox']
    });
    // 新建页面
    var page = await browser.newPage();
    
    // 设定浏览器UserAgent
    await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
    // 跳转淘宝登录页
    await page.goto('https://login.taobao.com/member/login.jhtml?redirectURL=https%3A%2F%2Fwww.taobao.com%2F');
    // 这一步十分重要,因为大部分大型网站都会对selenium机制进行检测,例如navigator.webdriver,navigator.languages等等。
    // 这一步就是把navigator的一些属性方法等等注入到浏览器中,绕过这些检测机制。
    await page.evaluate(async () => {
        Object.defineProperty(navigator, 'webdriver', { get: () => false })
    })
    // 等待登录按钮加载完毕
    await page.$('.password-login');
    // 自动输入账号,间隔频率随机数300毫秒内
    await page.type('input[id=fm-login-id]', '你的账号', { delay: (parseInt(Math.random() * 300)) });
    // 自动输入密码,间隔频率随机数300毫秒内
    await page.type('input[id=fm-login-password]', '你的密码)', { delay: (parseInt(Math.random() * 300)) })
    // 点击登录按钮
    await page.click('.password-login');

    console.log('登录成功!')

    // 获取cookies
    // cookies = await page.evaluate(() => document.cookie);
    // console.log(cookies);

    // 等待页面加载完毕
    await page.waitForNavigation()

    // 搜索关键字
    var keyName = '连衣裙';
    // 等待输入框加载完毕
    await page.$('#q');
    // 输入关键字
    await page.type('input[id=q]', keyName, { delay: 300 });
    // 点击搜索按钮
    await page.click('.btn-search');

    // 等待5秒后进入采集方法
    await page.waitFor(5000);

    console.log('采集开始...');
    gather(page);
})();

 

 四、实现淘宝数据采集

const gather = async (page) => {
    await page.waitFor(5000);

    // 等待下一页的按钮
    var nextBtn = await page.waitForSelector('#mainsrp-pager .next:not(.next-disabled)');

    // 数据对象
    console.log(`进行第${nowPage}页数据采集...`)
    // 执行JS方法,将获取到的结果返回
    var content = await page.evaluate(() => {
        // 这里的:not(.item-ad)是指不需要推广的商品,如果需要则直接去掉即可。
        var itemList = document.querySelectorAll('#mainsrp-itemlist .J_MouserOnverReq:not(.item-ad)');
        var dataList = [];
        for (var i = 0; i < itemList.length; i++) {
            var data = {};
            var item = itemList[i];
            // 商品名称
            data.name = item.querySelector('.title .J_ClickStat').innerText;
            // 价格
            data.price = item.querySelector('.price strong').innerText;
            // 地区
            data.area = item.querySelector('.location').innerText;
            // 店铺名称
            data.shopName = item.querySelector('.shopname').innerText;
            // 月销量
            data.sellerMonth = item.querySelector('.deal-cnt').innerText || 0;
            if (data.sellerMonth) {
                data.sellerMonth = data.sellerMonth.replace('人付款', '');
            }
            dataList.push(data);
        }
        return dataList;
    });
    console.log(`采集到${content.length}条数据!`);
    content.map(item => {
        // 这里本应是数据库操作,但是篇幅有限就直接写在日志里。
        logger.debug(JSON.stringify(item));
        resultList.push(item);
    })
    // 判断页码是否小于定义的采集最大页码,并且存在下一页按钮。
    if (nowPage < maxPage && nextBtn) {
        nowPage++;
        page.click('#mainsrp-pager .next');
        gather(page);
    }
    else {
        console.log(`采集完毕,一共采集${maxPage}页,${resultList.length}条数据!`);
    }
}

 

代码都是实测没问题的,这里的maxPage也本应是动态获取的,但都比较简单,有问题的小伙伴可以留言问我,转载请注明出处,谢谢!

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM