Python腳本每天爬取微博熱搜-升級版

在這里插入圖片描述

主要優化內容:

定時任務調整:

將定時任務從每小時改為每10分鐘執行一次

調整了請求延遲時間,從1-3秒減少到0.5-1.5秒

縮短了請求超時時間,從10秒減少到8秒

性能優化:

移除了廣告數據的處理,減少不必要的處理

優化了數據結構,減少內存占用

添加了數據清理功能,自動刪除7天前的數據

用戶體驗改進:

HTML頁面添加了自動刷新功能(每5分鐘)

添加了手動刷新按鈕

增加了統計信息顯示(總熱搜數、時間段數等)

優化了移動端顯示效果

代碼健壯性:

添加了異常處理

優化了數據存儲和讀取邏輯

添加了數據清理機制,防止數據無限增長

界面美化:

添加了網站圖標

優化了顏色方案和布局

改進了響應式設計,適配移動設備

這個優化版本每10分鐘獲取一次微博熱搜,并將新數據追加到當天的HTML文件中,同時保持了去重功能。頁面也會每5分鐘自動刷新,確保用戶看到最新數據。

import requests
from bs4 import BeautifulSoup
import time
import os
from datetime import datetime, timedelta
import schedule
import random
import json
import redef fetch_weibo_hot():"""使用API接口獲取微博熱搜數據(避免HTML結構變化問題)"""api_url = "https://weibo.com/ajax/side/hotSearch"headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36','Referer': 'https://weibo.com/','Cookie': 'XSRF-TOKEN=RKnNBEaQBrp=='  # 替換為你的實際Cookie}try:# 添加隨機延遲避免被封time.sleep(random.uniform(0.5, 1.5))response = requests.get(api_url, headers=headers, timeout=8)response.raise_for_status()# 解析JSON數據data = response.json()# 提取熱搜數據hot_items = []for group in data['data']['realtime']:# 普通熱搜項if 'word' in group:item = {'rank': group.get('rank', ''),'title': group['word'],'hot': group.get('num', '0'),'link': f"https://s.weibo.com/weibo?q={group['word']}",'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),'source': 'weibo'}hot_items.append(item)# 只保留前50條熱搜return hot_items[:50]except Exception as e:print(f"🚨 獲取熱搜數據失敗: {e}")return []def load_existing_hot_searches(date_str):"""加載當天已存在的熱搜數據"""json_file = os.path.join("weibo_hot", date_str, "hot_searches.json")if os.path.exists(json_file):try:with open(json_file, 'r', encoding='utf-8') as f:return json.load(f)except Exception as e:print(f"讀取已有熱搜數據失敗: {e}")return []return []def save_hot_data_json(hot_data, date_str):"""保存熱搜數據到JSON文件"""daily_dir = os.path.join("weibo_hot", date_str)if not os.path.exists(daily_dir):os.makedirs(daily_dir)json_file = os.path.join(daily_dir, "hot_searches.json")# 加載已有數據existing_data = load_existing_hot_searches(date_str)existing_titles = {item['title'] for item in existing_data}# 過濾掉已存在的熱搜new_data = [item for item in hot_data if item['title'] not in existing_titles]# 合并數據all_data = existing_data + new_data# 保存到JSON文件with open(json_file, 'w', encoding='utf-8') as f:json.dump(all_data, f, ensure_ascii=False, indent=2)return all_data, len(new_data)def generate_html(hot_data, date_str):"""生成HTML文件"""if not hot_data:return "<html><body><h1>未獲取到熱搜數據</h1></body></html>"# 按時間分組熱搜time_groups = {}for item in hot_data:time_key = item['timestamp'][:13]  # 只取到小時if time_key not in time_groups:time_groups[time_key] = []time_groups[time_key].append(item)# 按時間倒序排列sorted_times = sorted(time_groups.keys(), reverse=True)# 統計信息total_count = len(hot_data)time_count = len(time_groups)html_content = f"""<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>微博熱搜榜 {date_str}</title><link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔥</text></svg>"><style>* {{box-sizing: border-box;margin: 0;padding: 0;}}body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", sans-serif; background-color: #f5f8fa;color: #14171a;line-height: 1.5;padding: 20px;max-width: 1200px;margin: 0 auto;}}.container {{background: white;border-radius: 16px;box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);overflow: hidden;margin-bottom: 30px;}}.header {{ background: linear-gradient(135deg, #ff6b6b, #5e72eb);color: white;padding: 25px 30px;position: relative;}}.title {{font-size: 28px;font-weight: 700;margin-bottom: 5px;}}.subtitle {{font-size: 16px;opacity: 0.9;}}.stats {{margin-top: 15px;display: flex;gap: 15px;flex-wrap: wrap;}}.stat-item {{background: rgba(255, 255, 255, 0.2);padding: 8px 15px;border-radius: 20px;font-size: 14px;}}.update-time {{position: absolute;top: 25px;right: 30px;background: rgba(0, 0, 0, 0.15);padding: 5px 12px;border-radius: 20px;font-size: 14px;}}.time-section {{margin: 20px 0;padding: 15px;background: #f8f9fa;border-radius: 8px;}}.time-header {{font-size: 18px;font-weight: 600;margin-bottom: 15px;color: #495057;display: flex;align-items: center;justify-content: space-between;}}.time-info {{display: flex;align-items: center;}}.time-count {{background: #e9ecef;padding: 2px 8px;border-radius: 10px;font-size: 14px;margin-left: 10px;}}.hot-list {{padding: 0;}}.hot-item {{display: flex;align-items: center;padding: 16px 20px;border-bottom: 1px solid #e6ecf0;transition: background 0.2s;}}.hot-item:hover {{background-color: #f7f9fa;}}.rank {{width: 36px;height: 36px;line-height: 36px;text-align: center;font-weight: bold;font-size: 16px;background: #f0f2f5;border-radius: 8px;margin-right: 15px;flex-shrink: 0;}}.top1 {{ background: linear-gradient(135deg, #ff9a9e, #fad0c4);color: #d63031;}}.top2 {{ background: linear-gradient(135deg, #a1c4fd, #c2e9fb);color: #0984e3;}}.top3 {{ background: linear-gradient(135deg, #ffecd2, #fcb69f);color: #e17055;}}.hot-content {{flex: 1;min-width: 0;}}.hot-title {{font-size: 17px;font-weight: 500;margin-bottom: 6px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;}}.hot-stats {{display: flex;align-items: center;color: #657786;font-size: 14px;gap: 15px;flex-wrap: wrap;}}.hot-value {{color: #ff6b6b;font-weight: 700;}}.hot-time {{font-size: 12px;color: #868e96;}}.link {{color: #1da1f2;text-decoration: none;transition: color 0.2s;}}.link:hover {{color: #0d8bda;text-decoration: underline;}}.footer {{text-align: center;padding: 20px;color: #657786;font-size: 13px;border-top: 1px solid #e6ecf0;}}.no-data {{text-align: center;padding: 40px;color: #657786;}}.collapse-btn {{background: #6c757d;color: white;border: none;padding: 5px 10px;border-radius: 4px;cursor: pointer;font-size: 12px;}}.collapse-btn:hover {{background: #5a6268;}}.collapsed .hot-list {{display: none;}}.auto-refresh {{text-align: center;margin: 20px 0;}}.refresh-btn {{background: #28a745;color: white;border: none;padding: 10px 20px;border-radius: 5px;cursor: pointer;font-size: 14px;}}.refresh-btn:hover {{background: #218838;}}@media (max-width: 768px) {{body {{padding: 10px;}}.header {{padding: 20px 15px;}}.title {{font-size: 22px;}}.update-time {{position: static;margin-top: 10px;}}.hot-item {{padding: 14px 15px;}}.hot-title {{font-size: 16px;}}.hot-stats {{flex-direction: column;align-items: flex-start;gap: 5px;}}}}</style></head><body><div class="container"><div class="header"><h1 class="title">微博熱搜榜</h1><div class="subtitle">全天熱點匯總 · 每10分鐘更新</div><div class="stats"><div class="stat-item">📊 總熱搜數: {total_count}</div><div class="stat-item">🕒 時間段: {time_count}</div><div class="stat-item">? 更新頻率: 每10分鐘</div></div><div class="update-time">最后更新: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</div></div>"""# 添加時間分組的熱搜內容for time_key in sorted_times:time_display = f"{time_key}:00"time_data = time_groups[time_key]html_content += f"""<div class="time-section"><div class="time-header"><div class="time-info">🕒 {time_display}<span class="time-count">{len(time_data)} 條熱搜</span></div><button class="collapse-btn" onclick="this.parentElement.parentElement.classList.toggle('collapsed')">折疊/展開</button></div><div class="hot-list">"""for item in time_data:rank_class = ""if item['rank'] == 1:rank_class = "top1"elif item['rank'] == 2:rank_class = "top2"elif item['rank'] == 3:rank_class = "top3"hot_value = f"<span class='hot-value'>🔥 {item['hot']}</span>" if item['hot'] else ""html_content += f"""<div class="hot-item"><div class="rank {rank_class}">{item['rank']}</div><div class="hot-content"><div class="hot-title"><a href="{item['link']}" class="link" target="_blank">{item['title']}</a></div><div class="hot-stats">{hot_value}<span class="hot-time">📅 {item['timestamp']}</span></div></div></div>"""html_content += """</div></div>"""if not hot_data:html_content += """<div class="no-data"><h3>暫無熱搜數據</h3><p>請檢查網絡連接或稍后再試</p></div>"""html_content += f"""<div class="auto-refresh"><button class="refresh-btn" onclick="location.reload()">🔄 刷新頁面</button><p>頁面每10分鐘自動更新,也可手動刷新</p></div><div class="footer">數據來源: 微博熱搜 ? 每10分鐘自動更新 ? 最后更新: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} ? 僅供學習參考</div></div><script>// 默認折疊所有時間段的搜索結果document.addEventListener('DOMContentLoaded', function() {{var sections = document.querySelectorAll('.time-section');sections.forEach(function(section, index) {{if (index > 0) {{ // 保持最新時間段展開section.classList.add('collapsed');}}}});// 設置自動刷新(每5分鐘)setTimeout(function() {{location.reload();}}, 5 * 60 * 1000);}});</script></body></html>"""return html_contentdef cleanup_old_data():"""清理7天前的數據"""try:now = datetime.now()cutoff_date = (now - timedelta(days=7)).strftime("%Y-%m-%d")weibo_hot_dir = "weibo_hot"if os.path.exists(weibo_hot_dir):for date_dir in os.listdir(weibo_hot_dir):if date_dir < cutoff_date:dir_path = os.path.join(weibo_hot_dir, date_dir)import shutilshutil.rmtree(dir_path)print(f"🗑? 已清理過期數據: {date_dir}")except Exception as e:print(f"清理舊數據時出錯: {e}")def save_hot_data():"""保存熱搜數據"""try:# 創建存儲目錄if not os.path.exists("weibo_hot"):os.makedirs("weibo_hot")# 獲取當前日期now = datetime.now()date_str = now.strftime("%Y-%m-%d")print(f"🕒 開始獲取 {now.strftime('%Y-%m-%d %H:%M:%S')} 的熱搜數據...")hot_data = fetch_weibo_hot()if hot_data:print(f"? 成功獲取 {len(hot_data)} 條熱搜數據")# 保存到JSON文件并獲取所有數據all_data, new_count = save_hot_data_json(hot_data, date_str)print(f"📊 已有 {len(all_data)} 條熱搜,新增 {new_count} 條")# 生成HTML內容html_content = generate_html(all_data, date_str)# 保存HTML文件html_file = os.path.join("weibo_hot", date_str, "index.html")with open(html_file, "w", encoding="utf-8") as f:f.write(html_content)print(f"💾 已保存到: {html_file}")# 每周清理一次舊數據#if now.weekday() == 0 and now.hour == 0 and now.minute < 10:  # 每周一凌晨#    cleanup_old_data()else:print("?? 未獲取到熱搜數據,跳過保存")except Exception as e:print(f"? 保存數據時出錯: {e}")def job():"""定時任務"""print("\n" + "="*60)print(f"? 執行定時任務: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")save_hot_data()print("="*60 + "\n")if __name__ == "__main__":print("🔥 微博熱搜爬蟲已啟動 🔥")print("? 首次執行將立即運行,之后每10分鐘執行一次")print("💡 提示: 請確保已更新有效的Cookie")print("="*60)# 立即執行一次job()# 設置定時任務(每10分鐘執行一次)schedule.every(10).minutes.do(job)# 每天凌晨清理一次舊數據schedule.every().day.at("00:00").do(cleanup_old_data)print("? 程序運行中,按Ctrl+C退出...")try:# 保持程序運行while True:schedule.run_pending()time.sleep(30)  # 每30秒檢查一次except KeyboardInterrupt:print("\n👋 程序已手動停止")

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96234.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96234.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96234.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

