当前位置: 首页 > 后端技术 > Node.js

Koa2+Mongo+爬虫搭建一个新颖的微信小程序(本地开发)

时间:2023-04-03 19:07:16 Node.js

前言:根据MOOCKoa2,实现电影微信公众号前端和前端开发的改造。因为上下班的时候可以看小说,但是无奈广告太多了,而且要收费,所以结合课程,开发了,上传到我的微信小程序。github的总体思路:1.连接数据库2.运行定时任务更新数据库3.开启接口服务4.微信小程序接口调用1.连接数据库,连接本地mongodb数据库constmongoose=require('mongoose')vardb='mongodb://localhost/story-bookShelf'exports.connect=()=>{让maxConnectTimes=0returnnewPromise((resolve,reject)=>{if(process.env.NODE_ENV!=='production'){mongoose.set('debug',false)}mongoose.connect(db)mongoose.connection.on('disconnected',()=>{maxConnectTimes++if(maxConnectTimes<5){mongoose.connect(db)}else{thrownewError('Thedatabaseisdown,let'sfixit')}})mongoose.connection.on('error',err=>{console.log(err)maxConnectTimes++if(maxConnectTimes<5){mongoose.connect(db)}else{thrownewError('数据库已关闭,让我们修复它')}})mongoose.connection.once('open',()=>{resolve()console.log('MongoDBConnectedsuccessfully!')})})}然后初始化定义好的Schemaconstmongoose=require('mongoose')constSchema=mongoose.SchemaconstbookSchema=newSchema({name:{type:String},bookId:{unique:true,type:Number}})......mongoose.model('Book',bookSchema)2.运行计划任务并更新数据库。这一步主要是定时更新数据库中的小说章节。Node-schedule用于执行计划任务。小说章节数是否增加不需要爬取。同时,爬取的时候需要提前爬取前5章,避免一些作者为了占坑而提前写的预告。每部小说都会运行一个子进程child_process,将数据存储到mongo中,存储子进程对后续有帮助。定时运行任务时,之前的任务还在运行,所以每次运行前,清除存储的子进程,kill掉子进程。章节任务//chapter.jsconstcp=require('child_process')const{resolve}=require('path')constmongoose=require('mongoose')const{childProcessStore}=require('../lib/child_process_store')//全局存储子进程/****@param{bookID}bookId*@param{从哪里开始看}startNum*/exports.taskChapter=async(bookId,startNum=0)=>{constChapter=mongoose.model('Chapter')constscript=resolve(__dirname,'../crawler/chapter.js')//实际执行爬虫任务模块constchild=cp.fork(script,[])//打开IPCchannel,transferdataletinvoked=false//等待子进程传回数据,然后存入mongo(具体爬取看下一段代码)child.on('message',asyncdata=>{//先找有没有数据letchapterData=awaitChapter.findOne({chapterId:data.chapterId})//需要将获取的章节和存储的章节进行比较,防止作者占坑if(!chapterData){chapterData=newChapter(data)awaitchapterData.save()return}//比较字数,相差50个字符if((data.content.length-50>=0)&&(data.content.length-50>章节数据.content.length)){Chapter.updateOne({chapterId:+data.chapterId},{content:data.content});}})child.send({//发送给子进程抓取bookId,//whereThisnovelstartNum//从哪一章开始抓取})//存储运行进程抓取的所有章节并删除子进程childProcessStore.set('chapter',child)}真正开始爬取,使用puppeteer,谷歌内核爬取,很强大分两步:1.爬取小说对应的章节目录,获取章节数组2.根据传入的startNum爬取章节startNum//crawler/chapter.jsconstpuppeteer=require('puppeteer')leturl=`http://www.mytxt.cc/read/`//目标URLconstsleep=time=>newPromise(resolve=>{setTimeout(resolve,time)})process.on('message',asyncbook=>{url=`${url}${book.bookId}/`console.log('开始访问目标页面---章节',url)//查找对应的小说并获取具体章节数组constbrowser=awaitpuppeteer.launch({args:['--no-sandbox'],dumpio:false}).catch(err=>{console.log('browser--error:',err)browser.close})constpage=awaitbrowser.newPage()awaitpage.goto(url,{waitUntil:'networkidle2'})awaitsleep(3000)awaitpage.waitForSelector('.story_list_m62topxs')//找到特定字段的类letresult=awaitpage.evaluate((book)=>{letlist=document.querySelectorAll('.cp_dd_m62topxsli')letreg=newRegExp(`${book.bookId}\/(\\S*).html`)letchapter=Array.from(list).map((item,iindex)=>{return{title:item.innerText,chapterId:item.innerHTML.match(reg)[1]}})returnchapter},book)//拦截从哪里开始爬取章节lettempResult=result.slice(book.startNum,result.length)for(leti=0;i{returndocument.querySelectorAll('.detail_con_m62topxsp')[0].innerText})tempResult[i].content=contenttempResult[i].bookId=book.bookIdprocess.send(tempResult[i])//通过IPC回传数据并触发child.on('message')}browser.close()process.exit(0)})3.打开接口主要任务是获取mongodb数据,通过koa发布路由-router先定义路由装饰器,方便后续使用。看decorator.js底层从数据库中获取数据service/book.js//获取数据库中存储的值constChapter=mongoose.model('Chapter')//获取具体的Chapter内容exportconstgetDetailChapter=async(data)=>{constchapter=awaitChapter.findOne({chapterId:data.chapterId,bookId:data.bookId},{content:1,title:1,chapterId:1})//控制台.log('getDetailChapter::',chapter)returnchapter}...路由定义的后续接口为'/api/book/chapter'@controller('/api/book')exportclassbookController{@post('/chapter')asyncgetDetailChapter(ctx,next){const{chapterId,bookId}=ctx.request.body.dataconstlist=awaitgetDetailChapter({chapterId,bookId})ctx.body={success:true,data:list}}}4.微信小程序是使用wepy开发的,功能也很简单。具体开发请参考小程序代码。支持记录每章进度和全局设置这里就不详细说了。后续可以自己玩。在目标网站上找到小说的Id后,就可以搜索了。接下来,我们将解释部署到服务器的细节。最后感谢@汪江江哥的帮助。我想了两个月,他却只用了三天。感谢您的不懈帮助。很高兴与您合作。以上只是本人技术不成熟,欢迎大家留言指教。