记一次简单的Node.js爬取某网站列表中a标签的属性

2,146 阅读4分钟

需求:根据关键词搜索 爬取某网站的列表跳转的链接及标题 并导入excel

感觉这次的思路并不是很正确 是一种野路子 个人理解正常的爬虫是爬取页面的内容 而我这次是直接调用接口获取数据 拿到数据后整理 导入excel 感觉还有很大整理及优化空间 遇到的问题 多次疯狂请求会出现验证码 疯狂过分的请求会导致封号和封ip 解决方式用代理 多个账号进行调用接口

新手需要注意一下爬取的网站是否有robots协议

编码

导入所需模块
// 首先导入所需的所有模块
const fs = require('fs');                   //引入fs模块 读写作用
const xlsx = require('node-xlsx');         // 引入控制excel的模块
const superagent = require('superagent')   // superagent-nodejs处理请求的模块
var request = require("request");          // 引入请求模块
var Promise = require("bluebird");
require('superagent-proxy')(superagent);
注册全局变量
// 全局变量部分
// 小饼干~
var cookie; // 存储登陆cookie 获取请求时需要带上cookie因为每次都更换ip和账号 所以就每次都需要存
// 搜索所有的关键字 
var keyword = []
// 获取excle里已有的数据  这里可以优化一下 判断一下是否有这个excel如果没有就新建 如果有就获取
var info = xlsx.parse("./resut.xlsx")
// 搜索关键词   这一步是搜索第几个关键词 思路是 所有关键词 然后通过获取的excel里的数据有几条就是该搜索第几个了
var searchString = keyword[info.length];
// 所有账号 
var user = [17*******36, 17*******90, 17******72, 17******5, 17******40]
// 每次随机一个账号
var username = user[Math.floor(Math.random() * user.length)];
// 固定密码 所有的账号密码都是一样的
var password = 'a123456';
// 所有数据  获取到的数据需要标题 链接 和 链接为手动拼接 接口只返回了datainfo
var addInfo = {
  name: searchString,
  data: [
    ['title', 'href', 'datainfo']
  ]
// 请填写无忧代理订单号 这里用的无忧代理 缺点收费 自己倒贴11块钱 其实可以自己动手寻找免费的代理 思路都是一样的
var order = '';
// 要测试的网址
var targetURL = 'http://ip.chinaz.com/getip.aspx';
// 请求超时时间
var timeout = 8000;
// 测试次数
var testTime = 5;
// 间隔多少毫秒调用一次接口
var sleepTime = 5000;
// 获取代理ip的网站
var apiURL = 'http://api.ip.data5u.com/dynamic/get.html?order=' + order + '&sep=3';
获取代理ip
// 获取代理ip异步方法
function getProxyList() {
  return new Promise((resolve, reject) => {
    var options = {
      method: 'GET',
      url: apiURL,
      gzip: true,
      encoding: null,
      headers: {},
    };

    request(options, function (error, response, body) {
      try {
        if (error) throw error;
        var ret = (body + '').match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}/g);
        resolve(ret);
      } catch (e) {
        return reject(e);
      }
    });
  });
  
获取代理ip并测试速度是否能使用
function execute() {
  // 调用获取代理ip方法 并测试代理速度 
  getProxyList().then(function (proxyList) {
    var targetOptions = {
      method: 'GET',
      url: targetURL,
      timeout: timeout,
      encoding: null,
    };

    proxyList.forEach(function (proxyurl) {
      // 修改全局变量代理ip
      proxy = 'http://' + proxyurl
      console.log(proxy, 'ip')
      var startTimestamp = (new Date()).valueOf();
      targetOptions.proxy = 'http://' + proxyurl;
      request(targetOptions, function (error, response, body) {
        try {
          if (error) throw error;
          body = body.toString();
          var endTimestamp = (new Date()).valueOf();
          var time = endTimestamp - startTimestamp
          getCookie();
        } catch (e) {
          console.error(e);
        }
      });
    });
  }).catch(e => {
    console.log(e);
  }).finally(() => {})
}
登陆获取cookie
// 获取登陆饼干
function getCookie() {
  // 调用网站的登陆方法
  superagent.post('https://www.com')
    // 设置代理ip
    .proxy(proxy)
    .type('form')
    .send({
      // 需要发送的数据
      reqType: 'phoneLogin',
      phone: username,
      password: password,
    })
    .end(function (err, res) {
      if (err) {
        handleErr(err.message);
        return;
      }
      cookie = res.header['set-cookie']; //从response中得到cookie 并赋值到全局变量
      getData();
    })
}
获取列表 整理数据并导入excel
async function getData() { 
    // 因为只获取前10页 所以循环十遍 该网站 页面只能看得到10页 但是接口可以继续向后调 为了安全 所以只拿前10页
  for (let i = 1; i <= 10; i++) {
    // 调用列表的接口
    const response = await superagent.post('https://www')
      // 设置代理
      .proxy(proxy)
      .type('form')
      // 设置饼干
      .set('Cookie', cookie)
      // 发送数据
      .send({
      })
    if (JSON.parse(response.text).list !== null) {
      // 转译需要的数据 将数据转换成json
      let addData = JSON.parse(response.text);
      // 取出数据中的list list为我们需要的数据
      let list = addData.list;
      list.map((res) => {
        // 提取我们需要的 title dataid href为拼接后的数据
        let getInfo = [res.title, 'https://www' + res._id + '.html', res._id]
        // 将提取出的数据存放到所有数据中
        addInfo.data.push(getInfo)
      })
      console.log(i)
    } else {
      // 同上 这里是不够10页数据的时候
      info.push(addInfo)
      console.log(username, 'username')
      console.log(searchString, 'searchString')
      var buffer = xlsx.build(info);
      fs.writeFile('./resut.xlsx', buffer, function (err) {
        if (err)
          throw err;
      });
      return;
    }
  }

  info.push(addInfo)
  
  // 修改excel文件
  var buffer = xlsx.build(info);
  fs.writeFile('./resut.xlsx', buffer, function (err) {
    if (err)
      throw err;
  });
}
调用方法
// 最后一部就是调用啦
execute();

项目不足 总结

  • 使用了收费代理
  • 需要每次都去运行这个node index.js每次完事儿都需要在手动运行 没有实现全部自动
  • 感觉路子不对 比如如果需要的数据不是接口返回 是在js中的 就无法实现了 如果在dom中可以使用尝试cheerio来完成

遇到的困难

  • 如果遇到js动态加载的dom不知道如何处理 想用puppeteer来爬取 感觉有点杀鸡用牛刀

github地址

[github.com/dzc980812/I…]

转载需标明出处

结语

一次简单的爬虫 希望对你有所帮助 欢迎各位大佬热烈讨论及建议 我们一起解决 顺便圆我js动态加载的dom处理的梦