win11兼容運行遠古游戲

游戲<遠古戰爭>屬于win7時代的游戲&#xff0c;在win11系統中運行&#xff0c;當鼠標移動立馬卡住 解決方案&#xff1a; 最優&#xff1a;采用wmware虛擬機安裝win7系統 最簡單&#xff1a;使用 DxWnd 模擬老游戲運行環境 DxWnd官網下載 附錄&#xff1a;游戲下載網址…

Docker小游戲 | 使用Docker部署人生重開模擬器

Docker小游戲 | 使用Docker部署人生重開模擬器 前言 項目介紹 項目簡介 項目預覽 二、系統要求 環境要求 環境檢查 Docker版本檢查 檢查操作系統版本 三、部署人生重開模擬器小游戲 下載鏡像 創建容器 檢查容器狀態 檢查服務端口 安全設置 四、訪問人生重開模擬器 五、總結 前言…

從依賴到自研:一個客服系統NLP能力的躍遷之路

前言&#xff1a;七年磨一劍的技術突圍2015年在某平臺上線初期&#xff0c;智能客服系統即采用行業通用的第三方NLP解決方案。在隨后的八年發展歷程中&#xff0c;系統雖歷經三次重大版本迭代&#xff0c;但始終未能突破核心語義識別能力的外部依賴。這種依賴帶來了三重困境&am…

