Node爬蟲應用的實踐
阿新 • • 發佈:2019-12-31
Welcome to nodecrawler ?
node 爬蟲筆記
? Homepage
一、什麼是爬蟲?
爬蟲簡而言之就是爬去網頁上的資訊。而網頁結構就是一個樹形結構,就像一個蜘蛛網一樣。而爬蟲程式就像一個蜘蛛,在這個蜘蛛網上去收取我們感興趣的資訊。
二、開始寫爬蟲前需要確定的兩個東西。
- Where to crawler? (要爬那的資訊?)。
- What to crawler? (你要爬什麼資訊?)。
工藝利其事必先利器
剛開始找了幾個 node 爬蟲庫,但是效果不是很理想。不過皇天不負有心人,不過最終還是讓我找到了一個:Apify
三、使用 Apify 來開始我的爬蟲之旅
1. 首先新建一個工程然後安裝 apify 依賴。
npm i apify -S
複製程式碼
接下來要確定一下爬取那個網站的資訊(以豆瓣電影 Top 250 為例)
2.現在我們已經確定了要爬取的 url(movie.douban.com/top250),現在開始編寫程式碼。
// 引入apify
const Apify = require('apify');
複製程式碼
3.apify 提供了一個動態佇列(requestQueue)來管理我們要爬取的 url,我們可以使用它來管理我們所有要爬取的 url。
const Apify = require('apify' );
Apify.main(async ()=>{
// 首先建立一個請求佇列
const requestQueue = await Apify.openRequestQueue();
// 將要爬取的url新增到佇列當中
await requestQueue.addRequest('https://movie.douban.com/top250');
})
複製程式碼
5.已經有了請求佇列,接下來要做的是What to crawler。需要一個方法去解析請求的網頁內容。
定義一個函式來解析網頁內容,該函式之後會傳入apify爬蟲的一個例項當中
async function handlePageFunction({ request,$ }) {
// 是不是對$很熟悉,其實就是node裡的jquery
// 先簡單列印下網頁的title.
const title = $('title').text();
console.log(`網頁的title:${title}`);
}
複製程式碼
6.最後,建立一個CheerioCrawler 爬蟲例項,並將requestQueue,handlePageFunction作為引數傳入。然後啟動爬蟲
const crawler = new Apify.CheerioCrawler({
requestQueue,handlePageFunction
})
// 啟動爬蟲
await crawler.run();
複製程式碼
我們把程式碼做一下整合,然後啟動爬蟲。
const Apify = require('apify');
Apify.main(async () => {
// 建立請求佇列
const requestQueue = await Apify.openRequestQueue();
// 將要爬取的url新增到佇列當中
await requestQueue.addRequest({ url: 'https://movie.douban.com/top250' });
const handlePageFunction = async ({ request,$ }) => {
// 是不是對$很熟悉,其實就是node裡的jquery
// 先簡單列印下網頁的title.
const title = $('title').text();
console.log(`網頁的title:${title}`);
}
//建立一個CheerioCrawler,將requestQueue,handlePageFunction作為引數傳入
const crawler = new Apify.CheerioCrawler({
requestQueue,handlePageFunction
})
// 啟動爬蟲
await crawler.run();
})
複製程式碼
執行程式碼,頁面的標題成功被爬取
到這裡,就已經實現了一個簡易的爬蟲,但是還沒有實現我們的需求(爬取完整的top250)。我們需要動態的去新增url,才能爬取到完整的250部電影。
8.獲取所有要爬取的頁面
初始url是首頁,我們需要獲取所有頁碼的頁面,通過解析頁面,我們可以通過以apify提供的一個動態新增url到佇列的方法來將我們想要爬去的頁面新增到請求佇列當中。
const {
utils: { enqueueLinks },} = Apify;
複製程式碼
await enqueueLinks({
$,requestQueue,selector: '.next > a',// 跳轉到下一頁的a標籤
baseUrl: request.loadedUrl,//根據baseUrl會將a中的href補全
});
複製程式碼
9. 接下來需要修改一下handlePageFunction,來解析需要的電影資訊。
/**
* 解析網頁,獲取電影資訊
*/
function parseMovie($) {
const movieDoms = $('.grid_view .item');
const movies = [];
movieDoms.each((index,item) => {
const movie = {
rank: $(item).find('.pic em').text(),// 排名
name: $(item).find('.title').text(),// 電影名
score: $(item).find('.rating_num').text(),// 評分
sketch: $(item).find('.inq').text() // 主題
}
movies.push(movie)
})
return movies
}
複製程式碼
10. 再把程式碼整合到一起,執行看看結果
const Apify = require('apify');
const {
utils: { enqueueLinks },} = Apify;
Apify.main(async () => {
// 首先建立一個請求佇列
const requestQueue = await Apify.openRequestQueue();
await requestQueue.addRequest({ url: 'https://movie.douban.com/top250' });
const crawler = new Apify.CheerioCrawler({
requestQueue,handlePageFunction
})
async function handlePageFunction({ request,$ }) {
await enqueueLinks({
$,//根據baseUrl會將a中的href補全
});
const movies = parseMovie($);
movies.forEach((item,i) => {
console.log(`${item.rank}|${item.name}|${item.score}|${item.sketch}`)
})
}
// 啟動爬蟲
await crawler.run();
})
/**
* 解析網頁,獲取電影資訊
*/
function parseMovie($) {
const movieDoms = $('.grid_view .item');
const movies = [];
movieDoms.each((index,// 評分
sketch: $(item).find('.inq').text() // 主題
}
movies.push(movie)
})
return movies
}
複製程式碼
⭐️執行下看看結果
現在的執行結果已經滿足我們的需求了,但是會不會覺得上面的程式碼有些麻煩,得找到連結、再轉換、再新增到請求佇列。可不可以給出一個url規則,然後程式自動幫我新增到佇列中呢?
五、本地資料持久化
這裡我們使用sqlite來做本地資料持久化,因為它是一個輕量級的資料庫、而且是不需要服務端的。
- 安裝sqlite3依賴
npm i sqlite3 -S
複製程式碼
- 初始化資料庫,建立movies表
const sqlite3 = require('sqlite3').verbose();
function initDB(){
let db = new sqlite3.Database('./db/crawler.db',(err) => {
if (err) {
return console.error(err.message,'啊哈');
}
console.log('Connected to the crawler database.');
});
createTable(db);
return db;
}
function createTable(db){
const sql = `CREATE TABLE IF NOT EXISTS movies(
rank TEXT,name TEXT,TEXT TEXT,sketch TEXT
);`
db.run(sql,[],(err)=>{
if(err){
return console.log(err)
}
console.log('表建立成功')
})
}
複製程式碼
3.插入資料
function insertData(db,movie = {}) {
db.serialize(function () {
db.run(`INSERT INTO movies(rank,name,score,sketch) VALUES(?,?,?)`,[movie.rank,movie.name,movie.score,movie.sketch],function (err) {
if (err) {
return console.log(err.message);
}
// get the last insert id
console.log(`A row has been inserted with rowid ${this.lastID}`);
});
})
}
複製程式碼
結尾
到這裡,一個簡單的爬蟲程式算是寫完了,但是這裡還少了ip代理以及請求源偽裝。後面再加上
程式碼地址:github.com/hp0844182/n…