爬虫的原理
1.获取初始的URL。初始的URL地址可以由用户人为地指定,也可以由用户指定的某个或某几个初始爬取网页决定。
2.根据初始的URL爬取页面并获得新的URL。获得初始的URL地址之后,首先需要爬取对应URL地址中的网页,爬取了对应的URL地址中的网页后,将网页存储到原始数据库中,并且在爬取网页的同时,发现新的URL地址,同时将已爬取的URL地址存放到一个URL列表中,用于去重及判断爬取的进程。
3.将新的URL放到URL队列中。在第2步中,获取了下一个新的URL地址之后,会将新的URL地址放到URL队列中。
4.从URL队列中读取新的URL,并依据新的URL爬取网页,同时从新网页中获取新URL,并重复上述的爬取过程。
5.满足爬虫系统设置的停止条件时,停止爬取。在编写爬虫的时候,一般会设置相应的停止条件。如果没有设置停止条件,爬虫则会一直爬取下去,一直到无法获取新的URL地址为止,若设置了停止条件,爬虫则会在停止条件满足时停止爬取
实现爬虫的技术
开发网络爬虫的语言有很多,常见的语言有:Python、Java、PHP、Node.JS、C++、Go语言等。以下我们将分别介绍一下用这些语言写爬虫的特点:
● Python:爬虫框架非常丰富,并且多线程的处理能力较强,并且简单易学、代码简洁,优点很多。
● Java:适合开发大型爬虫项目。
● PHP:后端处理很强,代码很简洁,模块也较丰富,但是并发能力相对来说较弱。
● Node.JS:支持高并发与多线程处理。
● C++:运行速度快,适合开发大型爬虫项目,成本较高。
● Go语言:同样高并发能力非常强。
使用node进行爬虫
获取网页数据
1、http
const http=require('http')
http.get(url, (res) => {
// 数据分段 只要接受数据就会触发data事件 chunk表示每次接受的数据分段
let rawData=''
res.on('data', (chunk) => {
rawData + = chunk.toString('utf8')
})
//数据传输完毕
res.on('end', () => {
console.log('获取到的网页数据:',rawData)
})
}).on('error', (err) => {
console.log('请求错误')
})
2、 request
const request = require("request");
request.get(url, (err, response, body) => {
if (!err && response.statusCode == 200) {
console.log('获取到的网页数据:',body)
}
})
3、 superagent
const superagent= require('superagent');
superagent.get(url).end((err, res) => {
if (err) {
// 如果访问失败或者出错,会这行这里
console.log(`数据抓取失败 - ${err}`)
} else {
// 访问成功,请求页面所返回的数据会包含在res
// 抓取热点新闻数据
console.log(`数据抓取成功 - ${res}`)
}
});
4、axios
分析数据
使用第三方模块 cheerio
将网页数据转化成JQ的写法
// cheerio 使用试例
const cheerio = require('cheerio');
const $ = cheerio.load('<h2 class="title">Hello world</h2>');
$('h2.title').text('Hello there!');
$('h2').addClass('welcome');
$.html();
使用 eventproxy 重复异步协作
var ep = new EventProxy();
ep.all('tpl', 'data', function(tpl, data){//or ep.all(['tpl', 'data'], function(tpl, data{}))
//在所有指定的事件触发后, 将会被调用执行
//参数对应各自的事件名
});
fs.readFile('template.tpl', 'utf-8', function(err, content){
ep.emit('tpl', content);
});
db.get('sql', function(err, content){
ep.emit('data', result);
});
// 重复请求
ep.after('got_file', files.length, function(list){
//在所有文件的异步执行结束后将被执行
//所有文件的内容都存在list数组中
});
for(var i = 0; i<files.length; i++){
fs.readFile(files[i], 'utf-8', function(err, content){
//触发结果事件
ep.emit('got_file', content);
})
}
邮箱发送
发送邮箱—— nodemailer
"use strict";
const nodemailer = require("nodemailer");
// async..await is not allowed in global scope, must use a wrapper
async function main() {
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // 发送方账号
pass: testAccount.pass, // 授权码 可自行百度各邮箱授权码获取
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"Fred Foo 👻" <foo@example.com>', // sender address
to: "bar@example.com, baz@example.com", // list of receivers
subject: "Hello ✔", // Subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>", // html body
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}
自定义模版——art-template
var template = require('art-template');
const html=template(path.join(__dirname,'./index.html'),{
user: '张三',
age: '22'
})
定时发送——node-schedule
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ │
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)
const schedule = require('node-schedule');
const job = schedule.scheduleJob({hour: 16, minute: 11, second: 10}, function(){
console.log('The answer to life, the universe, and everything!');
});
const job2 = schedule.scheduleJob([
{hour: 16, minute: 11, second: 10},
{hour: 17, minute: 11, second: 10}],
function(){
console.log('The answer to life, the universe, and everything!');
});
依赖汇总
eventproxy —— 重复异步操作处理
superagent —— 发送爬虫请求
cheerio —— 爬虫数据分析
art-template —— 模版数据
nodemailer —— 邮箱发送
node-schedule —— 定时任务