跳到正文
Hacker News· pob944·· 6 天前AI 评分22

Facebook Marketplace MCP 服务器:用 Chrome 会话自动化车源搜索

Facebook Marketplace Reaper Automate Marketplace Finder

AI 导读

一个 MCP 服务器通过现有 Chrome Facebook 登录会话访问 Facebook Marketplace,位置查询走 Facebook GraphQL API,列表搜索读取该会话的 Marketplace 搜索页。

正文 · AI 翻译

一个 MCP 服务器,使用你现有的 Chrome Facebook 会话访问 Facebook Marketplace。位置查询使用 Facebook 的 GraphQL API。商品搜索读取该会话的 Marketplace 搜索页面。

前提条件

  • macOS(Cookie 提取使用钥匙串)
  • Google Chrome 并已登录 Facebook
  • Python 3.11+

安装

cd server
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e .

macOS 上的 python3 通常低于 3.11。请使用 python3.12 或任何 Python 3.11+ 二进制文件。

设置

facebook-marketplace-mcp

或者将 MCP 客户端指向该模块:

{
  "mcpServers": {
    "facebook-marketplace": {
      "command": "python",
      "args": ["-m", "facebook_marketplace_mcp"],
      "env": {
        "CHROME_PROFILE": "Default"
      }
    }
  }
}

如果包不在默认的 PATH 中,请使用虚拟环境的 python。

CLI

facebook-marketplace 直接调用 Marketplace,无需 MCP 客户端或模型回合。每个命令都接受 --json(打印记录而非表格)和 --chrome-profile(Chrome 配置文件目录;默认为 CHROME_PROFILE 或 Default)。

里程从不需要,也不会打印。搜索页面使用已登录 Chrome 账户上的 Marketplace 城市。--latitude、--longitude 和 --radius-km 会随监视器一起存储,但不会改变该搜索。省略它们时,它们会保存为 0、0 和 50。

search

搜索商品并打印 slug、price、title、location、seller 和 url。

facebook-marketplace search "cr-v 2023" --min-price 20000 --max-price 26000
facebook-marketplace search "cr-v 2023" --province quebec
facebook-marketplace search "crv 2023" "cr-v 2023" --province quebec

第一条命令查找 cr-v 2023,并保留价格从 CA$20,000 到 CA$26,000 的商品。第二条搜索魁北克省。Facebook 从魁北克城以 650 公里半径进行查询,然后丢弃魁北克省以外的商品。--province 也接受 QC 以及其他省份和地区。

卖家对同一辆车使用不同的措辞。传入多个名称,或用逗号分隔,命令会搜索每个名称,并为每个商品保留一行:

facebook-marketplace search "crv 2023, cr-v 2023" --province quebec

每个名称最多返回 --limit 个商品。当 Facebook 报告还有下一页时,搜索最多读取 10 页。空页会被跳过,但仍会请求下一页。合并后的行保存在一个文件夹中,runs/crv 2023, cr-v 2023/。

标志 默认值 含义
--min-price 无 最低价格(美元)
--max-price 无 最高价格(美元)
--limit 20 最大行数
--category 无 Marketplace 分类 ID
--latitude 0 仅存储;不作为搜索中心发送
--longitude 0 仅存储;不作为搜索中心发送
--radius-km 50 仅存储,除非设置了 --province
--province 无 加拿大省份或地区(quebec、QC)。搜索该省份并丢弃省外的商品

空结果会打印 No listings found 并以 0 退出。钥匙串、Cookie 或 HTTP 失败会打印到 stderr 并以 1 退出。

每个找到的商品都会获得一个稳定的 slug,slugified-title-<listing id>。首次看到某个商品 ID 时,该 slug 会保存在 ~/.fb-marketplace/catalog.json 中,即使之后标题发生变化也会复用。一个搜索名称对应一个文件夹。多个名称共享一个文件夹,文件夹名由这些名称用逗号连接而成:

server/runs/cr-v 2023/<slug>.json
server/runs/crv 2023, cr-v 2023/<slug>.json

每个商品存储 created_at、updated_at、original_price 和 price。打开商品链接时显示的照片会保存一次,为 <slug>.png,同一文件既是缩略图,也是 runs/index.html 中打开的图片。首次搜索将 created_at 和 updated_at 设为同一时间,并将 original_price 设为当时发现的价格。之后再次找到该商品的搜索会将 updated_at 设为该时间。更低的价格会保留 original_price,将更低的价格写入 price,并设置 price_dropped。

