从零开始,如何用puppeteer写一个爬虫脚本

最近看到一篇关于爬虫的文章,而自己又正好在爬虫,于是就想写一篇分享下, 让我们一步一步来,

第一步:安装核心爬虫依赖puppeteer, 如果你打开googole.com是404,运行npm i puppeteer前,先运行set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1; ok,如果没有问题,我们可以在项目根目录(下文简称根目录)下新建index.js;

//index.js
const puppeteer=require('puppeteer');
复制代码

第二步:选择一个你需要爬取资源的站点, 作为一个b站用户,拿b站作为举例吧,我经常会看排行榜,于是今天我们就爬爬排行榜,地址(www.bilibili.com/ranking/all…

第三步:分析如何爬取站点内容, 打开chrome浏览器,按f12,按ctrl+shift+c,你首先就会看到排行榜每个条目对应的一些信息,如果你有过简单的爬虫经验,你大概可能会直接获取页面内容再做提取,当然不是不行,但这种方法一般最后才采取。更优雅的方法是去爬api,要爬api,我们需要将刚刚打开的调试工具切换到network界面,在页面点一点链接跳转,你会发现一些请求记录,自己点开看看,那些是加载这个网页所需要的资源,其中可能就有我们需要的资源,一般来说,xhr选项卡会对应数据内容,但比较神奇,经过调试发现,数据再js选项卡中找到。

然后刷新一下页面,嗯,你会发现,没有了刚刚的发现请求,那数据去哪了呢,api没数据,那数据只能在页面了,估计是为了更好的渲染,数据放在服务端渲染了,api数据只有在切换页面的时候才会有,那么这次就直接用最后手段在页面直接爬取吧。

第四步:写爬取代码, 回到我们的index.js

//index.js
const puppeteer=require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPad = devices['iPad landscape'];//https://github.com/GoogleChrome/puppeteer/blob/master/DeviceDescriptors.js

const program = require('commander');

//定义一些命令
program
    .version('0.0.1')
    .option('-t, --top_10','show top 10')
    .parse(process.argv);

//记录结果,如果想写到数据库,自行对接即可
const log4js = require('log4js');
log4js.configure({
    appenders: { log: { type: 'file', filename: './log/log.log' } },
    categories: { default: { appenders: ['log'], level: 'info' } }
});
const logger = log4js.getLogger('log');

const ifOpenBrowser=false;
const lanchConf={
    headless:!ifOpenBrowser,
    // executablePath: 'C:/Users/xxx/Downloads/chromium/chrome-win32/chrome.exe',//mac用户自行查看文档更改
};

const sleep=(time)=>{
    return new Promise(resolve=>setTimeout(resolve,time))
};
async function repeat(time,fn,gapTime=500){
    if(time>0){
        // console.log('do fn',time);
        await fn();
        await sleep(gapTime);
        return repeat(--time,fn,gapTime)
    }
    // console.log('final');
    return {msg:'done'}
}
const banList=['.png','.jpg'];
puppeteer.launch(lanchConf).then(async browser => {
    //打开一个新的页面
    const page = await browser.newPage();
    //更改浏览器外观,宽高等
    await page.emulate(iPad);
    //启用请求拦截
    await page.setRequestInterception(true);
    //拦截无用请求
    page.on('request', interceptedRequest => {
        //屏蔽后缀为.png或.jpg的请求;减少资源消耗
        if (banList.some(val=>interceptedRequest.url().match(val))){
            interceptedRequest.continue();
			//本来是要屏蔽的,但图片地址在屏蔽的情况下不能获取,故开启
        } else{
            interceptedRequest.continue();
        }
    });
    //跳转到我们的目标页面
    await page.goto('https://www.bilibili.com/ranking/all/0/0/3',{
        waitUntil:'networkidle0'//页面完全加载
    });

    // 图片实现了懒加载,页面需要滚动到底部,连续点击翻页键一定次数,否则图片地址可能不能拿到
    await repeat(20,async ()=>{
        await page.keyboard.press('PageDown',200);
    },200);

    //通过选择器找到目标,如果觉得api难懂,建议使用cheerio辅助
    const listHandle = await page.$('.rank-list');
    //处理子节点内容,难点在选择器的处理,部分反爬虫的页面不会提供一直不变的选择器
    const titles=await listHandle.$$eval('.info .title', nodes => nodes.map(n => n.innerText));
    const authors=await listHandle.$$eval('.detail>a>.data-box', nodes => nodes.map(n => n.innerText));
    const pts=await listHandle.$$eval('.pts div', nodes => nodes.map(n => n.innerText));
    const links=await listHandle.$$eval('.title', nodes => nodes.map(n => n.getAttribute('href')));
    const views=await listHandle.$$eval('.detail>.data-box', nodes => nodes.map(n => n.innerText));
    const images=await listHandle.$$eval('img', nodes => nodes.map(n => n.getAttribute('src')));

    //序列化结果
    const res=[];
    for(let i=0;i<100;i++){
        res[i]={
            rank:i+1,
            title:titles[i],
            author:authors[i],
            pts:pts[i],
            link:links[i],
            view:views[i],
            image:images[i]
        }
    }
    
    //根据命令行输出数据
    if (program.top_10) console.log(res.slice(0,10));
    //写入数据
    logger.info(res);
    //关闭浏览器
    await browser.close();
});
复制代码

写入上面的内容,认真浏览阅读相关配置选项,然后补全相关依赖npm i commander log4js; 打开当前项目所在位置的命令行界面,输入node .程序运行的结果就会输出到根目录下的log目录中,如果想在命令行查看前10条数据,可以运行node . -tnode . -top_10即可,

第五步,上传代码到github,

ps:如果运行了set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1,需设置本地chromium路径。另外,如果使用cnpm安装依赖,chromium似乎能正常下载下来,不妨试试

转载于:https://juejin.im/post/5b755e3de51d45662c1b1d90

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值