PHP+JS+CSS+JSON 新闻采集系统实现方案

53 阅读4分钟

PHP+JS+CSS+JSON 新闻采集系统实现方案

下面是一个完整的实现方案,用于采集中国新闻网(Chinanews.com)的最新新闻,并以JSON格式存储数据,支持翻页和伪静态。

系统架构

/news-collector/
├── index.php          // 主控制器
├── functions.php      // 核心功能函数
├── config.php         // 配置文件
├── static/
│   ├── css/style.css  // 样式文件
│   └── js/script.js   // JavaScript文件
├── storage/           // JSON存储目录
│   ├── page1.json
│   ├── page2.json
│   └── ...
└── .htaccess          // Apache伪静态规则

1. 配置文件 (config.php)

<?php
// 基本配置
define('SITE_URL', 'https://www.chinanews.com/');
define('PER_PAGE', 10); // 每页显示新闻数量
define('MAX_PAGES', 5); // 最大采集页数
define('STORAGE_DIR', __DIR__ . '/storage/');
define('CACHE_TIME', 3600); // 缓存时间1小时

// 确保存储目录存在
if (!file_exists(STORAGE_DIR)) {
    mkdir(STORAGE_DIR, 0755, true);
}

2. 核心功能 (functions.php)

<?php
require_once 'config.php';

/**
 * 采集中国新闻网新闻
 */
function fetch_news($page = 1) {
    $url = SITE_URL . ($page > 1 ? "scroll-news/news{$page}.html" : "scroll-news/news1.html");
    
    $html = file_get_contents($url);
    if (!$html) {
        return false;
    }
    
    // 使用DOMDocument解析HTML
    $dom = new DOMDocument();
    @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
    $xpath = new DOMXPath($dom);
    
    $news = [];
    $items = $xpath->query("//div[contains(@class, 'content_list')]//li");
    
    foreach ($items as $item) {
        $titleNode = $xpath->query(".//a", $item)->item(0);
        if (!$titleNode) continue;
        
        $title = trim($titleNode->nodeValue);
        $link = $titleNode->getAttribute('href');
        
        // 处理相对链接
        if (strpos($link, 'http') !== 0) {
            $link = SITE_URL . ltrim($link, '/');
        }
        
        // 获取新闻详情
        $content = fetch_news_content($link);
        
        $news[] = [
            'title' => $title,
            'link' => $link,
            'content' => $content,
            'time' => date('Y-m-d H:i:s'),
            'source' => '中国新闻网'
        ];
    }
    
    return $news;
}

/**
 * 获取新闻详情内容
 */
function fetch_news_content($url) {
    $html = @file_get_contents($url);
    if (!$html) return '';
    
    $dom = new DOMDocument();
    @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
    $xpath = new DOMXPath($dom);
    
    // 尝试获取正文内容 - 根据中国新闻网的实际结构调整
    $content = '';
    $paragraphs = $xpath->query("//div[contains(@class, 'left_zw')]//p");
    
    foreach ($paragraphs as $p) {
        $content .= '<p>' . trim($p->nodeValue) . '</p>';
    }
    
    return $content;
}

/**
 * 保存新闻数据到JSON
 */
