Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:爬取教务处新闻并展示 #30

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/src/main.ts
Expand Up @@ -10,6 +10,7 @@ import {CourseRepository} from "./model/course/course";
import {StudentRepository, StudentService} from "./model/student/student";
import {ObjectID} from "bson";
import {DateTimeService} from "../../shared/tools/dateTime/dateTime";
import {fetchNews} from "./service/crawl/news/news"

const app = new Koa();
const router = new Router();
Expand Down Expand Up @@ -112,6 +113,9 @@ router
context.status = 403;
}
})
.post('/api/fetchNews',async(context)=>{
context.body =await fetchNews(context.request.body.type,context.request.body.startIndex,context.request.body.endIndex)
})
.get('/*', async (context) => {
context.body = 'It works!';
});
Expand Down
53 changes: 53 additions & 0 deletions backend/src/service/crawl/news/news.ts
@@ -0,0 +1,53 @@
import * as Cheerio from 'cheerio';
import * as url from 'url';
import * as Request from 'request-promise-native';


const host = 'http://www.jwc.shu.edu.cn';
/**
* 爬取教务处网站公告新闻
* @param type 数据类型
* @param startIndex 起始条数
* @param endIndex 终止条数
*/
export async function fetchNews(type:string,startIndex:number,endIndex:number) {
let link:string;
if(type == "新闻"){
if(startIndex>=30){
link = `http://www.jwc.shu.edu.cn/index/tzgg/${51-Math.floor(startIndex/30)}.htm`;
startIndex =startIndex %30;
endIndex = endIndex %30 === 0 ? 30:endIndex%30;
} else {link = 'http://www.jwc.shu.edu.cn/index/tzgg.htm'}
} else {
if(startIndex>=30){
link = `http://www.jwc.shu.edu.cn/index/xw/${19-Math.floor(startIndex/30)}.htm`;
startIndex =startIndex %30;
endIndex = endIndex %30 === 0 ? 30:endIndex%30;
} else {link = 'http://www.jwc.shu.edu.cn/index/xw.htm'}
}
let respond = await Request.get(link)
console.log(link);
console.log(startIndex)
const $ = Cheerio.load(respond);
let list:Array<any> =$('#dnn_ctr43516_ArticleList__ctl0_ArtDataList__ctl1_titleLink1').slice(startIndex,endIndex)
.map(function(index:number, ele:CheerioElement) {
return {
title: $(ele).attr('title'),
link: $(ele).attr('href'),
data: $('#dnn_ctr43516_ArticleList__ctl0_ArtDataList__ctl1_Label6').eq(index+startIndex).text(),
};
})
.get();
const all:Promise<any> = Promise.all(
list.map((item) => {
const itemUrl = url.resolve(host, item.link);
const single = {
title: item.title,
link: itemUrl,
data:item.data
};
return Promise.resolve(single);
})
)
return all;
};
3 changes: 2 additions & 1 deletion frontend/layouts/default.vue
Expand Up @@ -68,7 +68,8 @@
title = 'SHUHelper';
items = [
{icon: 'school', title: '首页', to: '/'},
{icon: 'calendar_today', title: '日程', to: '/schedule'}
{icon: 'calendar_today', title: '日程', to: '/schedule'},
{icon: 'list',title: '新闻', to: '/schoolNews'}
];

auth() {
Expand Down
79 changes: 79 additions & 0 deletions frontend/pages/schoolNews.vue
@@ -0,0 +1,79 @@
<template>
<div>
<v-select :items="allType" v-model="type"></v-select>
<v-progress-linear :indeterminate="true" v-if="isLoading"></v-progress-linear>
<v-list v-for="item in news" :key="item.title" v-else dense>
<a :href="item.link" target="_blank" id="article_link">
<v-list-tile>
<v-list-tile-title>
{{item.title}}
</v-list-tile-title>
<v-list-tile-action-text id="article_data">
{{item.data}}
</v-list-tile-action-text>
</v-list-tile>
</a>
</v-list>
<v-pagination v-model="page" :length = 50 circle></v-pagination>
</div>
</template>

<script lang="ts">
import Component, {namespace} from "nuxt-class-component";
import {Vue, Watch} from 'vue-property-decorator';

@Component({

})
export default class schoolNews extends Vue{
allNews:any;
news:any;
allType=['通知公告','新闻'];
type = '新闻';
page:number = 1;
isLoading:boolean = true;
@Watch('page')
onPageChanged(){
this.isLoading = true
if(this.page>5){
this.$axios.$post('/api/fetchNews',{type:this.type,startIndex:(this.page-1)*6,endIndex:this.page*6})
.then(res=>{
this.news=res
this.isLoading = false;
})
} else {
this.news = this.allNews.slice((this.page-1)*6,this.page*6)
this.isLoading = false;
}
}
@Watch('type')
onTypeChanged(){
this.isLoading = true;
this.$axios.$post('/api/fetchNews',{type:this.type,startIndex:0,endIndex:30})
.then(res=>{
this.allNews = res;
this.page = 1;
this.news = this.allNews.slice(0,6);
this.isLoading = false;
})
}
mounted(){
this.$axios.$post('/api/fetchNews',{type:this.type,startIndex:0,endIndex:30})
.then(res=>{
this.allNews = res;
this.news=this.allNews.slice(0,6)
this.isLoading = false;
})
}
}
</script>

<style scoped>
#article_link{
text-decoration: none;
color:white
}
#article_data{
white-space: nowrap;
}
</style>