使用 facebook-marketplace serve 打开已保存的商品,然后转到 http://127.0.0.1:8767/index.html。页面读取每个商品的 JSON,并每 15 秒再次检查。搜索会更新 runs/index.json,即这些文件的列表。listing 和 monitor check 更新同一个商品文件。

列表显示每个搜索文件夹,然后是照片、价格、标题、地点和卖家。商品按最便宜优先排序。

Search list with listing rows

点击一行,保存的 Marketplace 页面会在该行下方打开。再次点击可关闭。只有一行保持打开。

Open listing with the Marketplace page snapshot

serve

在本机上提供 runs/,以便商品页面可以读取 JSON 文件。

facebook-marketplace serve

打开 http://127.0.0.1:8767/index.html。--port 选择另一个端口。进程会持续运行,直到被停止。

location

将城市或城镇解析为坐标。

facebook-marketplace location "Montreal"

为每个匹配项打印 name、latitude 和 longitude,包括 Montreal、Quebec。使用诸如 Montreal 这样的城市名。Montreal QC 可能不返回任何行。

listing

通过搜索 URL 中的 id 打开一个商品列表(/marketplace/item/<id>/)。

facebook-marketplace listing 29168184989452025

打印标题、价格、成色、位置、卖家、描述和 URL。

monitor add

在 ~/.fb-marketplace/monitors.json 中保存搜索,以便后续检查只显示新的 id。每个 --query 值都作为独立的关键词存储。同名的监控会更新这些关键词,而不是创建第二个监控。

facebook-marketplace monitor add crv --query "crv 2023" --query "cr-v 2023" --min-price 20000 --max-price 26000

这会保存一个名为 crv 的监控,同时跟踪 crv 2023 和 cr-v 2023,然后合并这些行。--query 是必需的,且可以重复。用相同的名称再次运行 add 会更新这些关键词和价格范围。--limit 默认为 250。--category、--latitude、--longitude 和 --radius-km 匹配 search。该命令会打印监控名称、id 以及每个关键词。它此时还不会进行搜索。

monitor check

运行每个已保存的搜索,并打印之前未见过其 id 的商品列表。新见到的 id 会被存储,最多保留最近 500 个。

facebook-marketplace monitor check

检查每个监控。传入名称可只检查一个:

facebook-marketplace monitor check crv
facebook-marketplace monitor check "hrv, hr-v"

每个块以 <name>: <count> new 开头,然后是跟 search 相同的列。缺少名称,或完全没有监控时,退出码为 1。

当该检查发现新商品列表时,它还会发送一条 Slack 消息。单独的 search 不会。没有新内容的检查也不会。消息内容是监控名称、新数量、最多五行价格、标题和地点,以及一个指向运行页面的链接。

每日检查

scripts/daily-monitors.sh 会为每个已保存的监控运行 monitor check。该检查会重写 runs/index.json。随后脚本会提交 runs/(包括 runs/index.html),并将该文件夹推送到 fb-marketplace main。index.html 会加载 index.json。推送到 main 会创建一个短期分支并将其合并到 gh-pages。GitHub Pages 从 gh-pages 构建站点,因此 Settings → Pages 必须使用 Deploy from a branch、gh-pages、/ (root)。没有商品列表变化的日子不会提交。没有新内容的日子不会发送 Slack。

用户 crontab 会在 Mac 本地时区的 9:00 运行它:

0 9 * * * /Users/poboisvert/Desktop/GIT/mrk-agent/server/scripts/daily-monitors.sh

届时 Mac 必须处于开机并已登录状态。该检查会从 Keychain 读取 Chrome 的 Facebook cookies,而 cron 不会唤醒睡眠中的 Mac。输出会追加到 ~/Library/Logs/fb-marketplace-daily.log。

通知

在 api.slack.com/apps 创建一个 Slack 应用。在 OAuth & Permissions 下,添加机器人作用域 chat:write,然后将该应用安装到工作区。复制 Bot User OAuth Token(xoxb-...)。邀请该机器人加入应接收提醒的频道,并从频道详情中复制频道 ID。

在运行 facebook-marketplace monitor check 或 facebook-marketplace-mcp 的 shell 中导出这些值:

export SLACK_BOT_TOKEN="xoxb-your-bot-token"
export SLACK_CHANNEL="C0123456789"