function save_news_to_json($page, $data) {
    $filename = STORAGE_DIR . "page{$page}.json";
    file_put_contents($filename, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
    return $filename;
}

/**
 * 从JSON加载新闻数据
 */
function load_news_from_json($page) {
    $filename = STORAGE_DIR . "page{$page}.json";
    if (!file_exists($filename)) {
        return false;
    }
    
    $data = file_get_contents($filename);
    return json_decode($data, true);
}

/**
 * 检查是否需要更新缓存
 */
function is_cache_expired($page) {
    $filename = STORAGE_DIR . "page{$page}.json";
    if (!file_exists($filename)) {
        return true;
    }
    
    return (time() - filemtime($filename)) > CACHE_TIME;
}

3. 主控制器 (index.php)

<?php
require_once 'functions.php';

$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;

// 检查缓存或采集新数据
if (is_cache_expired($page)) {
    $news = fetch_news($page);
    if ($news) {
        save_news_to_json($page, $news);
    } else {
        // 采集失败,尝试加载缓存
        $news = load_news_from_json($page) ?: [];
    }
} else {
    $news = load_news_from_json($page) ?: [];
}

// 输出HTML
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>中国新闻网新闻采集 - 第<?php echo $page; ?>页</title>
    <link rel="stylesheet" href="static/css/style.css">
</head>
<body>
    <div class="container">
        <h1>中国新闻网最新新闻</h1>
        <div class="news-list" id="newsList">
            <?php if (!empty($news)): ?>
                <?php foreach ($news as $item): ?>
                    <div class="news-item">
                        <h2><a href="<?php echo htmlspecialchars($item['link']); ?>" target="_blank"><?php echo htmlspecialchars($item['title']); ?></a></h2>
                        <div class="news-content"><?php echo $item['content']; ?></div>
                        <div class="news-meta">
                            <span class="source">来源: <?php echo htmlspecialchars($item['source']); ?></span>
                            <span class="time">时间: <?php echo htmlspecialchars($item['time']); ?></span>
                        </div>
                    </div>
                <?php endforeach; ?>
            <?php else: ?>
                <p>暂无新闻数据</p>
            <?php endif; ?>
        </div>
        
        <div class="pagination">
            <?php if ($page > 1): ?>
                <a href="<?php echo get_page_url($page - 1); ?>" class="prev">上一页</a>
            <?php endif; ?>
            
            <?php for ($i = 1; $i <= MAX_PAGES; $i++): ?>
                <a href="<?php echo get_page_url($i); ?>" <?php echo $i == $page ? 'class="active"' : ''; ?>><?php echo $i; ?></a>
            <?php endfor; ?>
            
            <?php if ($page < MAX_PAGES): ?>
                <a href="<?php echo get_page_url($page + 1); ?>" class="next">下一页</a>
            <?php endif; ?>
        </div>
    </div>
    
    <script src="static/js/script.js"></script>
</body>
</html>

4. JavaScript文件 (static/js/script.js)

document.addEventListener('DOMContentLoaded', function() {
    // 可以添加一些交互效果
    const newsItems = document.querySelectorAll('.news-item');
    
    newsItems.forEach(item => {
        item.addEventListener('click', function(e) {
            if (e.target.tagName !== 'A') {
                this.querySelector('.news-content').classList.toggle('expanded');
            }
        });
    });
    
    // 可以添加AJAX加载功能
    /*
    document.querySelectorAll('.pagination a').forEach(link => {
        link.addEventListener('click', function(e) {
            e.preventDefault();
            const page = this.getAttribute('href').split('=')[1];
            fetchNews(page);
        });
    });
    
    function fetchNews(page) {
        fetch(`api.php?page=${page}`)
            .then(response => response.json())
            .then(data => {
                renderNews(data);
                history.pushState(null, null, `?page=${page}`);
            });
    }
    */
});

5. CSS样式文件 (static/css/style.css)

body {
    font-family: 'Microsoft YaHei', Arial, sans-serif;
    line-height: 1.6;
    color: #333;
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    background-color: #f5f5f5;
}

.container {
    background-color: #fff;
    padding: 20px;
    border-radius: 5px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h1 {
    color: #d32f2f;
    border-bottom: 1px solid #eee;
    padding-bottom: 10px;
}

.news-list {
    margin: 20px 0;
}

.news-item {
    padding: 15px;
    margin-bottom: 20px;
    border: 1px solid #eee;
    border-radius: 4px;
    transition: all 0.3s ease;
}

.news-item:hover {
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
}

.news-item h2 {
    margin: 0 0 10px;
    font-size: 18px;
}

.news-item h2 a {
    color: #333;
    text-decoration: none;
}

.news-item h2 a:hover {
    color: #d32f2f;
}

.news-content {
    max-height: 100px;
    overflow: hidden;
    transition: max-height 0.5s ease;
}

.news-content.expanded {
    max-height: 2000px;
}

.news-content p {
    margin: 5px 0;
    font-size: 14px;
    color: #666;
}

.news-meta {
    margin-top: 10px;
    font-size: 12px;
    color: #999;
}

.news-meta span {
    margin-right: 15px;
}

.pagination {
    text-align: center;
    margin-top: 30px;
}

.pagination a {
    display: inline-block;
    padding: 5px 12px;
    margin: 0 5px;
    border: 1px solid #ddd;
    text-decoration: none;
    color: #333;
    border-radius: 3px;
}

.pagination a:hover {
    background-color: #f0f0f0;
}

.pagination a.active {
    background-color: #d32f2f;
    color: white;
    border-color: #d32f2f;
}

6. 伪静态配置

Apache (.htaccess)

<IfModule mod_rewrite.c>
    RewriteEngine On
    
    # 确保不是文件或目录
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # 新闻分页伪静态
    RewriteRule ^news/page/([0-9]+)/?$ index.php?page=$1 [L,QSA]
    
    # 首页重定向
    RewriteRule ^$ index.php [L]
</IfModule>

IIS (web.config)

<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="News Pagination" stopProcessing="true">
                    <match url="^news/page/([0-9]+)/?$" />
                    <action type="Rewrite" url="index.php?page={R:1}" />
                </rule>
                <rule name="Homepage" stopProcessing="true">
                    <match url="^$" />
                    <action type="Rewrite" url="index.php" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

宝塔面板伪静态

在宝塔面板中选择网站 -> 设置 -> 伪静态,然后粘贴Apache的.htaccess规则即可。

使用说明

  1. 将上述文件按照目录结构放置
  2. 确保服务器支持PHP和URL重写
  3. 根据实际需要调整中国新闻网的HTML解析逻辑,因为网站结构可能会变化
  4. 可以通过修改config.php中的配置来调整采集参数

注意事项

  1. 网站采集应遵守中国新闻网的robots.txt规定
  2. 频繁采集可能会被限制IP,建议合理设置缓存时间
  3. 实际应用中应考虑添加错误处理和日志记录
  4. 网站结构变化时需要相应调整解析逻辑

这个实现方案提供了完整的采集、存储、展示和分页功能,同时支持伪静态URL,适合在IIS和宝塔面板环境中部署。 更多详情:baijiahao.baidu.com/s?id=183050…