Instagram 对普通脚本几乎没有任何有用的内容可供获取。公开页面通过 JavaScript 渲染,API 接口受到严格限制,而反机器人系统会在几秒内将同一个数据中心 IP 的重复请求标记出来。因此,一个可用的 Instagram 爬虫实际上面临两个叠加的问题:获取一个平台认为是真实用户的 IP,以及让浏览器真正渲染页面后再读取内容。代理解决了前半个问题,但单靠代理并不能解决后半个。
本文的主题是抓取 Instagram 公开数据:帖子说明文字、公开个人主页的元数据,以及无需登录即可看到的帖子点赞数和评论数。不涵盖私人账号或需要登录才能访问的内容,文末的道德规范部分也不是走过场的套话。在明确范围之后,以下是 Instagram 为何封禁爬虫、哪种代理类型适合,以及一条能返回真实数据而非空壳的代码路径。
Instagram 为何封禁爬虫
Instagram 是一个数据丰富、高度商业化的平台,因此其防御机制经过精心调校,能快速丢弃自动化流量。以下四种机制承担了大部分封禁工作,了解是哪种机制捕获了你,就能知道需要改变什么。
- 速率限制。同一 IP 在短时间内发出过多请求会触发临时或永久限制。这是运营成本最低的防御手段,也是你最先遇到的那道墙。
- IP 信誉。归属于已知托管服务商(数据中心 ASN)的 IP 段会被直接标记,通常在你的请求到达页面之前就已被拦截。即使脚本本身没有问题,来自云服务器的请求也很少能看到真实内容。
- JavaScript 渲染。你想要的页面是在客户端构建的。原始 HTTP 请求返回的是字段为空的空壳,因此即使请求未被封禁,若没有浏览器先运行页面,也得不到任何有用的内容。
- 行为与会话分析。快速、重复、完全相同的请求模式与真人刷屏的行为毫无相似之处,Instagram 正是专门监控这种特征的。
代理直接针对前两个问题:它改变了你的流量出口 IP,而在多个 IP 之间轮换能分散负载,使单个地址不会触发速率限制。它不能渲染 JavaScript,也不能制造出人类一样的行为模式。这些是独立的工作,这也正是为什么单纯使用代理虽然必要,但在这里往往还不够。
实际上可以获取哪些公开数据
在写任何代码之前,先设定合理预期。未登录状态下,Instagram 仅暴露有限的内容:公开个人主页元数据(用户名、简介、粉丝数和帖子数)、公开帖子的媒体内容、说明文字,以及公开的点赞数和评论数。Stories、私信、私人账号以及任何需要登录的内容均超出范围,也超出合理使用的边界。如果你的使用场景需要这些数据,抓取并不是合适的工具。
即便是可以获取的数据,也有一个障碍:它通过 JavaScript 加载。用普通 HTTP 客户端获取帖子 URL,你得到的是内容字段为空的 HTML,因为什么都还没有渲染。这是 Instagram 爬虫"能运行"却返回空对象的最常见原因,也是为什么单靠代理还不是终点。
代理的作用,以及应该选哪种类型
代理是你的爬虫与 Instagram 之间的一层间接中转:它替你发出请求,平台看到的是代理 IP 而不是你的 IP。面对这样一个高度防御的目标,IP 的种类比代理的其他特性更重要。
数据中心 IP 快速且廉价,但 Instagram 一见就封,因为它们指向托管 ASN。这使它们在这里无法作为主要选项。能够存活的 IP 是那些看起来像真实用户的:住宅代理从真实的消费者 ISP 连接出口,移动代理则通过运营商网络路由,而运营商级 NAT 让一个 IP 被数千名用户共享,因此封禁它有可能误伤真实客户。移动代理最难被封,但也最贵;住宅代理是 Instagram 的实际最低门槛。完整的对比见 数据中心 vs 住宅代理。
信誉只是其中一半。轮换才是让单个 IP 在整个爬取过程中不被速率限制的关键。轮换住宅代理将你的请求分散到众多真实用户地址,即使你的总量很高,每个 IP 的请求频率也保持在较低水平。使用这种方式最简洁的办法是回连网关(backconnect gateway):一个主机和端口,在后台按请求或按会话(需要会话一致性时)切换出口 IP,这样你的代码只需指向一个端点,轮换在服务器端完成。关于该模式的更多内容,参见 如何使用轮换代理。
合适的住宅或移动 IP 能让你的请求被接受,但不能渲染页面。对于 Instagram,代理和 JavaScript 渲染必须同时到位,否则你得到的是一个未被封禁但响应体依然为空的请求。从一开始就把两者都规划进去,不要等 IP 生效了再临时加渲染。
Instagram 代理类型一览
| 代理类型 | 是否识别为真实用户? | 适用于 Instagram |
|---|---|---|
| 数据中心 | 否(托管 ASN) | 很快被标记,不建议作为主要选项 |
| 住宅(轮换) | 是 | 公开数据抓取的实际最低门槛 |
| 移动 | 是,效果最强 | 最难被封;较贵,在住宅代理受阻时使用 |
实用代码路径
以下示例使用一个同时支持 JavaScript 渲染的轮换住宅网关,因为对 Instagram 而言,两者必须在一次调用中同时具备。端点是一个回连主机,你用普通 HTTP 客户端指向它;轮换和渲染在服务器端处理。你将访问 token 作为代理用户名传入,渲染和短暂等待通过请求参数控制。
首先安装唯一的依赖。
pip install requests
通过网关发出的普通 GET 请求会更换出口 IP,但在 Instagram 上返回的是内容字段为空的空壳,因为什么都还没有渲染。这是需要认清的失败模式,而不是终点。
import requests # Backconnect gateway: token as the username, rotation server-side. proxy_url = "http://_USER_TOKEN_:@smartproxy.crawlbase.com:8012" proxies = {"http": proxy_url, "https": proxy_url} target = "https://www.instagram.com/p/B5-tZGRAPoR/" resp = requests.get(target, proxies=proxies, verify=False) print(resp.status_code) # 200, but the body is mostly empty
要获取真实数据,需要告知网关用浏览器渲染页面,并等待片刻让内容填充。你通过请求头中的参数来实现这一点:开启 JavaScript 渲染,设置短暂的页面等待时间,并调用内置的 Instagram 帖子解析器以返回结构化字段,而不是原始 HTML。
import requests import json proxy_url = "http://_USER_TOKEN_:@smartproxy.crawlbase.com:8012" proxies = {"http": proxy_url, "https": proxy_url} # Render with a browser, wait 3s, parse the post into JSON. params = "scraper=instagram-post&javascript=true&page_wait=3000" headers = {"CrawlbaseAPI-Parameters": params} target = "https://www.instagram.com/p/B5-tZGRAPoR/" resp = requests.get(target, headers=headers, proxies=proxies, verify=False) data = json.loads(resp.content.decode("latin1")) print(json.dumps(data, indent=2))
开启渲染后,同一请求返回的是帖子的结构化字段,而不是空壳。
{ "cb_status": 200, "url": "https://www.instagram.com/p/B5-tZGRAPoR/", "body": { "postedBy": { "accountUserName": "thisisbillgates" }, "caption": { "text": "Our family loves reading together..." }, "likesCount": 339131, "dateTime": "2019-12-12T16:55:16.000Z" } }
这里的关键不在于具体字段,而在于空响应体与有内容的响应体之间的差异完全源于渲染,而非 IP。关于在此技术栈中构建爬虫的完整说明,参见 使用 Python 和 Selenium 进行网页抓取;通用策略则见 如何不被封禁地抓取网站。
调优以保持不被封禁
以下几个习惯能让一次运行在前几百个请求之后仍然保持活跃。这些都不是什么高深技巧,只是让流量看起来像人类行为而非脚本循环的关键区别。
- 保持低单 IP 请求频率。只有当总量确实分散到整个 IP 池时,轮换才能发挥作用。适当控制请求节奏,而不是在紧密循环中高速发出。
- 发送真实的请求头。一个合理的 User-Agent 以及真实浏览器发送的请求头,效果往往超出预期;缺少这些的请求很容易被标记。
- 仅在必要时渲染。JavaScript 渲染比原始请求更慢、成本更高。对确实需要渲染的页面(Instagram 帖子属于此类)使用,对数据已在 HTML 中的页面则跳过。
- 关注状态码。当运行开始返回 403 或验证挑战页面时,这说明当前的 IP 层级或请求频率已不足。把 代理状态错误码当作信号而非噪音来对待。
这些数字背后(每个 IP 被封禁前能发出多少请求、某一层级能维持多高的成功率)都是我们在实践中观察到的范围值,而非固定常量;你的实际数据会因目标站点和服务商而不同。用自己的流量进行测试调优,而不要依赖某份已发布的基准数据。
正视事实:服务条款与合法性
Instagram 的服务条款禁止未经授权的自动化数据访问,无论你的工具多么谨慎,抓取行为都可能违反这些条款。有两条原则值得坚守:只采集公开数据,并遵守平台的明确规则,包括其 robots.txt 和速率预期。不要抓取私人账号、需要登录才能访问的内容,或你没有合理依据采集的个人数据。用于分析目的的公开帖子元数据是一回事,批量获取用户个人信息是另一回事,后者才是法律和道德风险所在。
本指南的范围限定在公开数据,正是因为这条线让工作处于可辩护的范围内。如果一个项目需要更多数据,答案是官方 API 协议,而不是更聪明的爬虫。
Instagram 需要在同一次请求中同时具备真实用户 IP 和渲染后的页面。Smart AI Proxy 是一个单一的回连端点,在庞大的住宅和移动代理池中路由流量,按请求轮换,并可在服务器端渲染 JavaScript,这样你的代码只需指向一个主机,而不必管理代理池和无头浏览器集群。先在免费额度内用它请求一个公开帖子。
核心要点
- Instagram 抓取是两个问题的叠加。获取可信 IP,以及渲染页面。解决其中一个而不解决另一个,结果只会是被封禁或返回空响应体。
- IP 来源决定代理选择。数据中心 IP 很快被标记;轮换住宅代理是实际最低门槛,住宅代理受阻时升级为移动代理。
- 渲染是不可妥协的。公开帖子内容通过 JavaScript 加载,因此无论 IP 多么干净,原始请求都只会返回空壳。
- 控制节奏和请求头是保持存活的关键。低单 IP 请求频率加上真实的请求头,永远优于追求原始速度。
- 坚守公开数据边界。遵守 Instagram 的服务条款和 robots.txt;私人及需要登录的内容是禁区。
常见问题
为什么抓取 Instagram 需要代理?
Instagram 会直接标记数据中心 IP,并对发出重复请求的单一地址进行速率限制。代理会更换你的流量出口 IP,而在真实用户 IP 池中轮换能分散请求,使单个地址不会触发速率限制。没有代理,即使脚本本身没有问题,在发出少数几个请求后就会被封禁。
哪种代理类型最适合 Instagram?
轮换住宅代理是实际最低门槛,因为它们从真实消费者 ISP 的 IP 出口,Instagram 将其识别为普通访客。移动代理最难被封,因为运营商级 NAT 让一个 IP 被许多真实用户共享,但价格更贵。数据中心 IP 被标记得太快,不能作为这里的主要选项。
为什么我的 Instagram 爬虫返回空响应?
几乎总是因为页面没有被渲染。Instagram 使用 JavaScript 在客户端构建内容,因此即使请求本身成功,普通 HTTP 请求返回的 HTML 中数据字段也是空的。开启 JavaScript 渲染并添加短暂的页面等待,让内容在你读取响应之前填充完毕。
抓取 Instagram 数据合法吗?
Instagram 的服务条款禁止未经授权的自动化访问,因此抓取行为可能与这些条款产生冲突。只采集公开数据,遵守平台的 robots.txt 和速率预期,绝不触碰私人账号或需要登录的内容。对于超出公开数据范围的任何需求,正确路径是官方 API 协议,而不是爬虫。
我可以抓取私人 Instagram 账号或 Stories 吗?
不可以,本指南也不涵盖这些内容。私人账号、Stories 和私信都在身份验证后才可访问,通过自动化手段访问它们违反了 Instagram 的服务条款,并带来真实的法律和道德问题。可获取且可辩护的数据仅限于公开个人主页元数据和公开帖子内容。
使用代理后还需要无头浏览器吗?
你需要渲染,但不一定需要自己搭建浏览器集群。代理负责 IP;渲染可以通过你自己的无头浏览器或服务器端渲染的网关来完成。一个在单次请求中同时完成两件事的托管端点,比并行运行代理池和 Selenium 集群要简单得多,尤其在规模较大时。
大规模爬取任何站点,无需与基础设施对抗。
Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。
