爬百度文库有偿资料顺便学习mongoose

写本文大体分为如下几个心理活动。

本想作作爬虫,而后持久化到mongodDb。后来,有需求要下载百度文库的资料,又没有下载券,因而想一想怎样可以免费下载资料,顺便保存下来。因此就有了获取百度文库的资料而顺便学习mongoose。html

按心理活动排序本文叙述分为如下几点。node


mongoDb安装

1.安装

sudo brew install mongodb
复制代码

2. 建立一个数据库存储目录 /data/db:

sudo mkdir -p /data/db
复制代码

3.启动Mongodb

sudo mongod
复制代码

4.新开窗口,进入mongodb命令行模式

mongo
复制代码

链接mongodb

  • 在根目录下安装mongodb数据驱动库
cd ~ && cnpm i mongodb
复制代码
  • 新建一个链接文件connect.js
var MongoClient = require('mongodb').MongoClient;
// 链接数据库
var url_test = 'mongodb://localhost:27017/test'; //数据库test本不存在,链接时会自动建立

var insertData = function(db){
  // 往test数据库里新建一个site集合,并插入一条数据
  db.collection('site').insertOne({name: 'guojc', age: 99, hobby: 'movie'}, function(err, result){
    console.log('inserted successly');
    console.log(result);
    db.close();
    console.log('close');
  });
}

MongoClient.connect(url_test, function(err, db) {
  console.log('Connected successly to server.');
  insertData(db);
});
复制代码
  • node connect.js,发现链接成功,可是插入数据报错 ==db.collection is not a function==git

  • 解决方法github

  • 我改为这样mongodb

var MongoClient = require('mongodb').MongoClient;
// 链接数据库
var url = 'mongodb://localhost:27017';

var insertData = function(client){
  // 往test数据库里新建一个site集合,并插入一条数据
  client.db('test').collection('site').insertOne({name: 'guojc', age: 99, hobby: 'movie'}, function(err, result){
    console.log('inserted successly');
    console.log(result);
    client.close();
    console.log('close');
  });
}

MongoClient.connect(url, function(err, client) {
  console.log('Connected successly to server.');
  insertData(client);
});
复制代码
  • show dbs 可以看到建立的数据库
  • use test 选择建立爱的数据库
  • show tables 显示表
  • db.site.find() 查询该表全部数据

Mongoose简介

Mongoose是在node.js异步环境下对mongodb进行便捷操做的对象模型工具。本文将详细介绍如何使用Mongoose来操做MongoDB。

Mongoose是NodeJS的驱动,不能做为其余语言的驱动。Mongoose有两个特色

    1. 经过关系型数据库的思想来设计非关系型数据库
    1. 基于mongodb驱动,简化操做

Mongooose三个重要概念:

Schema: 至关于一个数据库的模板,Schema不具有操做数据库的能力。数据库

Model: 由Schema编译而成的构造器,具备抽象属性和行为,能够对数据库进行增删查改。npm

Entity: 真实的数据。canvas

Schema 生成 ModelModel 创造 DocumentModelDocument均可对数据库操做形成影响。bash

简单demoapp

const mongoose = require('mongoose');


mongoose.connect('mongodb://localhost:27017/test');
const con = mongoose.connection;
con.on('error', console.error.bind(console, '链接数据库失败'));
con.once('open',()=>{
    //定义一个schema
    let Schema = mongoose.Schema({
        name:String,
        age:Number
    });
    // 自定义方法
    Schema.methods.getAge = function(){
        console.log("I am "+this.age + "years old");
    }
    //继承一个schema
    let Model = mongoose.model("student",Schema);
    //生成一个document
    let student = new Model({
        name:'hanmeimei',
        age:16
    });
    //存放数据
    student.save((err,res)=>{
        if(err) return console.log(err);
        res.getAge();
        //查找数据
        Model.find({name:'hanmeimei'},(err,data)=>{
            console.log(data);
        })
    });
})
复制代码

输出

I am 16years old
[ { _id: 5ab1cad40b0132e9a9e6c65b,
    name: 'hanmeimei',
    age: 16,
    __v: 0 } ]
复制代码

查看数据库,发现多了一个students的table,Mongoose会将集合名称设置为模型名称的小写版。若是名称的最后一个字符是字母,则会变成复数;若是名称的最后一个字符是数字,则不变;若是模型名称为"MyModel",则集合名称为"mymodels";若是模型名称为"Model1",则集合名称为"model1"

