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代理以及请求源假装。后面再加上