从零编写一只会赚钱的爬虫

本文介绍的是如何编写一只会赚钱的爬虫,那如何编写一只爬虫来赚钱呢?且听我一一道来,在开始之前我们不得不提到一个名次“羊毛党”,现今社会网络异常发达,各种各样的平台为了抢用户,拉新,推广或者一些其他的目的都纷纷推出了一些有奖活动,比如注册送红包,玩游戏领红包,邀请送红包啦之类的,这个时候就出现了一批人,他们会从不同渠道获得这些信息,然后专门薅这些羊毛,随便每笔今个可能不多,但是积少成多,参加的活动多了也是一笔很客观的收入。

上面我们提到了渠道,有些人可能有关系能得到内部消息,但是大部分人都是没有这种关系的,所以只能靠那些有内幕消息的羊毛大佬分享的信息来薅羊毛,但是别人为什么把信息分享给你呢?因为邀请拉人头有奖励呀,这个时候网络上又诞生了一大批羊毛资讯网站,QQ群,微信群,而我们本节的目的主要就是编写一只从各个羊毛资讯网站抓取信息,定时抓取,然后生成简报发送给我们的爬虫。

在开始之前首先需要确保我们开发的机器已经正确安装了nodejs,如果尚未安装,可以参考后面的网站进行安装,http://www.runoob.com/nodejs/nodejs-install-setup.html,下面我们就正式开始会赚钱爬虫的开发了,你准备好了吗?

一、首先我们新建文件夹moneyRobot用于存储我们的项目文件,并新建文件readed.json文件用于存储抓取过的链接,之后打开控制台进入该目录(windows电脑可以在按住shift键的同时在该目录中右击选择从此处打开命令行),然后运行命令:

npm init -y

这一步的主要目的是初始化项目生成package.json文件记录我们的后面所需要的一些项目依赖。接着我们就开始安装我们的项目依赖了

npm install request cheerio fs-extra iconv-lite --save

通过上面的命令我们就安装好了这个项目所有的依赖了,接下来准备开始进入项目的开发了,在动手编写之前我们先构思一下,首先这样的网站并不只有一个,我们也不会只抓取一个,而是要抓取很多个然后综合得到的信息,但是对于每个网站我们不可能都写一份代码呀,所以我们要想一个办法让我们的代码对大部分网站都适用,其实写过爬虫的应该都知道其实对于这种静态网站其实抓取都差不多,只不过是节点不一样罢了,当然要除开异步获取内容的,所以也又很多办法让它和那些直接输出内容的静态网站一样抓取,这里不多做讨论,为了让我们能用一份代码抓取不同的网站,我构造了以下数据结构:

[{
  url: '',
  selector: '',
  isGBK: false
}]

url字段表示待抓取的网址,selector表示的是抓取节点的选择器,isGBK表示这个网站是不是GB2312或者GBK编码,这种编码响应信息需要用iconv-lite这个库来做转换,然后我们开始编写单个URL的抓取方法:

function grab(item) {
  const { url, selector, headers = {} } = item;
  const oldData = fs.readJsonSync(READED_PATH);
  const grabUrl = url;
  request({
    url,
    encoding: null,
    headers: Object.assign({}, headers, {
      userAgent: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    })
  }, (err, response, body) => {
    if (err) {
      startList();
    } else {
      const newBody = item.isGBK ? iconv.decode(body,'gb2312').toString() : body.toString();
      const $ = cheerio.load(newBody);
      const list = $(selector);
      list.each(function() {
        const _this = $(this);
        let url = _this.attr('href');
        if (!/^https?/.test(url)) {
          url = joinPath(grabUrl, url);
        }
        const title = _this.text().replace(/\d{2}:?\d{2}:?\d{2}/g, '');
        const isRead = checkIsRead(oldData, url);
        if (!isRead && title.trim() && !RegExp(FILTER_WORDS.join('|')).test(title)) {
          oldData.unshift(url);
          newData.push({
            title,
            url
          });
        }
      });
      fs.writeJsonSync(READED_PATH, oldData);
      startList();
    }
  });
}

其中READED_PATH表示的是记录已经抓取过的链接记录的本地文件地址,文件以JSON方式记录,startList方法是遍历所有待抓取地址的方法,下面是该方法的代码:

function startList() {
  const item = sources.shift();
  if (item) {
    grab(item);
  } else {
    if (newData.length) {
      const subject = '新的活动线报';
      let content = '\r\n\r\n';
      newData.forEach(item => {
        const { title, url } = item;
        content += `${title}\r\n\r\n${url}\r\n\r\n`;
      });
      sendMessage(subject, content);
    }
  }
}

这里又出现了一个sendMessage方法,我们抓取到了消息需要推送到我们的手机,推送的话就那些渠道,短信,微信,邮件之类的,邮件的话我们不会经常去看,短信的话成本还是有一些的,最适合的就是邮件了,这里使用的是Server酱来进行微信消息的推送,怎么使用呢?打开网址http://sc.ftqq.com然后登录,没有账号的可以注册一个,点击发送消息,我们可以得到我们的SCKEY和调用代码