参考:

mongoose基础入门

深刻浅出mongoose


保存百度文库资料为图片

(PS) 前提是百度文库能看到内容,只是下载须要下载券。

一看到这个需求第一反应就是

  • 用爬虫
  • 打开百度文
  • 而后爬取须要的资料保存到本地

然而打开文库看了看里面的内容是多张 图片 来的, 并且有 加载更多按钮 emmmm...

那就用 puppeteer吧,以前也用过,因而思路分为如下几点

  • 打开连接
  • 点击全屏查看(感受省了一堆功夫)
  • 点击加载更多
  • 去掉页面上的多余的dom节点
  • 保存为pdf/图片

直接上代码

1. 打开连接

await page.goto(url);
复制代码

2. 点击全屏

page.click('a[data-toolsbar-log=fullscreen]')
复制代码

3. 点击加载更多

page.click('.moreBtn')
复制代码

4. 去掉页面上的多余的dom节点

await page.evaluate(v => {
    // dom操做
})
复制代码

5. 保存为pdf

page.pdf({path: 'page.pdf'});
 or 
 page.screenshot({
   path: '1.png',
   fullPage:true
 });
复制代码

问题来了

  • 保存为pdf时图片变空白
  • 改为保存为图片,部分图片空白

发现 滚动操做的时候会 从新请求图片资源,因此dom节点上面只会存在部分图片。

看了看每张图片的外层都有一个pageNo-x的ID,


根据这个为切入点的话,就改良了上面步骤。

  • 打开连接(同上)
  • 保存已经加载的图片
  • 点击加载更多
  • 保存加载的而且id值不等于以前几个的图片
  • 下拉
  • 保存剩余的图片
  • 将最后合成的图片保存为图片(资料只须要打印出来,因此保存为图片也能够)
  • 优化(去掉图片背景的广告)

部分代码

// 找图片,并用一个新节点存起来
async function collectPng(index) {
  const res = await page.evaluate(v => {
      const div = document.getElementById('collection') || document.createElement('div')
      div.id = 'collection'
      document.getElementsByTagName('body')[0].appendChild(div)
      const item = document.getElementById('pageNo-'+v)
      const rpi = item?item.getElementsByClassName('reader-pic-item')[0]: null
      rpi&&(rpi.style.position = 'relative')
      rpi&&div.appendChild(rpi)
      return {index:v, exist:!!rpi}
  },index)
  return res
}
// 根据返回值,判断是否继续查找仍是下拉页面
async function collecting(index) {
  const res = await collectPng(index)
  if(res.exist) {
    index+=1
    await collecting(index)
  } else {
    if(!hasLoadMore){
      console.log('加载更多')
      hasLoadMore = true
      await loadMore()
      await collecting(index)
    } else if(index<9){
      console.log('下拉')
      await pressDown()
      await collecting(index)      
    } else {

    }
  }
}
// 生成纯图片组合成的dom
async function createDom(){
  await page.evaluate(v => {
    const div = document.getElementById('collection');
    const body = document.createElement('body');
    body.appendChild(div)
    document.getElementsByTagName('body')[0].remove()
    document.getElementsByTagName('html')[0].appendChild(body)
  })
}
//pressDown
async function pressDown() {
  await page.keyboard.press('ArrowDown',{delay: 2500});
  await timeout(1000);  
}
复制代码

实际执行状况

  • 开始,保存前三张图片
  • 发现没有了,加载更多
  • 发现没有了,下拉
  • 知道真的没有了就保存图片

最后优化图片背景

因为图片背景会有这些教育机构,为了打印出来更加清晰,能够尝试去掉背景

本身的思路是

  • 将保存的图片用canvas画出来,而后对比像素点rgb的值均大于100的话就变成白色,再保存成图片。
  • 固然,你能够用PS抠 :)

代码

结语

若是你能看到这里,谢谢。文章、代码写的较为之粗糙,只是将本身的想法用代码实现,本文初衷是爬虫并持久化到mongoDb的,后来感受偏离了路线。后面会在这个基础上加上这方面功能。至于这个获取百度文库资源的,只是针对这篇三年级上册数学期末试卷及答案,还没作其余灵活处理,之后会考虑更多实际状况。

相关文章
相关标签/搜索