50.Seata-AT模式

AT模式同樣是分階段提交的事務模型。優勢是彌補了XA模型中資源鎖定周期過長的缺陷。 沒有代碼入侵,框架自動完成快照生成、回滾和提交。實現非常簡單。 兩階段之間屬于軟狀態,屬于最終一致。 AT模式 階段一RM的工作: 1.注冊分支事務 2.記錄undo-log (數據快照),記錄更…

Android13車機系統自定義系統欄顯示策略之狀態欄下拉異常

1、引言 文章《Android13車機系統實現系統欄自定義顯示策略》介紹了車機系統上自定義系統欄(狀態欄、底部欄)顯示策略,文中末尾提到了一個遺留問題: 由于狀態欄區域支持點擊或下拉顯示出快捷設置&消息通知欄,三方應用顯示時,從狀態欄中間區域而不從頂部邊緣下拉,底…

【Langchain系列五】DbGPT——Langchain+PG構建結構化數據庫智能問答系統

Langchain二次開發專欄 【Langchain系列一】常用大模型的key獲取與連接方式 【Langchain系列二】LangChain+Prompt +LLM智能問答入門 【Langchain系列三】GraphGPT——LangChain+NebulaGraph+llm構建智能圖數據庫問答系統 【Langchain系列四】RAG——基于非結構化數據庫的智能問…