https://sc.ftqq.com/SCKEY.send?text=主人服务器又挂掉啦~

然后我们在代码中简单的编写发送代码:

function sendMessage(title, content) {
  request({
    url: `https://sc.ftqq.com/SCU43320Tb8f1c7232560d9aa45f9b3c60b3d99ad5c4bf326b4df0.send?text=${encodeURIComponent(title)}&desp=${encodeURIComponent(content)}`
  })
}

这样子我们的要冒爬虫就基本实现了,下面是所有代码,包含了一些个人找的比较好的源,但是里面会有垃圾信息,加了一些简单的过滤,还是有,有兴趣的朋友可以再去调调:

const path = require('path');
const fs = require('fs-extra');
const request = require('request');
const cheerio = require('cheerio');
const iconv = require('iconv-lite');

const FILTER_WORDS = ['虚拟', '软件', '破解', '搬砖', '考核', '道具', '王者荣耀', '原创修改', '作图必备', '技术', '制作', '神器', '关闭', '黄了'];

const READED_PATH = path.join(__dirname, 'readed.json');
const newData = [];

const sources = [
  {
    url: 'https://www.zhuanyes.com/',
    selector: '#threadlisttableid a'
  },
  {
    url: 'http://www.wz169.com/category/xianbao/',
    selector: '#main a'
  },
  {
    url: 'https://www.work28.com/category-4.html',
    selector: '.listbody ul a'
  },
  {
    url: 'https://www.xiaozuan8.com/xianbao/',
    selector: '#postlist_blog .post-title_blog a'
  },
  {
    url: 'http://www.79tao.com/forum-44-1.html',
    selector: 'tbody[id^="normalthread_"] .new a.xst',
  },
  {
    url: 'http://www.wz169.com/category/xianbao/',
    selector: '#main h2.list-title a'
  },
  // {
  //   url: 'https://www.fxzhan.com/?cate=2',
  //   selector: '.mainlist .wx_li a'
  // },
  {
    url: 'http://8ym.cn/RptList',
    selector: '.list-group .list-group-item'
  },
  {
    url: 'https://www.haojiyou.la/html/newslist-14.html',
    selector: '.news-left ul li span a'
  }
];

function checkIsRead(readData, url) {
  return readData.indexOf(url) !== -1;
}

function grab(item) {
  const { url, selector, headers = {} } = item;
  const oldData = fs.readJsonSync(READED_PATH);
  const grabUrl = url;
  request({
    url,
    encoding: null,
    headers: Object.assign({}, headers, {
      userAgent: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    })
  }, (err, response, body) => {
    if (err) {
      startList();
    } else {
      const newBody = item.isGBK ? iconv.decode(body,'gb2312').toString() : body.toString();
      const $ = cheerio.load(newBody);
      const list = $(selector);
      list.each(function() {
        const _this = $(this);
        let url = _this.attr('href');
        if (!/^https?/.test(url)) {
          url = joinPath(grabUrl, url);
        }
        const title = _this.text().replace(/\d{2}:?\d{2}:?\d{2}/g, '');
        const isRead = checkIsRead(oldData, url);
        if (!isRead && title.trim() && !RegExp(FILTER_WORDS.join('|')).test(title)) {
          oldData.unshift(url);
          newData.push({
            title,
            url
          });
        }
      });
      fs.writeJsonSync(READED_PATH, oldData);
      startList();
    }
  });
}

function sendMessage(title, content) {
  request({
    url: `https://sc.ftqq.com/SCU43320Tb8f1c7232560d9aa45f9b3c60b3d99ad5c4bf326b4df0.send?text=${encodeURIComponent(title)}&desp=${encodeURIComponent(content)}`
  })
}

function startList() {
  const item = sources.shift();
  if (item) {
    grab(item);
  } else {
    if (newData.length) {
      const subject = '新的活动线报';
      let content = '\r\n\r\n';
      newData.forEach(item => {
        const { title, url } = item;
        content += `${title}\r\n\r\n${url}\r\n\r\n`;
      });
      sendMessage(subject, content);
    }
  }
}

function start() {
	startList();
}

function joinPath(url, path) {
  const pathArr = url.split(/(?<!\/)\/(?!\/)/);
  if (path[0] === '/') {
    return pathArr[0] + path;
  } else {
    if (path.substr(0, 2) === './') {
      pathArr.pop();
      return pathArr.join('/') + '/' + path.substr(2);
    } else {
      const backArr = path.split('../');
      pathArr.length = pathArr.length - backArr.length;
      return pathArr.join('/') + '/' + backArr[backArr.length - 1];
    }
  }
}

start();

最后还有一个问题就是如何定时抓取呢?我们只需要简单的设置定时任务就可以了,至于定时怎么设,百度一下铺天盖地,这里就不多做讨论了,如果想更实时一点,抓取间隔时间可以设的短一点,这个可以看自己情况而定。

好了,一个会赚钱的爬虫就完成了。

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章