背景
这篇文章记录一个“小工具脚本”的实现思路:从微信公众号后台(mp.weixin.qq.com)抓取用户会话里的表情消息(type=47),把表情文件下载到服务器,再(可选)导入到 WordPress 媒体库,方便后续在站点里整理与展示。
整体流程(从输入到产出)
准备请求凭证(Cookie + Token)。
获取所有会话用户列表(脚本里对应 get_all_users())。
逐个用户拉取最近消息(脚本里对应 get_user_messages(fakeid))。
筛选出表情消息(常见为 type=47)。
按 msgid 调用下载接口,把表情文件保存到目录(脚本里对应 download_emoji(msgid))。
(可选)通过 docker exec 在 WordPress 容器里运行 wp media import 导入媒体库(脚本里对应 import_to_wordpress(path))。
最终你会得到:一个本地文件夹里的表情文件 +(可选)WordPress 媒体库里的附件记录。
接口与关键点(脱敏说明)
脚本通常会用到以下页面/接口(URL 结构示意,不含任何真实参数值):
消息列表:https://mp.weixin.qq.com/cgi-bin/message?t=message/list&count=50&day=7&token=…
单聊页(用于获取会话/用户信息):https://mp.weixin.qq.com/cgi-bin/singlesendpage?t=message/send&action=…
文件下载:https://mp.weixin.qq.com/cgi-bin/downloadfile?msgid=…
重点在于:Cookie/Token 只是“门票”,真正的业务逻辑是“列用户 → 拉消息 → 过滤 type=47 → 按 msgid 下载文件”。
import os
import json
import time
import subprocess
import requests
from datetime import datetime
# ============ 配置 ============
COOKIE = ''
TOKEN = ''
SAVE_DIR = '/opt/1panel/apps/wordpress/wordpress/data/wechat-media/emoji'
WP_CONTAINER = '1Panel-wordpress-4JAd'
# ==============================
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Cookie': COOKIE,
'Referer': 'https://mp.weixin.qq.com/',
}
def get_all_users():
url = f'https://mp.weixin.qq.com/cgi-bin/message?t=message/list&count=50&day=7&token={TOKEN}&lang=zh_CN&f=json'
try:
resp = requests.get(url, headers=HEADERS, timeout=30)
data = resp.json()
if data.get('base_resp', {}).get('ret') != 0:
return []
users = []
for item in data.get('item', []):
msg = item.get('msg', {})
msg_items_str = msg.get('msg_items', '{}')
msg_items = json.loads(msg_items_str) if isinstance(msg_items_str, str) else msg_items_str
for m in msg_items.get('msg_item', []):
fakeid = m.get('fakeid')
nick = m.get('nick_name', 'unknown')
if fakeid and fakeid not in [u['fakeid'] for u in users]:
users.append({'fakeid': fakeid, 'nick_name': nick})
return users
except:
return []
def get_user_messages(fakeid):
url = f'https://mp.weixin.qq.com/cgi-bin/singlesendpage?t=message/send&action=index&tofakeid={fakeid}&token={TOKEN}&lang=zh_CN&f=json'
try:
resp = requests.get(url, headers=HEADERS, timeout=30)
data = resp.json()
if data.get('base_resp', {}).get('ret') != 0:
return []
return data.get('page_info', {}).get('msg_items', {}).get('msg_item', [])
except:
return []
def import_to_wordpress(filepath):
"""导入文件到 WordPress 媒体库并分配到 Unreviewed 文件夹"""
# 容器内路径
wp_path = filepath.replace('/opt/1panel/apps/wordpress/wordpress/data', '/var/www/html')
cmd = f'docker exec {WP_CONTAINER} wp media import {wp_path} --porcelain --allow-root 2>&1'
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
# --porcelain 返回附件 ID
attachment_id = result.stdout.strip()
if attachment_id.isdigit():
print(f' -> 已导入媒体库 (ID: {attachment_id})')
# 设置文件夹为 Unreviewed (使用 slug)
set_folder_cmd = f'docker exec {WP_CONTAINER} wp post term set {attachment_id} media_folder unreviewed-1770143382-1 --allow-root 2>&1'
subprocess.run(set_folder_cmd, shell=True, capture_output=True, text=True, timeout=10)
print(f' -> 已分配到 Unreviewed 文件夹')
return True
else:
print(f' -> 导入失败: {result.stdout[:100]}')
except Exception as e:
print(f' -> 导入错误: {e}')
return False
def download_emoji(msg_id):
url = f'https://mp.weixin.qq.com/cgi-bin/downloadfile?msgid={msg_id}&token={TOKEN}&lang=zh_CN'
try:
resp = requests.get(url, headers=HEADERS, timeout=60)
ct = resp.headers.get('Content-Type', '')
if 'image' not in ct and 'gif' not in ct:
return None
ext = 'gif'
if 'png' in ct: ext = 'png'
elif 'jpeg' in ct or 'jpg' in ct: ext = 'jpg'
os.makedirs(SAVE_DIR, exist_ok=True)
filename = f'{msg_id}.{ext}'
filepath = os.path.join(SAVE_DIR, filename)
if os.path.exists(filepath):
print(f' [{msg_id}] 已存在,跳过')
return None
with open(filepath, 'wb') as f:
f.write(resp.content)
size_kb = len(resp.content) / 1024
print(f' [{msg_id}] 已下载: {filename} ({size_kb:.1f}KB)')
# 导入到 WordPress
import_to_wordpress(filepath)
return filepath
except Exception as e:
print(f' [{msg_id}] 失败: {e}')
return None
def main():
print(f'=== 表情包下载 {datetime.now().strftime("%H:%M:%S")} ===')
users = get_all_users()
for user in users:
messages = get_user_messages(user['fakeid'])
emoji_msgs = [m for m in messages if m.get('type') == 47]
for msg in emoji_msgs:
msg_id = msg.get('id')
if msg_id:
download_emoji(msg_id)
time.sleep(0.5)
print('完成')
if __name__ == '__main__':
main()
发表回复