PHP + CSS + JS + JSON 数据采集与展示系统
下面我将为你实现一个完整的系统,包含前端单页展示、后端数据采集、JSON数据存储,并支持IIS和宝塔伪静态。
目录结构
bash
/project-root/
├── api/ # PHP后端文件
│ ├── collector.php # 数据采集脚本
│ ├── data.json # 存储采集的数据
│ └── config.php # 配置文件
├── static/ # 静态资源
│ ├── css/
│ │ └── style.css # 样式文件
│ └── js/
│ └── app.js # 前端JavaScript
├── index.php # 前端入口文件
└── .htaccess # Apache伪静态规则
1. 后端数据采集 (PHP)
api/config.php
php
<?php
// 配置采集的站点信息
$config = [
'target_sites' => [
'example' => [
'url' => 'https://example.com',
'selectors' => [
'title' => 'h1',
'content' => '.article-content',
'date' => '.post-date'
]
]
// 可以添加更多站点
],
'storage_file' => __DIR__ . '/data.json',
'update_interval' => 3600 // 1小时更新一次
];
// 设置JSON头
header('Content-Type: application/json');
// 跨域设置(根据需要)
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");
?>
api/collector.php
php
<?php
require_once 'config.php';
// 简单的HTML内容采集函数
function fetchData($url, $selectors) {
$html = file_get_contents($url);
if (!$html) return null;
$dom = new DOMDocument();
@$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$result = [];
foreach ($selectors as $key => $selector) {
$nodes = $xpath->query($selector);
if ($nodes && $nodes->length > 0) {
$result[$key] = trim($nodes->item(0)->nodeValue);
} else {
$result[$key] = '';
}
}
return $result;
}
// 检查是否需要更新数据
function needsUpdate($storageFile, $interval) {
if (!file_exists($storageFile)) return true;
$lastModified = filemtime($storageFile);
return (time() - $lastModified) > $interval;
}
// 主采集逻辑
if ($_SERVER['REQUEST_METHOD'] === 'POST' || needsUpdate($config['storage_file'], $config['update_interval'])) {
$allData = [];
foreach ($config['target_sites'] as $siteName => $siteConfig) {
$data = fetchData($siteConfig['url'], $siteConfig['selectors']);
if ($data) {
$data['source'] = $siteName;
$data['fetched_at'] = date('Y-m-d H:i:s');
$allData[] = $data;
}
}
file_put_contents($config['storage_file'], json_encode($allData, JSON_PRETTY_PRINT));
echo json_encode(['status' => 'success', 'message' => 'Data updated']);
} else {
// 直接返回现有数据
if (file_exists($config['storage_file'])) {
readfile($config['storage_file']);
} else {
echo json_encode(['status' => 'error', 'message' => 'No data available']);
}
}
?>
2. 前端展示
index.php
php
<?php
// 前端入口文件
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据采集展示系统</title>
<link rel="stylesheet" href="static/css/style.css">
</head>
<body>
<div class="container">
<h1>数据采集展示系统</h1>
<div class="controls">
<button id="refreshBtn">手动刷新数据</button>
<div class="loading" id="loadingIndicator" style="display: none;">加载中...</div>
</div>
<div id="dataContainer" class="data-container"></div>
</div>
<script src="static/js/app.js"></script>
</body>
</html>
static/css/style.css
css
/* 基础样式 */
body {
font-family: 'Arial', sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #2c3e50;
text-align: center;
margin-bottom: 30px;
}
.controls {
margin-bottom: 20px;
text-align: center;
}
button {
background-color: #3498db;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
button:hover {
background-color: #2980b9;
}
.loading {
margin-top: 10px;
color: #7f8c8d;
}
.data-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.data-item {
background: #ecf0f1;
padding: 15px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.data-item h2 {
margin-top: 0;
color: #2c3e50;
font-size: 1.2em;
}
.data-item .meta {
font-size: 0.9em;
color: #7f8c8d;
margin-bottom: 10px;
}
.data-item .content {
margin-top: 10px;
}
static/js/app.js
javascript
document.addEventListener('DOMContentLoaded', function() {
const dataContainer = document.getElementById('dataContainer');
const refreshBtn = document.getElementById('refreshBtn');
const loadingIndicator = document.getElementById('loadingIndicator');
// 加载数据
function loadData() {
loadingIndicator.style.display = 'block';
dataContainer.innerHTML = '';
fetch('api/collector.php')
.then(response => response.json())
.then(data => {
renderData(data);
loadingIndicator.style.display = 'none';
})
.catch(error => {
console.error('Error:', error);
dataContainer.innerHTML = '<div class="error">加载数据失败,请稍后再试</div>';
loadingIndicator.style.display = 'none';
});
}
// 渲染数据
function renderData(items) {
if (!items || items.length === 0) {
dataContainer.innerHTML = '<div class="no-data">暂无数据</div>';
return;
}
items.forEach(item => {
const itemElement = document.createElement('div');
itemElement.className = 'data-item';
let html = `
<h2>${item.title || '无标题'}</h2>
<div class="meta">
<span>来源: ${item.source || '未知'}</span> |
<span>日期: ${item.date || '未知'}</span>
</div>
<div class="content">${item.content || '无内容'}</div>
<div class="fetched-at">更新时间: ${item.fetched_at || '未知'}</div>
`;
itemElement.innerHTML = html;
dataContainer.appendChild(itemElement);
});
}
// 手动刷新
refreshBtn.addEventListener('click', function() {
// 强制更新数据
fetch('api/collector.php', {
method: 'POST'
})
.then(() => loadData())
.catch(error => {
console.error('Error:', error);
loadingIndicator.style.display = 'none';
});
});
// 初始加载
loadData();
// 定时刷新(每5分钟)
setInterval(loadData, 5 * 60 * 1000);
});
3. 伪静态配置
IIS伪静态 (web.config)
xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="JSON API" stopProcessing="true">
<match url="^api/data$" />
<action type="Rewrite" url="api/collector.php" />
</rule>
<rule name="Frontend" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
宝塔伪静态 (Nginx)
bash
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location /api/data {
rewrite ^/api/data$ /api/collector.php last;
}
Apache伪静态 (.htaccess)
ruby
RewriteEngine On
# API重写
RewriteRule ^api/data$ api/collector.php [L]
# 前端重写
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]
4. 使用说明
- 将上述文件按照目录结构放置
- 根据你的服务器环境配置伪静态规则
- 修改
api/config.php
中的目标站点和选择器配置 - 确保PHP环境已启用
file_get_contents
函数和DOM扩展 - 确保
api/data.json
文件可写(权限设置为666或775)
5. 扩展建议
- 安全性增强:添加API密钥验证
- 更多采集选项:支持POST请求、自定义头等
- 数据库支持:可扩展为使用MySQL等数据库
- 日志系统:记录采集历史
- 错误处理:更完善的错误处理和重试机制
这个系统实现了基本的数据采集和展示功能,前端使用单页应用模式,后端使用PHP采集数据并存储为JSON,同时支持多种服务器的伪静态配置。 更多数据详情:baijiahao.baidu.com/s?id=183050...