概要:
這篇博文主要講一下如何使用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
上面這部分就是我們獲取到的詳細的電腦信息內容,然后再拼接完信息之后,我們要做的就是寫入文件中去,這里和上面是相似的,我就不重復了。