什么是 Instagram 爬取 – 定义
Instagram 爬取是从社交媒体平台自动收集公开数据的过程。根据您的编程知识,可以使用预制的爬取工具或定制的网络爬取工具来完成。
社交媒体骗子知道数据收集可以带来全新的交易。只需收集主题标签或帖子等信息,您就可以执行市场和情绪分析、监控在线品牌或寻找对您的业务有影响力的人。
如何合法地爬取 Instagram
网络爬取仍然是一个合法的灰色地带,对于社交媒体来说更是如此。我们不是律师,但普遍认为,如果满足以下条件,爬取网站是可以的(无论网站管理员希望您怎么想):a) 数据是公开的,b) 不涉及版权或 c) 个人信息。
Instagram 也不例外。只要小心行事,刮平台就是合法的。但是,如果有一件事您不应该做,那就是在登录后收集数据。如果 Meta 得知你的活动,那么你肯定会被起诉。
最后,立法根据用例施加了不同的标准。例如,如果您收集信息用于研究,那么您将获得更多的余地,而不是用于商业目的。如果您不确定自己的情况,最好联系律师。
那么,无需登录即可爬取哪些数据?
公开数据主要分为三类:
- 主题标签:帖子 URL、媒体 URL、帖子作者 ID。
- 个人资料:最新帖子、外部 URL、喜欢、图像、评论、每个帖子的喜欢数量和关注者。
- 帖子:最新帖子、日期、URL、评论、点赞、作者 ID。
但请记住,Instagram 经常更改规则,因此在实际操作之前检查一下您可以爬取哪些内容始终是个好主意。
选择你的 Instagram 爬取工具
通常可以使用三种类型的工具来爬取 Instagram:1) 定制的网页爬取工具,2) 网页爬取 API,或 3) 现成的网页爬取工具。
如果您有编程知识,您可以尝试使用 Selenium 或 Playwright 等网络爬取框架构建自己的网络爬取工具。它可以处理复杂的自动化,而且由于您是负责管理爬取机器人的人,因此您可以使其适应 Instagram 为您带来的所有结构变化。
Instagram 不再有自己的官方 API(并不是说它有任何用处)。但有许多可靠的提供商提供网络 爬取 API 。例如,Apify提供了不同的API来收集各种Instagram数据点,例如Instagram Profile Scraper和Post Scraper。或者,您可以使用基于 大型代理池的通用网络爬取工具,例如 Smartproxy 的 Web Scraping API 或 Zyte 的智能代理管理器。
如果您没有任何编程技能,您可以购买现成的爬取工具,例如 Parsehub、Octoparse 或 Bright Data 的数据收集器。这些工具可让您通过直观地单击元素或使用方便的模板来提取数据。
如何爬取 Instagram 数据:使用 Python 的分步指南
假设您想尝试自己爬取 Instagram。你怎样做呢?
我们将尝试构建两个简单的网络爬取工具。其中一种使用 Requests,这是一种流行的 Python 网络爬取库。第二种方法使用 Selenium 启动无头 Chrome 实例。以下是它们的不同之处。
Selenium 模拟浏览器 – 它打开并转到网页。使用 Selenium 进行爬取将为您带来更多成功的请求。另一方面,Requests 库仅将 HTTP 请求发送到浏览器。这种方法的成功率较低,但你可以更快地爬取 Instagram。
开始爬取 Instagram 的其他必要工具
如果您想开始安全地爬取 Instagram,您还必须考虑隐藏您的 IP 地址,因为该平台限制了人们无需登录即可访问的信息量。
最好的方法是使用旋转代理服务器。根据您的代理提供商的不同,它会每 5 分钟、10 分钟或每次连接请求为您提供一个不同的 IP。如果您不需要从哪里获取代理,请查看我们优秀的Instagram 代理提供商列表。
管理期望
爬取社交媒体平台是一个艰难而复杂的过程。您必须耐心武装自己,以增加成功收集 Instagram 数据的机会。
在您掌握窍门之前,您的某些请求将不可避免地失败 – 20%、30% 甚至更多。失败的请求将引发代理错误,从而停止爬取。您可以添加重试功能以重试。但是,为此,您需要针对每个失败的请求更改您的 IP 地址。
如今,包括 Instagram 在内的大多数在线媒体都要求用户提供个人信息才能访问网站或特定内容。他们将数据放在潜在客户捕获表格中,例如电话号码、电子邮件地址或一些问题。很快,需要爬取的数据点可能会更少,因为 Instagram 将屏蔽更多内容。
如何使用 Selenium 爬取 Instagram 的公开资料
这是使用代理的现实示例。我们将使用__a=1参数来爬取 Instagram 用户名,该参数可以将任何页面转换为 JSON 格式。在本指南中,该参数将从个人资料页面返回内容。
步骤 1.首先安装Selenium 、Chromedriver和Selenium-Stealth 。
1)首先,从Selenium模块导入webdriver。
from selenium import webdriver
2)然后使用Selenium中的By选择器模块导入Web驱动程序以简化选择。
from selenium.webdriver.common.by import By
3) 打印结果以格式化控制台输出。
from pprint import pprint
4) 由于我们将使用 JSON模块,因此您也需要导入它。
import json
5)然后导入Selenium-Stealth以获得更真实的浏览器。
from selenium_stealth import stealth
步骤 2.设置您想要爬取的 Instagram 个人资料的用户名。
usernames = ["jlo", "shakira", "beyonce", "katyperry"]
为您的代理创建一个变量。他们将帮助您达到更高的成功率。
proxy = "server:port"
您可以创建一个新的字典变量来存储爬取的结果。
output = {}
步骤 3.然后编写代码的开头,调用main()函数并添加另一行以在完成后打印出爬取的结果。
if __name__ == '__main__': main() pprint(output)
编写代码来迭代您要爬取的用户名。main ()函数将迭代 Instagram 用户名列表,并将其发送到我们稍后要编写的另一个scrape()函数。
def main(): for username in usernames: scrape(username)
步骤 4.接下来,您需要按照以下步骤定义函数:
1)创建一个新函数。它将允许您在每次爬取之前更改浏览器设置,例如更改用户代理或轮换代理。
def prepare_browser():
2) 初始化 Chrome 选项。
chrome_options = webdriver.ChromeOptions()
3)在浏览器选项中添加代理。
chrome_options.add_argument(f'--proxy-server={proxy}')
4) 现在让我们指定 Selenium-Stealth 工作所需的设置
chrome_options.add_argument("start-maximized") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False)
5) 使用您之前设置的选项创建 Chrome 浏览器。
driver = webdriver.Chrome(options= chrome_options)
6) 应用更多Selenium-Stealth设置。为了获得额外的匿名性,您可以轮换您的数字指纹或用户代理。
stealth(driver, user_agent= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.53 Safari/537.36', languages= ["en-US", "en"], vendor= "Google Inc.", platform= "Win32", webgl_vendor= "Intel Inc.", renderer= "Intel Iris OpenGL Engine", fix_hairline= False, run_on_insecure_origins= False, )
7) 返回 Chrome 驱动程序,其中包含您迄今为止设置的所有选项和设置。
return driver
步骤 5.现在让我们继续爬取。
1)创建一个新函数。scrape ()函数仅需要一个参数 – 您从main()函数的循环中传递的用户名。
def scrape(username):
2)建立一个URL。在末尾添加?__a=1&__d=dis可以让您直接从 Instagram 后端获取响应,而无需解析 HTML 内容。
url = f'https://instagram.com/{username}/?__a=1&__d=dis'
3) 然后调用prepare_browser()函数并将驱动程序分配给变量。
chrome = prepare_browser()
4)打开浏览器并发出请求。
chrome.get(url)
5) 要判断请求是否失败,您需要检查您是否没有被重定向到登录。您可以通过查看登录字符串来做到这一点 – 如果它出现在 URL 中,则请求未成功。可以在此处添加其他重试功能,以便稍后尝试爬取用户名。
print (f"Attempting: {chrome.current_url}") if "login" in chrome.current_url: print ("Failed/ redir to login") chrome.quit()
6) 否则,请求成功。这意味着我们可以从响应中提取正文并将其解析为JSON 。然后,结果可以与您爬取的 Instagram 用户名一起传递给parse_data()函数。
else: print ("Success") resp_body = chrome.find_element(By.TAG_NAME, "body").text data_json = json.loads(resp_body) user_data = data_json['graphql']['user'] parse_data(username, user_data) chrome.quit()
第 6 步:让我们继续解析数据。创建提到的parse_data()函数以从JSON响应中获取所需的数据。
def parse_data(username, user_data):
例如,您可以从公开帖子中获取一些帖子标题。
captions = [] if len(user_data['edge_owner_to_timeline_media']['edges']) > 0: for node in user_data['edge_owner_to_timeline_media']['edges']: if len(node['node']['edge_media_to_caption']['edges']) > 0: if node['node']['edge_media_to_caption']['edges'][0]['node']['text']: captions.append( node['node']['edge_media_to_caption']['edges'][0]['node']['text'] )
除了帖子标题之外,您还可以获取用户的全名、所属类别以及关注者数量。所有这些信息最终都可以写入输出字典中。
output[username] = { 'name': user_data['full_name'], 'category': user_data['category_name'], 'followers': user_data['edge_followed_by']['count'], 'posts': captions, }
这是 脚本的输出:
from selenium import webdriver from selenium.webdriver.common.by import By from pprint import pprint import json from selenium_stealth import stealth usernames = ["jlo", "shakira", "beyonce", "katyperry"] output = {} def prepare_browser(): chrome_options = webdriver.ChromeOptions() proxy = "server:port" chrome_options.add_argument(f'--proxy-server={proxy}') chrome_options.add_argument("start-maximized") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) driver = webdriver.Chrome(options= chrome_options) stealth(driver, user_agent= 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.53 Safari/537.36', languages= ["en-US", "en"], vendor= "Google Inc.", platform= "Win32", webgl_vendor= "Intel Inc.", renderer= "Intel Iris OpenGL Engine", fix_hairline= False, run_on_insecure_origins= False, ) return driver def parse_data(username, user_data): captions = [] if len(user_data['edge_owner_to_timeline_media']['edges']) > 0: for node in user_data['edge_owner_to_timeline_media']['edges']: if len(node['node']['edge_media_to_caption']['edges']) > 0: if node['node']['edge_media_to_caption']['edges'][0]['node']['text']: captions.append( node['node']['edge_media_to_caption']['edges'][0]['node']['text'] ) output[username] = { 'name': user_data['full_name'], 'category': user_data['category_name'], 'followers': user_data['edge_followed_by']['count'], 'posts': captions, } def scrape(username): url = f'https://instagram.com/{username}/?__a=1&__d=dis' chrome = prepare_browser() chrome.get(url) print (f"Attempting: {chrome.current_url}") if "login" in chrome.current_url: print ("Failed/ redir to login") chrome.quit() else: print ("Success") resp_body = chrome.find_element(By.TAG_NAME, "body").text data_json = json.loads(resp_body) user_data = data_json['graphql']['user'] parse_data(username, user_data) chrome.quit() def main(): for username in usernames: scrape(username) if __name__ == '__main__': main() pprint(output)
如何使用请求库爬取 Instagram 的公开资料
这是使用基于 Python 的库 Requests 的另一个分步示例。此方法明显更快且更轻量,因为您不需要模拟 Web 浏览器。然而,它也失败了很多。但即使成功率很低,您也可以通过简单地使用新代理重试来获取相当多的数据。
步骤 1.首先导入Requests 、JSON和Random 。
import requests, json, random
然后我们将打印结果以格式化控制台输出。
from pprint import pprint
步骤 2.现在让我们设置一个用户名列表,其中包含我们要爬取的所有 Instagram 用户。
usernames = ["jlo", "shakira", "beyonce", "katyperry"]
之后,设置您的代理。
proxy = "http://username:password@server:port"
您可以创建一个新的字典变量来存储爬取的结果。
output = {}
步骤3.然后编写代码的开头,调用main()函数。
if __name__ == '__main__': main() pprint(output)
现在准备您要通过爬取工具发送请求的标头和掩码。标头还将轮换几个用户代理。
def get_headers(username): headers = { "authority": "www.instagram.com", "method": "GET", "path": "/{0}/".format(username), "scheme": "https", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "accept-encoding" : "gzip, deflate, br", "accept-language": "en-GB,en-US;q=0.9,en;q=0.8", "upgrade-insecure-requests": "1", "Connection": "close", "user-agent" : random.choice([ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36" ]) } return headers
步骤 4. 编写代码来迭代您要爬取的用户名。main ()函数将遍历 Instagram 用户名列表。
def main(): for username in usernames: url = f"https://instagram.com/{username}/?__a=1&__d=dis"
步骤 5.现在我们将编写发送请求的行,并向其应用标头和代理。
response = requests.get(url, headers=get_headers(username), proxies = {'http': proxy, 'https': proxy})
要判断请求是否失败,您需要检查您是否未重定向到登录。您可以通过检查响应是否为JSON来做到这一点。此外,这一行还可以让您解析响应文本。
if response.status_code == 200: try: resp_json = json.loads(response.text)
如果您没有获得JSON 格式的结果,则意味着您已重定向到登录;脚本将继续执行下一个用户名。
except: print ("Failed. Response not JSON") continue
可以在此处添加其他重试功能,以便稍后尝试爬取用户名。
else:
如果您得到JSON 格式的结果,那么您可以清理(解析)您的数据。
user_data = resp_json['graphql']['user'] parse_data(username, user_data)
一路上可能会出现一些错误。让我们试着抓住他们。如果失败,则使用重试逻辑。
elif response.status_code == 301 or response.status_code == 302: print ("Failed. Redirected to login")
else: print("Request failed. Status: " + str(response.status_code))
步骤 6.创建parse_data()函数以从JSON响应中获取所需的数据。
def parse_data(username, user_data):
例如,您可以从公开发布的帖子中获取一些帖子标题,并将它们的列表分配给变量。
captions = [] if len(user_data['edge_owner_to_timeline_media']['edges']) > 0: for node in user_data['edge_owner_to_timeline_media']['edges']: if node['node']['edge_media_to_caption']['edges'][0]['node']['text']: captions.append( node['node']['edge_media_to_caption']['edges'][0]['node']['text'] ) output[username] = { 'name': user_data['full_name'], 'category': user_data['category_name'], 'followers': user_data['edge_followed_by']['count'], 'posts': captions, }
这是 脚本的输出。
import requests, json, random from pprint import pprint usernames = ["jlo", "shakira", "beyonce", "katyperry"] proxy = "http://username:password@proxy:port" output = {} def get_headers(username): headers = { "authority": "www.instagram.com", "method": "GET", "path": "/{0}/".format(username), "scheme": "https", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "accept-encoding" : "gzip, deflate, br", "accept-language": "en-GB,en-US;q=0.9,en;q=0.8", "upgrade-insecure-requests": "1", "Connection": "close", "user-agent" : random.choice([ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36" ]) } return headers def parse_data(username, user_data): captions = [] if len(user_data['edge_owner_to_timeline_media']['edges']) > 0: for node in user_data['edge_owner_to_timeline_media']['edges']: if len(node['node']['edge_media_to_caption']['edges']) > 0: if node['node']['edge_media_to_caption']['edges'][0]['node']['text']: captions.append( node['node']['edge_media_to_caption']['edges'][0]['node']['text'] ) output[username] = { 'name': user_data['full_name'], 'category': user_data['category_name'], 'followers': user_data['edge_followed_by']['count'], 'posts': captions, } def main(): for username in usernames: url = f"https://instagram.com/{username}/?__a=1&__d=dis" response = requests.get(url, headers=get_headers(username), proxies = {'http': proxy, 'https': proxy}) if response.status_code == 200: try: resp_json = json.loads(response.text) except: print ("Failed. Response not JSON") continue else: user_data = resp_json['graphql']['user'] parse_data(username, user_data) elif response.status_code == 301 or response.status_code == 302: print ("Failed. Redirected to login") else: print("Request failed. Status: " + str(response.status_code)) if __name__ == '__main__': main() pprint(output)