Python3.6(Mac OS X El Capitan)游戏搜索定时脚本问题及优化咨询
解决Mac平台游戏搜索脚本的问题:交互式输入与高效方案优化
我看你现在的脚本是靠调用Safari+模拟按键来做搜索,这种方式确实很容易失效——毕竟浏览器加载速度不稳定,而且焦点一不小心就跑偏了,根本没法保证每次都能准确输入关键词。结合你的需求(定时搜索游戏、存CSV、图表排序、价格筛选),我给你整理一套更靠谱的方案:
一、Mac平台友好的交互式输入模块
推荐两个比原生input()体验好太多的库,适配Mac命令行环境:
- questionary:专门做交互式命令行输入,支持文本输入、单选多选、输入验证,用起来很顺畅
安装命令:pip install questionary(Python3.6若遇版本问题,可指定兼容版:pip install questionary==1.10.0)
示例代码:import questionary # 获取游戏名称输入 game_name = questionary.text("请输入要搜索的游戏名称:").ask() # 选择定时搜索间隔 search_interval = questionary.select( "选择定时搜索间隔(小时):", choices=["1", "3", "6", "12"] ).ask() - rich:不仅能做输入,还能美化输出(彩色文本、进度条等),适合后续展示搜索结果
安装命令:pip install rich
二、替换不稳定的浏览器模拟:直接获取搜索结果
放弃webbrowser+osascript的方案,改用HTTP请求直接获取结构化结果,效率和稳定性提升N倍:
方案1:用requests+BeautifulSoup爬取谷歌搜索结果(免费)
需要先安装依赖:pip install requests beautifulsoup4
核心思路:构造谷歌搜索URL,请求后解析页面提取游戏名称、价格等信息(注意:需定期调整解析规则适配谷歌页面更新)
示例代码片段:
import requests from bs4 import BeautifulSoup import re def search_game(game_name): search_url = f"https://www.google.com/search?q={game_name}+游戏+价格" # 模拟Mac浏览器请求头,避免被反爬 headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } try: response = requests.get(search_url, headers=headers, timeout=10) response.raise_for_status() soup = BeautifulSoup(response.text, "html.parser") results = [] # 提取搜索结果卡片中的信息 for item in soup.select(".g"): title = item.select_one("h3").get_text().strip() if item.select_one("h3") else "无标题" # 匹配价格格式(如"99元"、"129.9元") price_match = re.search(r"(\d+\.?\d*)元", item.get_text()) price = price_match.group() if price_match else "无价格" results.append({"游戏名称": title, "价格": price}) return results except Exception as e: print(f"搜索出错:{str(e)}") return []
方案2:用SerpAPI(付费但无需处理反爬)
如果不想折腾页面解析和反爬规则,SerpAPI提供了谷歌搜索的结构化API接口,直接返回JSON格式结果,适合长期稳定使用。
三、整合定时任务、CSV存储、图表化与价格筛选
1. 定时任务:用schedule模块
安装命令:pip install schedule
示例代码:
import schedule import time def job(game_name): game_results = search_game(game_name) save_to_csv(game_results, game_name) print(f"[{datetime.now().strftime('%H:%M:%S')}] 本次搜索已完成并保存") # 比如每6小时执行一次 schedule.every(6).hours.do(job, game_name=game_name) # 持续运行定时任务 while True: schedule.run_pending() time.sleep(60)
2. 保存结果到CSV
import csv from datetime import datetime import os def save_to_csv(results, game_name): filename = f"{game_name}_搜索结果.csv" file_exists = os.path.isfile(filename) # 用utf-8-sig编码避免Excel乱码 with open(filename, "a", newline="", encoding="utf-8-sig") as f: writer = csv.DictWriter(f, fieldnames=["游戏名称", "价格", "搜索时间"]) # 首次写入表头 if not file_exists: writer.writeheader() current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") for result in results: result["搜索时间"] = current_time writer.writerow(result) print(f"已将{len(results)}条结果保存到{filename}")
3. 图表化排序与价格筛选
用pandas+matplotlib快速实现数据处理和可视化:
安装命令:pip install pandas matplotlib
示例代码:
import pandas as pd import matplotlib.pyplot as plt def analyze_game_data(csv_file): if not os.path.isfile(csv_file): print("数据文件不存在,请先执行搜索任务!") return df = pd.read_csv(csv_file) # 提取价格数值用于筛选和排序 df["价格数值"] = df["价格"].str.extract(r"(\d+\.?\d*)").astype(float) # 交互式设置价格筛选范围 min_price = questionary.text("请输入最低价格(元,留空不限制):").ask() max_price = questionary.text("请输入最高价格(元,留空不限制):").ask() filtered_df = df.copy() if min_price: filtered_df = filtered_df[filtered_df["价格数值"] >= float(min_price)] if max_price: filtered_df = filtered_df[filtered_df["价格数值"] <= float(max_price)] if filtered_df.empty: print("没有符合条件的结果!") return # 按价格升序排序 sorted_df = filtered_df.sort_values("价格数值") # 生成柱状图 plt.figure(figsize=(12,7)) plt.bar(sorted_df["游戏名称"], sorted_df["价格数值"], color="#4CAF50") plt.xticks(rotation=45, ha="right") plt.title(f"游戏价格排序({min_price if min_price else '不限'} - {max_price if max_price else '不限'}元)") plt.xlabel("游戏名称") plt.ylabel("价格(元)") plt.tight_layout() plt.show()
四、完整整合脚本
把上面的模块组合起来,就是一个支持交互式输入、定时搜索、数据存储和分析的完整工具:
import questionary import requests from bs4 import BeautifulSoup import schedule import time import csv from datetime import datetime import os import pandas as pd import matplotlib.pyplot as plt import re def get_user_input(): game_name = questionary.text("请输入要搜索的游戏名称:").ask() interval = questionary.select( "选择定时搜索间隔(小时):", choices=["1", "3", "6", "12"] ).ask() return game_name, int(interval) def search_game(game_name): search_url = f"https://www.google.com/search?q={game_name}+游戏+价格" headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } try: response = requests.get(search_url, headers=headers, timeout=10) response.raise_for_status() soup = BeautifulSoup(response.text, "html.parser") results = [] for item in soup.select(".g"): title = item.select_one("h3").get_text().strip() if item.select_one("h3") else "无标题" price_match = re.search(r"(\d+\.?\d*)元", item.get_text()) price = price_match.group() if price_match else "无价格" results.append({"游戏名称": title, "价格": price}) return results except Exception as e: print(f"搜索出错:{str(e)}") return [] def save_to_csv(results, game_name): filename = f"{game_name}_搜索结果.csv" file_exists = os.path.isfile(filename) with open(filename, "a", newline="", encoding="utf-8-sig") as f: writer = csv.DictWriter(f, fieldnames=["游戏名称", "价格", "搜索时间"]) if not file_exists: writer.writeheader() current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") for result in results: result["搜索时间"] = current_time writer.writerow(result) print(f"已将{len(results)}条结果保存到{filename}") def analyze_game_data(csv_file): if not os.path.isfile(csv_file): print("数据文件不存在,请先执行搜索任务!") return df = pd.read_csv(csv_file) df["价格数值"] = df["价格"].str.extract(r"(\d+\.?\d*)").astype(float) min_price = questionary.text("请输入最低价格(元,留空不限制):").ask() max_price = questionary.text("请输入最高价格(元,留空不限制):").ask() filtered_df = df.copy() if min_price: filtered_df = filtered_df[filtered_df["价格数值"] >= float(min_price)] if max_price: filtered_df = filtered_df[filtered_df["价格数值"] <= float(max_price)] if filtered_df.empty: print("没有符合条件的结果!") return sorted_df = filtered_df.sort_values("价格数值") plt.figure(figsize=(12,7)) plt.bar(sorted_df["游戏名称"], sorted_df["价格数值"], color="#4CAF50") plt.xticks(rotation=45, ha="right") plt.title(f"游戏价格排序({min_price if min_price else '不限'} - {max_price if max_price else '不限'}元)") plt.xlabel("游戏名称") plt.ylabel("价格(元)") plt.tight_layout() plt.show() def main(): game_name, interval = get_user_input() # 首次执行搜索 initial_results = search_game(game_name) save_to_csv(initial_results, game_name) # 设置定时任务 schedule.every(interval).hours.do(lambda: save_to_csv(search_game(game_name), game_name)) print(f"定时任务已启动,每{interval}小时搜索一次{game_name}!") print("输入'analyze'可以分析已保存的搜索结果,输入'exit'退出程序") # 主循环处理命令和定时任务 while True: schedule.run_pending() user_cmd = input("> ").strip().lower() if user_cmd == "exit": print("程序已退出") break elif user_cmd == "analyze": analyze_game_data(f"{game_name}_搜索结果.csv") else: print("无效命令,请输入'analyze'或'exit'") if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者Ruben Mulet
相关产品推荐
相关产品推荐

