基于小程序开发的藏书馆

1、小程序的发展

jsbridge -> js-sdk -> 小程序

  • 腾讯内部使用的jsbridge,被外部发现,并使用,逐渐成为微信中网页的事实标准。后提供了外部使用的js-sdk,之后为了提供更丰富的能力,提供小程序。
  • 小程序中js的组成:
    小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。

2、后端技术

后端可通过微信提供的云服务和自己搭建服务端来实现,两者的区别如下:
真棒 真棒

可以看到,使用自己搭建的服务端,需要一定的运维能力,需要提供数据库、https接口等,成本比较大。对于个人开发者,或者没有相关服务器、运维能力的团队,可以使用云服务。

3、云开发的流程

在下面的demo事例中,将提供相应云开发具体操作方式。
真棒

4、藏书馆demo体验

demo功能说明:

提供了书本的扫码、查询录入功能,将家中的图书管理起来。其中由于豆瓣的书本查询api关闭,最终通过网页爬虫,实现在线书本信息收集的工作。通过将书本信息存入提取,录入到数据库中,形成自己的在线书库。

功能部分:

  • 1、微信扫码识别条形码 or 手动输入作者、书名、isbn查询
  • 2、亚马逊网页爬虫
  • 3、数据录入数据库中

本示例提供了两种服务端,nodejs + mongodb自建;及云服务。将提供两者的实现方法。

上截图:

真棒 真棒

4.1、微信扫码识别条形码

wx.scanCode({
  success (res) {
    that.searchBookList(res.result);
  },
  fail(err) {
    console.log('fail', err);
  }
});

微信提供条形码识别的api,直接调用即可~~生成以后,通过亚马逊网页爬虫爬取信息。

4.2、亚马逊网页爬虫

由于豆瓣的图书api禁用,只能通过网页爬虫的方式去获取相关的信息,对比了豆瓣、当当、京东、亚马逊、几个在线图书馆,最终选择了亚马逊。区别对比:

真棒

从对比表格可以看出,仅仅亚马逊可以作为图书信息收集的渠道,但也会出现不稳定的情况,有时候需要多次请求才可取到。豆瓣做了相应的规避爬虫的处理,书本信息无法读取到(爬了几次,ip被豆瓣放入了黑名单。。。)。当当、京东比较尴尬的点是,它的查询结果包含其他第三方书店的结果信息,导致一个isbn对应很多的结果记录,在后面做作者、书名的查询扩展时,比较难过滤,所以丢弃。在线图书馆情况就更多,信息杂乱,书目不全等,丢弃。综合以上,最终选用亚马逊网页来实现书本信息的收集。

包含两个爬虫:

  • 1、根据作者、书名、isbn查询书目列表;
  • 2、step1 里的亚马逊详情链接,跳转到详情页,读取具体书本详细信息。

step1: 搜索结果爬虫

// 需要使用encodeURI进行编码,处理中文问题
const bookInfoDomain = 'https://www.amazon.cn';
rp(bookInfoDomain + '/s?k=' + encodeURI(event.params.searchValue + '&i=stripbooks')).then(html => {
	return getBookBaseInfo(html);
}).catch(err => {
	console.log(err)
});

书本查询结果列表的搜索结果,(搜索书名“自立”的结果)如图所示:
真棒 真棒

左边为亚马逊的图书列表,其中红线框中的信息为需要提取的图书信息;右边为提取相关信息后,在小程序端展现的搜索结果列表。
通过分析结果页的dom结构,来提取相关信息,代码:

let bookHtmlList = [];
if (htmlString) {
	let $ = cheerio.load(htmlString);
	$('.s-search-results .s-result-item').each((i, e) => {
  		let href = $(e).find("[data-component-type='s-product-image'] a").attr('href');
  		let logo = $(e).find(".s-image").attr('src');
  		let name = $(e).find("h2").text();
  		let price = ($(e).find(".a-spacing-top-small .a-offscreen").text() || '').replace(/[^0-9|\.]/ig,"");
  
  		bookHtmlList.push({......}); // 省略
	})
}
return bookHtmlList;

使用cheerio来解析html串,其使用jquery的核心实现,可在服务端,直接像jquery一样使用。在列表页提取了href,为书本详情页的跳转做准备。

step2:详情页爬虫

书本详情的结果如图所示:

真棒 真棒

左图为亚马逊的图书列表,右图为小程序收集到相关信息的展示页:

总结:爬虫的重点为 找到核心、有效信息的网页,再使用cheerio进行解析,最后按照需要,使用类jquery api提取信息即可。

4.3、数据录入数据库中

这里提供了两种服务提供方式:

  • a、本地nodejs + mongodb
  • b、小程序自带云服务
本地nodejs + mongodb
真棒

如上图,为nodejs + mongodb的服务端代码结构,通过提供api的方式,提供数据服务。当然,上线之后,需要提供ssh证书,仅https协议的访问才被允许;在小程序的配置当中,需要将相关的服务域名进行配置(另外,小程序没有cookie、session的机制,如果服务端是做迁移的,需要在这方面做下融合)。

小程序自带云服务

云服务的部署、运维,现在就看看具体如何操作:

  • step1:生成云开发的账号,通过小程序的devtools,点击"云开发"去生成,如下图所示;
    真棒

  • step2:创建云开发目录,一般与小程序项目同级;

  • step3:新建云函数,在生成的云函数目录内(该目录为云函数的名称),进行npm install,安装相关的组件;(小程序通过云函数,与云服务进行交互)
    真棒

  • step4:进行相关云开发的配置,配置方法如下:

    a、project.config.json里添加:

    {"cloudfunctionRoot": "cloudfunctions/",}
    

    b、app.js的配置

    // 进行云服务的初始化
    onLaunch: function () {
    	if (!wx.cloud) {
    		console.error('请使用 2.2.3 或以上的基础库以使用云能力')
    	} else {
    		wx.cloud.init({
    			traceUser: true,
    		})
    	}
    	......
    }
    
  • step5: 云函数使用

    a、调用云函数

    // 亚马逊查找相应的书本
    wx.cloud.callFunction({
    	name: 'bookinfo',
    	data: {
    		type: 'search',
    		params: {
    			searchValue
    		}
    	},
      	success: data => {
          	......
      	},
      	fail: err => {
       	......
      	}
    })
    

    b、云函数接收

    	// 云函数入口函数
    	exports.main = async (event, context) => {
    		......
    		return rst;
    	}
    

    其中event的属性与data一样,可通过event,使用data中传递的值信息。

  • step6: 数据库的使用

    	const bookStoreDb = cloud.database();
    	const bookCollection = bookStoreDb.collection('book');
    	const _ = bookStoreDb.command
    	let whereInfo = {};
      if (event.params.searchValue) {
        whereInfo = _.or([
          {
            author: {$regex: '.*'+ event.params.searchValue}
          },
          {
            isbn: {$regex: '.*'+ event.params.searchValue}
          },
          {
            name: {$regex: '.*'+ event.params.searchValue}
          },
        ])
      }
    
      // 一次最多查询100个记录,total大于100,需要多次请求,拼合
      rst = await bookCollection.where(whereInfo).get().then(res => {
      	......
      });
      return rst;
    

5、其他

posted @ 2019-07-11 17:17  蒲公英tt  阅读(619)  评论(1编辑  收藏  举报