Phantomjs+Nodejs+Mysql数据抓取(1.数据抓取)

概要: 这篇博文主要讲一下如何使用Phantomjs进行数据抓取,这里面抓的网站是太平洋电脑网估价的内容。主要是对电脑笔记本以及他们的属性进行抓取,然后在使用nodejs进行下载图片和插入数据库操作。

先进行所有页面的内容进行抓取

var page =require('webpage').create();
var address='http://product.pconline.com.cn/server/';
var fs = require('fs');
var mypath = 'version/server/server.txt';
var count = 2;
var pageSize=0;
  phantom.outputEncoding="gbk";
  page.settings.userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";


function loadController(status){
  loadComputerList(address);
}

function loadComputerList(url){
  console.log('loading '+url);

  page.onLoadFinished = function loadListsucc(status){
    console.log("loadlistSucc ["+url+"] =======================Status:"+status);
  };

  page.open(url,function(status){
    setTimeout(function(){
      console.log(status);
      var content='';
      content = page.evaluate(function(){
      var cont='';
      var listComputer = document.querySelectorAll('div.item-title>h3>a');
      var listPrice =document.querySelectorAll('div.price');
      for(var j=0;jvar computer = listComputer[j].innerText;
          var price = listPrice[j].innerText;
          var url = listComputer[j];
          cont += computer+'\t\t价格:'+price+','+url+'\r\n';
      }
      return cont;
    });
    console.log(content);
    console.log('========== write to file !============');
    try{
      fs.write(mypath, content, 'a');
    }catch(e){
      console.log(e);
    }
    console.log('========== begin loading next page!============');
    var nextUrl = page.evaluate(function(){
          var url = '';
          var next =  document.querySelectorAll('div.pager a[class=page-next]');
          var cont = '';
          url = next[0];
          cont += url;
          return cont;
                });
        console.log(nextUrl);

    if(count else{
        console.log(count);
    phantom.exit();
    }
    }, 100);
  });
}

page.open(address,function(status){
  // page.onLoadFinished = loadController;
  page.render('computer.jpeg');
  pageSize = page.evaluate(function(){
    var cont='';
    var size =document.querySelector('div.pager>em>i').innerText;
    cont += size;
    return cont;
  });
  console.log(pageSize);
  loadController(status);
});

上面部分代码可以直接抓取到

http://product.pconline.com.cn/server/

这个页面中所有分页的信息

下面进行代码分析:

page.open(address,function(status){
  // page.onLoadFinished = loadController;
  page.render('computer.jpeg');
  pageSize = page.evaluate(function(){
    var cont='';
    var size =document.querySelector('div.pager>em>i').innerText;
    cont += size;
    return cont;
  });
  console.log(pageSize);
  loadController(status);
});

这部分代码是Phantomjs的入口,也是我们进行数据抓取的开始部分。

 var size =document.querySelector('div.pager>em>i').innerText;

这里抓到的信息是所有页面的页数,用来作为循环判断的次数依据

然后观察代码就可以发现从入口结束之后就跳转到了LoadContriller函数中去,然后再调用loadComputerList这个函数,然后就可以进行数据抓取了

我们再看一下

 var listComputer = document.querySelectorAll('div.item-title>h3>a');
 var listPrice =document.querySelectorAll('div.price');

这两段代码,就是我们要抓取的电脑URL以及价格的信息。  再抓到我们想要的信息之后,我们再对其进行拼接

for(var j=0;jlistComputer.length;j++){
          var computer = listComputer[j].innerText;
          var price = listPrice[j].innerText;
          var url = listComputer[j];
          cont += computer+'\t\t价格:'+price+','+url+'\r\n';
      }

然后获得一行具有基本信息的电脑属性。  然后接下来的工作就是要把这些信息进行存储,我们这里因为不能直接存入数据库,所以要先存入文本中,代码如下:

var fs = require('fs');


try{
      fs.write(mypath, content, 'a');
    }catch(e){
      console.log(e);
    }

再PhantomJS中有API种有相应的读写文件讲解,这里就不多说了,上述代码就是在请求获得之后,将我们拼接好的内容写入文件中,采用的方式是’a’是添加的意思

经过上述过程,我们已经能够将第一个页面中的所有基本信息抓下来了,接下来的问题就是我们该如何跳转到下一个页面中,去抓取接下来的内容

代码如下:

var nextUrl = page.evaluate(function(){
          var url = '';
          var next =  document.querySelectorAll('div.pager a[class=page-next]');
          var cont = '';
          url = next[0];
          cont += url;
          return cont;
                });
        console.log(nextUrl);

    if(count console.log(nextUrl);
      count++;
      console.log(count);
      loadComputerList(nextUrl);
    }else{
        console.log(count);
    phantom.exit();
    }

这里面获取下一个页面Url用到的js语句是:

var next =  document.querySelectorAll('div.pager a[class=page-next]');

朋友们可以使用开发者工具去该网站中看一下点击下一页按钮对应的dom节点是什么,然后就明白这段代码的含义了

再这里面,我们获取了下一页的按钮之后,还需要进行判断现在的循环次数,由于下一页的按钮是一直存在的,我们并不能通过判断是否为空来结束任务,所以我这里用了一个比较蠢得办法来解决这个问题。

抓取所有页面的内容就基本上完成了,这段脚本代码比较简单,如果需要抓同一个网站,只需要修改两部分就可以了,一个是address这个入口,还有就是写文件的路径。

抓取详细信息

再上面我们已经抓到了一些基本信息了,但是页面中并没有为我们提供比如电脑cpu,内存,显卡这些内容,所以我们的抓取工作并没有完成。那么接下来的工作就是要通过我们刚才有抓到的url进入到电脑商品的详细信息页面中去,然后再抓下我们所需要的详细信息。  代码如下:

var page =require('webpage').create();
var address='http://product.pconline.com.cn/server/';
var fs = require('fs');
var mypath='version/Server/server_page.txt';
var stream = null;
var steams = null;
var K=1;
var line ='';
var cate ='';
var url = '';
var dragPath='version/Server/server_detail.txt';
phantom.outputEncoding="gbk";
page.settings.userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko";



function start(url){
  console.log(url);
  page.open(url,function(status){
    setTimeout(function(){
    if(status == 'success'){
    console.log('open success!');
    console.log('==========begin work!=============');
    stream = page.evaluate(function(){
        var name = document.querySelector('.pro-tit>h1').innerText;
        name = name.replace('参数','');
        var listComputer = document.querySelectorAll('div.pannel>ul .title');
        var listParameter = document.querySelectorAll('[itemid]');
        var price = document.querySelector('.r-price').innerText;
        price = price.replace(/\n/g,'');
        var cont= name+'|&|'+price+'|&|产品特性:';
        for(var j=0;jvar computer = listComputer[j].innerText;
            computer = computer.replace(' ','');
            cont += computer+' ';
          }
        for( var j = 0;jvar parameter = listParameter[j].innerText;
          parameter = parameter.replace(/\n/g,'');
          parameter = parameter.replace('\t',' ');
          if(j1){
              cont += parameter+"|&|";
            }else{
              cont += parameter+'';
            }
          }

          return cont+'\r\n';
    });
    try{
      fs.write(dragPath, stream, 'a');
    }catch(e){
      console.log(e);
    }
    console.log(stream);
  }else{
    console.log('page open fail!');
  }
    before();
            }, 100);
  });
}

function readFile(status){
    streams = fs.open(mypath,'r');
    before();
}

function before(){
  console.log('=========work in befor==========='+K);
  K++;
  if(!streams.atEnd()){
    console.log('=========work in befor get Next Line===========');
        line = streams.readLine();
        cate = line.split(',');
    console.log(cate[1]);
    var pcUrl = cate[1].replace('.html','_detail.html');
    console.log(pcUrl);
        start(pcUrl);
    }else{
    console.log('end!!!!!!!!!!!!');
    phantom.exit();
    }

}




page.open(address,function(status){

  readFile(status);

})

我们继续来分析下代码,Phantomjs的开始入口我们就不讲了,每次启动phantomjs都是由这个入口开始,然后再到我们想要的操作中去。

function readFile(status){
    streams = fs.open(mypath,'r');
    before();
}

这里我们成功打开文件,并且把文件中的内容缓存到了streams中去,这里设置的是全局变量,所以直接跳到before这个函数中去

function before(){
  console.log('=========work in befor==========='+K);
  K++;
  if(!streams.atEnd()){
    console.log('=========work in befor get Next Line===========');
        line = streams.readLine();
        cate = line.split(',');
    console.log(cate[1]);
    var pcUrl = cate[1].replace('.html','_detail.html');
    console.log(pcUrl);
        start(pcUrl);
    }else{
    console.log('end!!!!!!!!!!!!');
    phantom.exit();
    }

}

这里面进行的操作主要是在抓文件前,我们需要对我们刚才读进来的内容进行分析,比如:

line = streams.readLine();
cate = line.split(',');
var pcUrl = cate[1].replace('.html','_detail.html');

这三部分,首先就是实现了逐行读取的功能,将每一行的内容读出来,然后通过分隔符获得Url,这里由于我们获得的url并不是我们要的详细信息url,所以我们要进行拼接。

http://product.pconline.com.cn/server/lenovo/514943.html
http://product.pconline.com.cn/server/lenovo/514943_detail.html

这里提供两段实例,读者可以进去看一下,就明白我们为什么要这么拼接url了

stream = page.evaluate(function(){
        var name = document.querySelector('.pro-tit>h1').innerText;
        name = name.replace('参数','');
        var listComputer = document.querySelectorAll('div.pannel>ul .title');
        var listParameter = document.querySelectorAll('[itemid]');
        var price = document.querySelector('.r-price').innerText;
        price = price.replace(/\n/g,'');
        var cont= name+'|&|'+price+'|&|产品特性:';
        for(var j=0;jvar computer = listComputer[j].innerText;
            computer = computer.replace(' ','');

这部分代码就是我们要获取详细信息的代码了,读者可以研究一下,其实原理就是找到节点,然后取出来,进行拼接,最后获得一个详细的信息,实例:

联想ThinkServer TS130 S1225/2G/500O|&|¥5417|&|产品特性:产品型号 TS130 S1225/2G/500O|&|产品类型 塔式|&|产品结构 4U|&|CPU系列 至强处理器E3系列,Intel|&|CPU核心 四核|&|总线规格 DMI 5GT/s|&|CPU型号 E3-1225|&|CPU主频 3.1GHz|&|三级缓存 6M|&|标配CPU数目 1个|&|主板插槽 1×PCIE 2.0 x161×PCIE 2.0 x12×PCI 32/33|&|内存类型 DDR3|&|标配内存 2G|&|最大内存容量 32G|&|硬盘接口类型 SATAⅢ|&|标配硬盘 500G|&|最大硬盘容量 4TB|&|硬盘转速 7200转|&|硬盘阵列 Raid 0,Raid 1|&|光驱 DVD-ROM光驱|&|显示芯片 集成显卡|&|网卡 双端口千兆网卡|&|工作环境 工作温度:10℃-35℃,工作湿度:10%-80%|&|存储环境 储存温度:-40℃-70℃,储存湿度:10%-90%|&|电源 1个80PLUS单电源|&|最大功率 280W|&|操作系统 Windows 2003 R2 SP2简体中文标准版(32位/64位) Windows 2003 R2 SP2简体中文企业版(32位/64位)Windows Server 2008 简体中文基础版(64位) Windows Server 2008 简体中文标准版(32位/64位)Windows Server 2008 简体中文企业版(32位/64位)Windows Server 2008 R2 简体中文基础版(64位)Windows Server 2008 R2 简体中文标准版(64位) Windows Server 2008 R2 简体中文企业版(64位) Windows Small Business Server 2011 Essential Windows XP 简体中文专业版,SP2Windows Vista Business 简体中文商业版Windows 7简体中文专业版(32位/64位)Windows 7简体中文旗舰版(32位/64位)|&|尺寸 406×377×174mm

上面这部分就是我们获取到的详细的电脑信息内容,然后再拼接完信息之后,我们要做的就是写入文件中去,这里和上面是相似的,我就不重复了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏QQ音乐技术团队的专栏

Android O 新特性和行为变更总结

多窗口是 Android 7.1 之后引入的(关于多窗口适配需要注意的地方,但是趁此机会了解一下 Android O 版本的新特性也不错,而且 Google I...

5581
来自专栏华仔的技术笔记

Xcode 7 自动测试XCTestCase

3387
来自专栏小樱的经验随笔

深入理解USB流量数据包的抓取与分析

在一次演练中,我们通过wireshark抓取了一个如下的数据包,我们如何对其进行分析?

1032
来自专栏极客生活

真正好用的python库

这个库是我安装完python环境后第一个安装的库,装上这个库再开始写代码才有底气,作者 Kenneth Reitz 是公认python领域代码写的最好的两个人之...

763
来自专栏java达人

总结 XSS 与 CSRF 两种跨站攻击

作者:Jiangge Zhang 来源:https://blog.tonyseek.com/post/introduce-to-xss-and-csrf/(点击...

1838
来自专栏Android点滴积累

Android热修复框架之优逆势分析(Hotfix)

Android平台出现了一些优秀的热更新方案,主要可以分为4类: 基于Instant Run 热插拔方案:美团的Robust(实时修复)   Robust插件对...

39411
来自专栏杨建荣的学习笔记

Oracle 12.2中的一个参数说明(r12笔记第76天)

之前花了些时间做了Oracle 10g,11g,12c参数的差别,其中有一个参数很有意思,在不同版本代表的含义还有所差别。就是sec_case_sens...

2558
来自专栏PHP技术

重磅资料!Github上的PHP资源汇总大全

依赖管理 ——用于依赖管理的包和框架 Composer/Packagist : 一个包和依赖管理器 Composer Installers: 一个多框架Com...

2824
来自专栏佳爷的后花媛

json & jsonp

对于JSON和JSONP,应该都不陌生,咳咳,不过最初对JSONP有点误解,以为是JSON的另外一个别名,其实二者风马牛不相及。

683
来自专栏C/C++基础

计算机基础知识

攻击过程如下: 1. 攻击者通过MIM(比如arp欺骗等)劫持server与客户端浏览器之间的http包; 2. 攻击者生成一对伪造的RSA密钥: fa...

551

扫描关注云+社区