⭐️ Basic Link Navigation ⭐️
Server →☁️ AliCloud event address
See sample →🐟 Groping small website address
Learning Code →💻 Source code repository address
I. Preface
In the earlier chapters of this article series, we have successfully purchased servers and configured core middleware such as MySQL and Redis. Immediately after that, we not only set up the back-end services, but also developed our first crawler program. Later on, we also saved the crawled data, generated a complete set of MVC backend code and provided an interface out of it.
What about this post I'm going to start the front-end development part. The advantage of front-end development over back-end development is its intuitiveness and instant feedback. Developers can quickly see the results of their code, and this "what you see is what you get" experience greatly enhances the fun and satisfaction of development. In the next chapter, I will show how to crawl the hot search data into the front-end interface, so that it is presented in a user-friendly way, you can see.
II. Front-end application construction
My front-end tech stack is still stuck at four years old, when I mainly used Vue2 and ElementUI. it's not that I think Vue3 or React are bad, it's just that I'm more used to using technologies I'm familiar with. Even so, these technologies can still deliver good results. If you want to try different technologies or component libraries, that's perfectly fine.
1. Front-end environment setup
(1) Installation, download the appropriate version, download address:/en/download/ , after downloading double-click to install, click next until the installation is complete, it is recommended to download the version that is:
v16.20.2
(2) After the installation is complete, the attachment to select the command prompt (or in the start of the search box, type cmd enter to bring up the command panel) enter: node -v enter, the corresponding version of the proof of successful installation, node environment has been installed.
Due to some npm some resources are blocked or foreign resources, often lead to npm installation of dependent packages when the failure, all I also need npm domestic mirror --- cnpm. in the command line:npm install -g cnpm --registry=
Enter, it will take about 3 minutes, if there has been no response use administrator to run cmd and retry.
(3) Install the global vue-cli scaffolding that will be used to help build the required template framework. Enter the command:
cnpm install -g @vue/cli
Enter and wait for completion.
(4) to create the project, first we need to select the directory, and then the command line to directory to the selected directory, if we intend to create a new project in the e drive under the vue folder then enter the following command: e: enter, and then cd vue, and then enter the command:
vue create summo-sbmy-front-web
If you want to use vue2 or vue3, select vue2 and click enter, it will create the project and download the dependencies.
(5) Start the project, first switch to the sumo-sbmy-front-web directory, and then execute the
npm run serve
If the project runs successfully, the browser will automatically open localhost:8080 (if the browser does not open automatically, you can manually enter it). After running successfully, you will see the Welcome to Your App page.
2. Scaffolding treatment
My development tool is VS Code, which is free and can be downloaded at the following address:/。
(1) Document and code cleanup
Delete files under components
Delete files under assets
The original code is as follows
<template>
<div >
<img alt="Vue logo" src="./assets/">
<HelloWorld msg="Welcome to Your App"/>
</div>
</template>
<script>
import HelloWorld from './components/'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Remove unnecessary code, otherwise the startup will report an error
<template>
<div >
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
(2) axios and element-ui dependency introduction
Execute the installation command
//axiosdependency introduction
cnpm install axios
//element-uidependency introduction
cnpm install element-ui
After downloading the above two components, go to the center to register the component, and then can be used, the code is as follows:
import Vue from 'vue'
import App from './'
//Introducing Hungry MouseUI
import {
Calendar,
Row,
Col,
Link,
Button,
Loading,
Container,
Header,
Footer,
Main,
Form,
Autocomplete,
Tooltip,
Card,
Dialog
} from 'element-ui';
(Calendar)
(Row)
(Col)
(Link)
(Button)
(Loading)
(Container)
(Header)
(Footer)
(Form)
(Autocomplete)
(Tooltip)
(Card)
(Main)
(Dialog)
import "element-ui/lib/theme-chalk/"
//pull intoaxios
import axios from 'axios';
.$ajax = axios;
= false
new Vue({
render: h => h(App),
}).$mount('#app')
(3) Encapsulation of easy-to-call interfaces
Create a folder named config in the src directory, create one, with the following code:
//
import axios from "axios";
// establishaxiosExample and configure the baseURL
const apiClient = ({
baseURL: "http://localhost:80/api",
headers: {
"Content-Type": "application/json"
},
});
export default {
// seal insideGetconnector
get(fetchUrl) {
return (fetchUrl);
}
};
III. Front-end hot search components
1. Introduction to components
First of all, the finished hot search component is styled as follows, including the title (icon + name), content area (sorting, title, hotness), and clicking on the title can jump to the specified hot search article.
2. Component realization
In the components directory, create thefile with the following code:
<template>
<el-card class="custom-card" v-loading="loading">
<template #header>
<div class="card-title">
<img :src="icon" class="card-title-icon" />
{{ title }}hot list
</div>
</template>
<div class="cell-group-scrollable">
<div
v-for="item in hotSearchData"
:key=""
:class="getRankingClass()"
class="cell-wrapper"
>
<span class="cell-order">{{ }}</span>
<span
class="cell-title hover-effect"
@click="openLink()"
>
{{ }}
</span>
<span class="cell-heat">{{ formatHeat() }}</span>
</div>
</div>
</el-card>
</template>
<script>
import apiService from "@/config/";
export default {
props: {
title: String,
icon: String,
type: String,
},
data() {
return {
hotSearchData: [],
loading:false
};
},
created() {
();
},
methods: {
fetchData(type) {
= true
apiService
.get("/hotSearch/queryByType?type=" + type)
.then((res) => {
// Processing response data
= ;
})
.catch((error) => {
// Handling of error conditions
(error);
}).finally(() => {
// End of loading
= false;
});
},
getRankingClass(order) {
if (order === 1) return "top-ranking-1";
if (order === 2) return "top-ranking-2";
if (order === 3) return "top-ranking-3";
return "";
},
formatHeat(heat) {
// in the event that heat Already a string,beginning with "ten thousand" wind up,Then return directly to
if (typeof heat === "string" && ("ten thousand")) {
return heat;
}
let number = parseFloat(heat); // Ensure conversion to numeric types for comparison
if (isNaN(number)) {
return heat; // in the event that无法convert to数值,then return as is
}
// in the event that数值小于1000,Returns the value directly
if (number < 1000) {
return ();
}
// in the event that数值在1000until (a time)9999among,convert tokunit (e.g. of measure)
if (number >= 1000 && number < 10000) {
return (number / 1000).toFixed(1) + "k";
}
// in the event that数值大于等于10000,convert toten thousandunit (e.g. of measure)
if (number >= 10000) {
return (number / 10000).toFixed(1) + "ten thousand";
}
},
openLink(url) {
if (url) {
// Using Open Link in New Tab
(url, "_blank");
}
},
},
};
</script>
<style scoped>
.custom-card {
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.custom-card:hover {
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.25);
}
>>> .el-card__header {
padding: 10px 18px;
}
>>> .el-card__body {
display: flex;
padding: 10px 0px 10px 10px;
}
.card-title {
display: flex;
align-items: center;
font-weight: bold;
font-size: 16px;
}
.card-title-icon {
fill: currentColor;
width: 24px;
height: 24px;
margin-right: 8px;
}
.cell-group-scrollable {
max-height: 350px;
overflow-y: auto;
padding-right: 16px; /* Restore inner margins of content areas */
flex: 1;
}
.cell-wrapper {
display: flex;
align-items: center;
padding: 8px 8px; /* Reduce top and bottom inner margins to minimize spacing */
border-bottom: 1px solid #e8e8e8; /* 为每个项among添加分割线 */
}
.cell-order {
width: 20px;
text-align: left;
font-size: 16px;
font-weight: 700;
margin-right: 8px;
color: #7a7a7a; /* Harmonization of non-special serial number colors */
}
/* This is accomplished through the use of thecell-heatAdd more parent selectors in front of the class,Improved specificity */
.cell-heat {
min-width: 50px;
text-align: right;
font-size: 12px;
color: #7a7a7a;
}
.cell-title {
font-size: 13px;
color: #495060;
line-height: 22px;
flex-grow: 1;
overflow: hidden;
text-align: left; /* left justification */
text-overflow: ellipsis; /* Show ellipses for overruns */
}
.top-ranking-1 .cell-order {
color: #fadb14;
} /* gold (color) */
.top-ranking-2 .cell-order {
color: #a9a9a9;
} /* silver (color) */
.top-ranking-3 .cell-order {
color: #d48806;
} /* copper color */
/* added.hover-effectclass is used for the title of thehoverstate of affairs */
.-effect {
cursor: pointer; /* Show pointer shape on mouse hover */
transition: color 0.3s ease; /* Smooth transition of color changes */
}
/* When the mouse is hovering over a file with.hover-effectclass changes color when it is placed on an element of the */
.-effect:hover {
color: #409eff; /* Or use your favorite color */
}
</style>
Add a hot search component to it, and since there's more than one hot search, I've made it into an array
<template>
<div >
<el-row :gutter="10">
<el-col :span="6" v-for="(board, index) in hotBoards" :key="index">
<hot-search-board
:title=""
:icon=""
:fetch-url=""
:type=""
/>
</el-col>
</el-row>
</div>
</template>
<script>
import HotSearchBoard from "@/components/";
export default {
name: "App",
components: {
HotSearchBoard,
},
data() {
return {
hotBoards: [
{
title: "Baidu",
icon: require("@/assets/icons/"),
type: "baidu",
},
{
title: "jitterbug",
icon: require("@/assets/icons/"),
type: "douyin",
},
],
};
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
background: #f8f9fa; /* Provides a soft background color */
min-height: 100vh; /* Use the viewport height to ensure that it fills the entire screen */
padding: 0; /* Keep the overall layout compact,No extra inside margins */
}
</style>
The final project structure and documentation is as follows
The code is not difficult, it is just the use of cards and lists of hot searches on the display, and I added some styles, such as the top three of the sorting has a color, the font changed.
IV. To summarize
In this post, I mainly show the front-end code logic. As for the back-end, some updates have been made, such as the addition of queryType interface and the handling of cross-domain requests, but these contents are basic, you can download the code at a glance, do not understand the comment section to communicate, or add my WeChat:hb1766435296
. The previous preparations are finally starting to pay off, and although it looks simple, it actually solves quite a few complex problems. Now that the foundations of the server, front-end and back-end have been laid, I'll continue to develop and add more features.
Regarding the crawler part, I have successfully implemented the crawling function against 12 different websites. Considering that the logic of the crawler is relatively simple, there is no need to write a separate article to explain it in detail. Therefore, I plan to briefly introduce the crawler logic for each hot search site in the appendix or extra section of each article. This arrangement will ensure the completeness of the information without making the article too lengthy.
Extra: Knowing the Hot Search Crawler
1. Evaluation of the reptile program
The know hot search looks like this, and the interface is:/api/v3/feed/topstory/hot-lists/total
The data is still complete, with title, heat, cover, sorting, etc. Zhihu's hot search interface returns data in JSON format, which is simpler than returning HTML.
2. Web page parsing code
This will be able to use Postman to generate the calling code, the process I will not repeat, directly on the code, ZhihuHotSearchJob:
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import ;
import static ;
/**
* @author summo
* @version , 1.0.0
* @description a popular search on Zhihuai (Chinese social network)Javacrawler code
* @date 2024surname Nian08moon09
*/
@Component
@Slf4j
public class ZhihuHotSearchJob {
@Autowired
private SbmyHotSearchService sbmyHotSearchService;
/**
* Timed Trigger Crawler Method,1Performed once an hour
*/
@Scheduled(fixedRate = 1000 * 60 * 60)
public void hotSearch() throws IOException {
try {
//查询a popular search on Zhihuai (Chinese social network)数据
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new ().url("/api/v3/feed/topstory/hot-lists/total")
.method("GET", null).build();
Response response = (request).execute();
JSONObject jsonObject = (().string());
JSONArray array = ("data");
List<SbmyHotSearchDO> sbmyHotSearchDOList = ();
for (int i = 0, len = (); i < len; i++) {
//获取a popular search on Zhihuai (Chinese social network)信息
JSONObject object = (JSONObject)(i);
JSONObject target = ("target");
//Build a hot search information list
SbmyHotSearchDO sbmyHotSearchDO = ().hotSearchResource(()).build();
//Setting up the Knowledge TripartiteID
(("id"));
//Setting up article links
("/question/" + ());
//Setting the article title
(("title"));
//Setting the author name
(("author").getString("name"));
//Setting the author avatar
(("author").getString("avatar_url"));
//Setting up article summaries
(("excerpt"));
//Setting the heat of a hot search
(("detail_text").replace("short-lived enthusiasm", ""));
//ordinal order
(i + 1);
(sbmyHotSearchDO);
}
//Data persistence
sbmyHotSearchService.saveCache2DB(sbmyHotSearchDOList);
} catch (IOException e) {
("Getting Knowledgeable Data Anomalies", e);
}
}
}
Zhihu's hot search data comes with a unique ID, which is very convenient as we don't need to generate it manually.