SLACK_BOT_TOKEN 和 SLACK_CHANNEL 是必需的。SLACK_CHANNEL 是频道 ID。当机器人已在该频道中时,诸如 #marketplace 这样的名称也可以使用。

相同的名称可以写入 server/.env。复制 server/.env.example 以开始。该文件会被 git 忽略。shell 中已设置的值会保留。不要将 token 放入仓库或 ~/.fb-marketplace/monitors.json 中。如果任一值缺失,检查会打印 Slack skipped: set SLACK_BOT_TOKEN and SLACK_CHANNEL.,但仍会完成。Slack 错误也会以相同方式打印。not_in_channel 表示机器人尚未被邀请到该频道。

用以下命令确认 token 和频道:

pytest tests/test_slack_setup.py

该测试会向 Slack 验证机器人,然后向 SLACK_CHANNEL 发送一条消息。当任一值缺失时它会跳过。

monitor list

显示已保存的搜索,而不联系 Facebook。

facebook-marketplace monitor list

每个监控会打印其名称、设置时的价格范围、已见到的商品列表 id 数量以及上次检查时间。每个关键词会在名称下方单独一行打印:

crv	20000.0-26000.0 seen 0
  crv 2023
  cr-v 2023

monitor delete

移除一个已保存的搜索。该名称对应的已见 id 也会随之删除。

facebook-marketplace monitor delete crv

打印一条确认信息。如果 crv 不存在,错误会输出到 stderr,且命令退出码为 1。

工具

search_listings

按一个或多个名称和价格筛选条件搜索 Marketplace。

参数 类型 必需 描述
query string yes 一个或多个名称,用逗号分隔(crv 2023, cr-v 2023)。每个名称都会被搜索,结果行会被合并
latitude number yes 搜索中心的纬度
longitude number yes 搜索中心的经度
radius_km number no 搜索半径(默认:50)。保留给调用方;搜索页面使用 Chrome 账号的 Marketplace 城市
min_price number no 最低价格(美元)
max_price number no 最高价格(美元)
category string no 分类 ID
limit number no 每个名称的最大结果数(默认:20)
province string no 加拿大省份或地区(quebec、QC)。会剔除其以外的房源

里程在房源上可能缺失,且不是必需的。用逗号分隔的 query 会为每个名称运行一次 Marketplace 搜索,并按房源 id 保留一行。

get_listing

获取特定房源的完整详情。

参数 类型 必需 描述
listing_id string yes Marketplace 房源 ID

search_location

查找城市或城镇并返回坐标。

参数 类型 必需 描述
query string yes 城市或城镇名称

monitor_search

将搜索保存为监控项。query 中的逗号是独立关键词,存储在监控项上,并在检查时合并。再次保存相同的 name 会替换这些关键词。

参数 类型 必需 描述
name string yes 监控项名称
query string yes 一个或多个名称,用逗号分隔。检查与合并方式与 search_listings 相同
latitude number yes 搜索中心纬度
longitude number yes 搜索中心经度
radius_km number no 半径(默认:50)
min_price number no 最低价格
max_price number no 最高价格
province string no 加拿大省份或地区(quebec、QC)

check_monitors

检查监控项自上次检查以来的新房源。

参数 类型 必需 描述
monitor_name string no 检查特定监控项,或省略以检查全部

list_monitors

列出已保存的监控项及其为每个名称存储的关键词。

delete_monitor

删除已保存的监控项。

监控项存储在 ~/.fb-marketplace/monitors.json 中。

配置

环境变量 默认值 描述
CHROME_PROFILE Default Chrome 配置文件目录名称
SLACK_BOT_TOKEN Slack 机器人令牌(xoxb-...)。在新监控项房源通知时必需
SLACK_CHANNEL Slack 频道 ID,或诸如 #marketplace 的名称。与 SLACK_BOT_TOKEN 一起使用时必需

速率限制

服务器自我限速为每分钟 3 次请求,并带有随机抖动。搜索需要几秒钟。

限制

  • 仅限 macOS 用于自动提取 cookie
  • 需要 Chrome 并保持活跃的 Facebook 会话
  • Facebook 服务条款 — 自动化操作 Facebook 违反其服务条款
  • 搜索城市 遵循已登录 Chrome 账号上的 Marketplace 位置
  • 速率受限 — 过度使用可能触发 CAPTCHA 或账号标记
  • 无写入操作 — 仅搜索/读取,不发送消息或创建房源

来源:Hacker News · github.com