如何用Python爬取iMessage?数据库路径错误问题求助
问题
我正在做一个远程控制Mac的项目,需要通过iPhone的Shortcuts功能向Mac发送指令,Mac用Python自动接收。要求用Shortcuts的「请求输入」动作简化操作,所以得用iMessage或iCloud邮件实现,避免在第三方应用手动输入(比如Discord的发送操作体验差)。
尝试用iMessage_reader库读取iMessage,但遇到以下问题:
- 找不到官方文档里的
chat.db,只找到chatRenderMetaData.db - 用这个文件运行脚本时报错:
Error reading the database: no such table: message - 爬取iCloud邮件的方案也不可行,没找到可用的自动爬取脚本
解决思路
1. 修正iMessage数据库路径
Mac上iMessage的真实数据库路径是固定的,你之前找错了文件:
- 正确路径:
~/Library/Messages/chat.db(~/代表你的用户目录) - 注意:这个目录默认隐藏,按
Command+Shift+.可以显示,或者直接用终端访问 - 权限配置:需要给Python脚本/IDE开启「完全磁盘访问」权限(系统设置-隐私与安全性-完全磁盘访问)
修改后的可运行代码:
from imessage_reader import fetch_data # 替换成你的用户名 DB_PATH = '/Users/你的用户名/Library/Messages/chat.db' fd = fetch_data.FetchData(DB_PATH) # 获取所有消息,可过滤最新的N条 my_data = fd.get_messages() latest_messages = my_data[-5:] print(latest_messages)
2. 改用HTTP直连方案(更可靠,无需爬取)
直接用Shortcuts发HTTP请求给Mac上的Python服务,比爬取数据库更高效:
第一步:Mac上运行Python HTTP服务
from flask import Flask, request import subprocess app = Flask(__name__) @app.route('/remote-command', methods=['POST']) def handle_command(): command = request.form.get('cmd') print(f"收到指令:{command}") # 这里可以添加执行指令的逻辑,比如运行系统命令 result = subprocess.run(command, shell=True, capture_output=True, text=True) return f"执行结果:\n{result.stdout}\n{result.stderr}" if __name__ == '__main__': # 0.0.0.0允许局域网设备访问,端口可自定义 app.run(host='0.0.0.0', port=5000, debug=True)
第二步:iPhone Shortcuts配置
- 添加「请求输入」动作,让用户输入控制指令
- 添加「发送HTTP请求」动作:
- 方法选
POST - URL填
http://你的Mac局域网IP:5000/remote-command(Mac局域网IP可在「系统设置-网络」里查看) - 请求体选「表单」,添加键
cmd,值选「请求输入」的结果
- 方法选
3. 备选:用Python标准库读取iCloud邮件
如果一定要用邮件方案,用Python自带的imaplib连接iCloud邮件服务器:
import imaplib import email from email.header import decode_header # iCloud IMAP配置 IMAP_SERVER = 'imap.mail.me.com' IMAP_PORT = 993 USERNAME = '你的iCloud邮箱@icloud.com' # 必须用iCloud专用密码(Apple ID设置-安全-专用密码生成) PASSWORD = '你的iCloud专用密码' def fetch_new_emails(): mail = imaplib.IMAP4_SSL(IMAP_SERVER, IMAP_PORT) mail.login(USERNAME, PASSWORD) mail.select('INBOX') # 搜索未读邮件 status, msg_ids = mail.search(None, 'UNSEEN') for msg_id in msg_ids[0].split(): status, msg_data = mail.fetch(msg_id, '(RFC822)') msg = email.message_from_bytes(msg_data[0][1]) # 解析主题 subject, encode = decode_header(msg['Subject'])[0] if isinstance(subject, bytes): subject = subject.decode(encode) print(f"新邮件主题:{subject}") # 解析内容 if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == 'text/plain': body = part.get_payload(decode=True).decode() print(f"邮件内容:{body}") else: body = msg.get_payload(decode=True).decode() print(f"邮件内容:{body}") mail.close() mail.logout() fetch_new_emails()
内容的提问来源于stack exchange,提问作者NurseNeko
相关产品推荐
相关产品推荐