生信分析自學攻略 | R語言數據類型和數據結構

在前面兩篇文章中&#xff0c;我們已經成功搭建了R和RStudio這一強大的生信分析平臺。然而&#xff0c;工具再好&#xff0c;若不懂得如何“放置”和“理解”你的數據&#xff0c;一切都將寸步難行。今天&#xff0c;我們將學習R語言最重要的部分——數據類型&#xff08;Data …

Python工程與模塊命名規范:構建可維護的大型項目架構

目錄 Python工程與模塊命名規范&#xff1a;構建可維護的大型項目架構 引言&#xff1a;命名的重要性 在軟件開發中&#xff0c;命名可能是最容易被忽視但卻是最重要的實踐之一。根據2023年對Python開源項目的分析&#xff0c;超過35%的維護問題與糟糕的命名約定直接相關。一個…

Props 與 State 類型定義

下面&#xff0c;我們來系統的梳理關于 TypeScript 集成&#xff1a;Props 與 State 類型定義 的基本知識點&#xff1a;一、TypeScript 在 React 中的核心價值 TypeScript 為 React 開發提供了強大的類型安全保證&#xff0c;特別是在定義組件 Props 和 State 時&#xff1a; …

[1Prompt1Story] 注意力機制增強 IPCA | 去噪神經網絡 UNet | U型架構分步去噪

第五章&#xff1a;注意力機制增強&#xff08;IPCA&#xff09; 歡迎回到1Prompt1Story&#x1f43b;??? 在第四章中&#xff0c;我們掌握了**語義向量重加權&#xff08;SVR&#xff09;**技術&#xff0c;通過語義向量調節實現核心要素強化。 但當場景從"雪地嬉戲…

