node 爬蟲筆記node
爬蟲簡而言之就是爬去網頁上的信息。而網頁結構就是一個樹形結構,就像一個蜘蛛網同樣。而爬蟲程序就像一個蜘蛛,在這個蜘蛛網上去收取咱們感興趣的信息。jquery
工藝利其事必先利器git
剛開始找了幾個 node 爬蟲庫,可是效果不是很理想。不過皇天不負有心人,不過最終仍是讓我找到了一個:Apify.github
npm i apify -S
複製代碼
接下來要肯定一下爬取那個網站的信息(以豆瓣電影 Top 250 爲例)sql
// 引入apify
const Apify = require('apify');
複製代碼
const Apify = require('apify');
Apify.main(async ()=>{
// 首先建立一個請求隊列
const requestQueue = await Apify.openRequestQueue();
// 將要爬取的url添加到隊列當中
await requestQueue.addRequest('https://movie.douban.com/top250');
})
複製代碼
定義一個函數來解析網頁內容,該函數以後會傳入apify爬蟲的一個實例當中數據庫
async function handlePageFunction({ request, $ }) {
// 是否是對$很熟悉,其實就是node裏的jquery
// 先簡單打印下網頁的title.
const title = $('title').text();
console.log(`網頁的title:${title}`);
}
複製代碼
const crawler = new Apify.CheerioCrawler({
requestQueue,
handlePageFunction
})
// 啓動爬蟲
await crawler.run();
複製代碼
咱們把代碼作一下整合,而後啓動爬蟲。npm
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();
})
複製代碼
運行代碼,頁面的標題成功被爬取api
到這裏,就已經實現了一個簡易的爬蟲,可是尚未實現咱們的需求(爬取完整的top250)。咱們須要動態的去添加url,才能爬取到完整的250部電影。bash
初始url是首頁,咱們須要獲取全部頁碼的頁面,經過解析頁面,咱們能夠經過以apify提供的一個動態添加url到隊列的方法來將咱們想要爬去的頁面添加到請求隊列當中。async
const {
utils: { enqueueLinks },
} = Apify;
複製代碼
await enqueueLinks({
$,
requestQueue,
selector: '.next > a', // 跳轉到下一頁的a標籤
baseUrl: request.loadedUrl, //根據baseUrl會將a中的href補全
});
複製代碼
/**
* 解析網頁,獲取電影信息
*/
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
}
複製代碼
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({
$,
requestQueue,
selector: '.next > a', // 跳轉到下一頁的a標籤
baseUrl: request.loadedUrl, //根據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, 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
}
複製代碼
⭐️運行下看看結果
如今的運行結果已經知足咱們的需求了,可是會不會以爲上面的代碼有些麻煩,得找到連接、再轉換、再添加到請求隊列。可不能夠給出一個url規則,而後程序自動幫我添加到隊列中呢?
這裏咱們使用sqlite來作本地數據持久化,由於它是一個輕量級的數據庫、並且是不須要服務端的。
npm i sqlite3 -S
複製代碼
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代理以及請求源假裝。後面再加上