本文 首发于 Anyeの小站
后端使用 python 构建API,用于每次访问的时候分析抓取最新的hybase安卓软件
import requests
from bs4 import BeautifulSoup
import json
import re
from flask import Flask, redirect
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
def get_hybase_content(page_number):
base_url = "https://www.hybase.com/shouji/android/"
if page_number == 1:
url = base_url
else:
url = f"{base_url}index_{page_number}.html"
response = requests.get(url)
soup = BeautifulSoup(response.content.decode('GB2312'), 'html.parser')
items = soup.find_all('div', class_='entry')
data = []
for item in items:
title = item.find('h2').text.strip()
thumb_url = item.find('img')['src']
article_url = item.find('a')['href']
publish_time = soup.find('em').text
description = item.find('div', class_='entry-content').find('span').text.strip()
description = re.sub(r'\s+', ' ', description)
data.append({
'title': title,
'thumb_url': f"https://www.hybase.com{thumb_url}",
'url': f"https://www.hybase.com{article_url}",
'publish_time': publish_time,
'description': description
})
return json.dumps(data, ensure_ascii=False)
@app.route('/api/', methods=['GET'])
def default_route():
return redirect('/api/1')
@app.route('/api/' , methods=['GET'])
def hybase(page_number):
content = get_hybase_content(page_number)
response = app.response_class(
response=content,
status=200,
mimetype='application/json'
)
return response
if __name__ == '__main__':
app.run(debug=False)
前端使用 /api
反代该接口,同时搭建静态页面调用
DOCTYPE html>
<html lang="zh">
<head>
<title>黑域基地 - 安卓软件title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="黑域基地致力于打造良心软件的栖息之地。提供最新纯净软件、优秀实用等精品软件,每个软件评测都极其用心,保证软件的安全与可用性!">
<link rel="icon" type="image/png" href="https://www.hybase.com/img/bxr.png">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css">
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
overflow-x: hidden;
width: 100%;
background-color: #f5f5f5;
}
.mdl-layout__header {
background-color: white;
}
.mdl-layout__header-row {
padding: 10px;
color: black;
display: flex;
justify-content: center;
align-items: center;
}
.site-logo {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
margin-right: 10px;
}
.card {
width: 90%;
margin: 20px auto;
text-align: left;
position: relative;
cursor: pointer;
border-radius: 5px;
overflow: hidden;
}
.card::before {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.4);
z-index: 1;
}
.card:hover {
background: rgba(0, 0, 0, 0.3);
}
.card img {
max-width: 100%;
height: auto;
margin-bottom: 10px;
object-fit: cover;
z-index: 0;
}
.card .title {
font-size: 1.5em;
z-index: 2;
position: relative;
padding: 20px;
color: black;
text-align: center;
}
.card .description {
font-size: 1em;
z-index: 2;
position: relative;
padding: 20px;
color: black;
}
.card .actions {
text-align: right;
}
.navigation-buttons {
display: flex;
justify-content: center;
margin: 20px;
}
@media (max-width: 600px) {
.mdl-layout__header-row {
font-size: 1.5em;
}
.card .title {
font-size: 1.2em;
}
.card .description {
font-size: 0.9em;
}
}
style>
<script>
function redirectDesktopUsers() {
const screenWidth = window.innerWidth;
const isDesktop = screenWidth >= 1024;
if (isDesktop) {
const confirmRedirect = confirm("您正在使用电脑访问该页面,是否跳转到手机安卓页面?");
if (confirmRedirect) {
window.location.href = "https://www.hybase.com/shouji/android/";
}
}
}
window.addEventListener('load', redirectDesktopUsers);
script>
head>
<body>
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<div class="mdl-layout__header-row">
<img src="https://www.hybase.com/logo.png" alt="黑域基地 Logo" class="site-logo">
<span class="mdl-layout-title">span>
div>
header>
<main class="mdl-layout__content">
<div class="mdl-grid">
div>
<div class="navigation-buttons">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect previous-button"
onclick="previousPage()" style="display: none;">上一页button>
<button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect"
onclick="nextPage()">下一页button>
div>
main>
div>
<script src="https://code.getmdl.io/1.3.0/material.min.js">script>
<script>
let currentPage = 1;
async function fetchData(pageNumber) {
const response = await fetch(`/api/${pageNumber}`);
const data = await response.json();
return data;
}
async function displaySoftware(pageNumber) {
const grid = document.querySelector('.mdl-grid');
grid.innerHTML = '';
const data = await fetchData(pageNumber);
if (data.length === 0) {
const noContentDiv = document.createElement('div');
noContentDiv.textContent = 'No content available.';
grid.appendChild(noContentDiv);
return;
}
data.forEach(item => {
const title = item.title.replace('[Android] ', '');
const card = document.createElement('div');
card.classList.add('card', 'mdl-card', 'mdl-shadow--2dp');
card.innerHTML = `
${item.thumb_url}" alt="Thumbnail">
${title}
发布时间:${item.publish_time}
描述:${item.description}
`;
grid.appendChild(card);
card.addEventListener('click', () => {
openInNewTab(item.url);
});
});
const previousButton = document.querySelector('.previous-button');
if (currentPage > 1) {
previousButton.style.display = 'inline-block';
} else {
previousButton.style.display = 'none';
}
}
async function previousPage() {
if (currentPage > 1) {
currentPage--;
await displaySoftware(currentPage);
}
}
async function nextPage() {
currentPage++;
await displaySoftware(currentPage);
}
function openInNewTab(url) {
window.open(url, '_blank');
}
displaySoftware(currentPage);
script>
body>
html>
适应手机界面,检测非手机打开自动跳转原站打开