【P7071 [CSP-J2020] 優秀的拆分 - 洛谷 https://www.luogu.com.cn/problem/P7071】

題目 P7071 [CSP-J2020] 優秀的拆分 - 洛谷 https://www.luogu.com.cn/problem/P7071 代碼 #include <bits/stdc.h> using namespace std; const int N1e71; int d; vector<int> v; bool k[N]; bool fen(int x){if(x0)return 1;//能拆分完 for(int ix;i>x/…

從ioutil到os:Golang在線客服聊天系統文件讀取的遷移實踐

了解更多&#xff0c;搜索"程序員老狼"作為一名Golang開發者&#xff0c;我最近在維護一個客服系統時遇到了一個看似簡單卻值得深思的問題&#xff1a;如何將項目中遺留的ioutil.ReadFile調用遷移到現代的os.ReadFile。這看似只是一個簡單的函數替換&#xff0c;但背…

Python UI自動化測試Web frame及多窗口切換

這篇文章主要為大家介紹了Python UI自動化測試Web frame及多窗口切換&#xff0c;有需要的朋友可以借鑒參考下&#xff0c;希望能夠有所幫助&#xff0c;祝大家多多進步&#xff0c;早日升職加薪 一、什么是frame&frame切換&#xff1f; frame&#xff1a;HTML頁面中的一…

工業相機基本知識解讀:像元、幀率、數據接口等

工業相機&#xff08;Industrial Camera&#xff09;是一種專門為工業自動化和機器視覺應用而設計的成像設備&#xff0c;它不同于消費類相機&#xff08;如手機、單反&#xff09;&#xff0c;主要追求的是成像穩定性、長時間可靠性、實時性和精確性。它通常與鏡頭、光源、圖像…

RTC之神奇小鬧鐘

&#x1f3aa; RTC 是什么&#xff1f;—— 電子設備的“迷你生物鐘”想象一下&#xff1a;你晚上睡覺時&#xff0c;手機關機了。但當你第二天開機&#xff0c;它居然知道現在幾點&#xff01;這就是 RTC&#xff08;Real-Time Clock&#xff0c;實時時鐘&#xff09; 的功勞&…

判斷IP是否屬于某個網段

判斷IP是否屬于某個網段判斷一個IP是否是否屬于某個CIDR網段&#xff0c;核心是比較IP與網段的網絡位是否一致&#xff0c;步驟如下&#xff1a; 一、明確CIDR網段的兩個關鍵信息 假設要判斷的IP是 IPx&#xff0c;目標網段是 CIDR 網段地址/n&#xff08;例如 192.168.1.0/24…

Python day50

浙大疏錦行 python day50. 在預訓練模型&#xff08;resnet18&#xff09;中添加cbam注意力機制&#xff0c;需要修改模型的架構&#xff0c;同時應該考慮插入的cbam注意力機制模塊的位置&#xff1b; import torch import torch.nn as nn from torchvision import models# 自…

VPS海外節點性能監控全攻略:從基礎配置到高級優化

在全球化業務部署中&#xff0c;VPS海外節點的穩定運行直接影響用戶體驗。本文將深入解析如何構建高效的性能監控體系&#xff0c;涵蓋網絡延遲檢測、資源閾值設置、告警機制優化等核心環節&#xff0c;幫助運維人員實現跨國服務器的可視化管控。 VPS海外節點性能監控全攻略&am…

C語言初學者筆記【結構體】

文章目錄一、結構體的使用1. 結構體聲明2. 變量創建與初始化3. 特殊聲明與陷阱二、內存對齊1. 規則&#xff1a;2. 示例分析&#xff1a;3. 修改默認對齊數&#xff1a;三、結構體傳參四、結構體實現位段1. 定義2. 內存分配3. 應用場景4. 跨平臺問題&#xff1a;5. 注意事項&am…

基于XGBoost算法的數據回歸預測 極限梯度提升算法 XGBoost

一、作品詳細簡介 1.1附件文件夾程序代碼截圖 全部完整源代碼&#xff0c;請在個人首頁置頂文章查看&#xff1a; 學行庫小秘_CSDN博客?編輯https://blog.csdn.net/weixin_47760707?spm1000.2115.3001.5343 1.2各文件夾說明 1.2.1 main.m主函數文件 該MATLAB 代碼實現了…