
本文详解如何绕过 instaloader 的评论数量限制,通过模拟浏览器+graphql api 调用,稳定获取 instagram 公开帖的全部评论(含嵌套回复),附完整可运行代码与关键注意事项。
Instagram 官方未开放公开评论的完整 API 接口,且 instaloader 默认仅拉取前 100 条顶层评论(不包含子回复),也无法自动翻页加载更多。要获取全部评论(含深层嵌套、点赞数、时间戳、用户信息等),需结合浏览器自动化与 Instagram 内部 GraphQL 查询机制——这是当前最稳定、免依赖第三方账号权限的方案。
✅ 核心原理说明
Instagram 网页版在加载评论时,实际向以下 GraphQL 端点发起请求:
https://www.instagram.com/graphql/query/?query_hash={hash}&variables={encoded_json}其中 query_hash 是固定哈希值(对应“获取帖子评论”逻辑),variables 包含 shortcode 及分页/深度参数。我们通过 Selenium 模拟登录后访问该 URL,即可获得结构化 JSON 响应。
✅ 完整可运行代码(含错误处理与注释)
import json
import time
from urllib.parse import quote, urlparse
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
def extract_shortcode(url: str) -> str:
"""从 Instagram 帖子 URL 提取 shortcode(如 C2SGS95NQH_)"""
path = urlparse(url).path.strip('/')
if path.startswith('p/'):
return path.split('/')[1]
raise ValueError("Invalid Instagram post URL format")
def build_graphql_url(shortcode: str) -> str:
"""构建 GraphQL 请求 URL,启用全量评论加载"""
variables = {
"shortcode": shortcode,
"child_comment_count": 10000, # 子回复上限(每条评论下的回复)
"fetch_comment_count": 10000, # 首次加载的顶层评论数
"parent_comment_count": 10000, # 顶层评论总数(用于分页)
"has_threaded_comments": True
}
query_hash = "b3055c01b4b222b8a47dc12b090e4e64"
encoded_vars = quote(json.dumps(variables))
return f"https://www.instagram.com/graphql/query/?query_hash={query_hash}&variables={encoded_vars}"
def setup_driver() -> webdriver.Chrome:
"""配置无头 Chrome 驱动(推荐关闭 headless 以便手动登录)"""
options = Options()
options.add_argument("--start-maximized")
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options)
# 隐藏 WebDriver 特征(降低被识别为爬虫概率)
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
})
return driver
def wait_for_manual_login(driver: webdriver.Chrome):
"""暂停等待用户完成 Instagram 登录(关键步骤)"""
print("✅ 请在打开的浏览器中手动登录 Instagram 账号...")
print("⚠️ 登录后,请确保页面跳转至目标帖子(如 https://www.instagram.com/p/...)")
input("按回车键继续 → ")
def fetch_comments_data(driver: webdriver.Chrome, graphql_url: str) -> dict:
"""访问 GraphQL URL 并解析返回的 JSON 数据"""
try:
driver.get(graphql_url)
# 等待 标签加载(GraphQL 响应直接渲染为 pre 标签)
WebDriverWait(driver, 20).until(
EC.presence_of_element_located((By.TAG_NAME, "pre"))
)
soup = BeautifulSoup(driver.page_source, "html.parser")
pre_tag = soup.find("pre")
if not pre_tag or not pre_tag.text.strip():
raise RuntimeError("GraphQL response not found in tag")
return json.loads(pre_tag.text)
except Exception as e:
raise RuntimeError(f"Failed to fetch comments: {e}")
def save_comments_to_file(data: dict, filename: str = "instagram_comments.json"):
"""保存原始响应数据到 JSON 文件(便于后续解析)"""
with open(filename, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"✅ 评论数据已保存至 {filename}")
# —— 主流程 ——
if __name__ == "__main__":
POST_URL = "https://www.instagram.com/p/C2SGS95NQH_/" # 替换为你需要的帖子链接
try:
shortcode = extract_shortcode(POST_URL)
print(f"? 解析 shortcode: {shortcode}")
driver = setup_driver()
driver.get(POST_URL)
wait_for_manual_login(driver)
graphql_url = build_graphql_url(shortcode)
print(f"? 正在请求 GraphQL 接口: {graphql_url[:80]}...")
comments_data = fetch_comments_data(driver, graphql_url)
save_comments_to_file(comments_data)
# ✨ 示例:提取前 5 条顶层评论(含用户名、文本、时间、子回复数)
edges = comments_data.get("data", {}).get("shortcode_media", {}).get("edge_media_to_parent_comment", {}).get("edges", [])
print(f"\n? 获取到 {len(edges)} 条顶层评论示例:")
for i, edge in enumerate(edges[:5]):
node = edge["node"]
username = node["owner"]["username"]
text = node["text"][:60] + "..." if len(node["text"]) > 60 else node["text"]
created_at = node["created_at"]
reply_count = node["edge_comment_to_child_comment"]["count"]
print(f"[{i+1}] @{username} ({time.strftime('%Y-%m-%d', time.gmtime(created_at))}): {text} [回复数: {reply_count}]")
except Exception as e:
print(f"❌ 执行出错: {e}")
finally:
driver.quit()⚠️ 关键注意事项
- 必须手动登录:Instagram 对未登录会话返回空评论,且登录状态需保持(Session Cookie 有效);
- 反爬策略:代码已加入 WebDriver 特征隐藏,但仍建议使用真实账号、避免高频请求(单帖间隔 ≥ 5 秒);
- 评论结构:返回 JSON 中 data.shortcode_media.edge_media_to_parent_comment.edges 为顶层评论列表;每个 node.edge_comment_to_child_comment.edges 为该评论下的嵌套回复;
- 合规提醒:仅限抓取公开帖子,遵守 Instagram Terms of Use 及 GDPR/CCPA 相关条款,禁止存储敏感用户信息或用于商业群发。
✅ 后续建议
- 如需持续采集,可封装为函数支持批量 URL 输入;
- 结合 instaloader 获取帖子元数据(发布时间、点赞数、作者信息),与评论数据关联分析;
- 对大规模评论做情感分析时,建议先清洗(过滤 emoji、URL、广告词)再送入 NLP 模型。
掌握此方法,你将能可靠获取任意公开 Instagram 帖子的全量、结构化评论数据,为舆情分析、用户行为研究提供坚实基础。
立即学习“Python免费学习笔记(深入)”;










