这是一个逐步示例,展示如何使用Python爬取公开可用的Facebook数据。
什么是 Facebook 爬取 – 定义
Facebook 爬取是一种自动从社交媒体平台收集数据的方法。人们通常使用预制的网络爬取工具或定制的爬取工具来爬取 Facebook 数据。然后,对收集到的数据进行解析(清理)并导出为易于分析的格式,例如 .json。
通过爬取帖子、点赞或关注者等数据点,企业可以收集客户意见、分析市场趋势、监控在线品牌推广工作并保护其声誉。
Facebook 爬取合法吗?
尽管社交媒体平台可能不喜欢网络爬取,但收集公开数据的行为是合法的。2022 年,第九巡回上诉法院裁定,爬取公共数据并不违反《计算机欺诈和滥用法》。
然而,这并不能阻止 Facebook 的所有者 Meta 积极打击任何从其平台窃取数据的人, 从新裁决后不久该公司针对爬虫提起的诉讼来看。看来 Meta 将继续为保持其信息垄断而奋斗。
那么,您可以爬取哪些 Facebook 数据?
首先也是最重要的,如果您想爬取社交媒体数据,您需要确保它 1) 公开,并且 2) 不受版权法保护。以下是 Facebook 上主要公开的类别:
- 个人资料:最新帖子、用户名、个人资料URL、个人资料照片URL、关注者和粉丝、点赞和兴趣以及包括在个人资料中的其他公开信息。
- 帖子:最新帖子、日期、位置、点赞、浏览次数、评论、文本和媒体URL。
- 标签:帖子URL、媒体URL、帖子作者ID。
- Facebook商业页面:URL、个人资料图片、名称、点赞、故事、关注者、联系信息、网站、类别、用户名、头像、类型、已验证、相关页面信息。
如果您将收集个人信息(这很可能),则会适用更多规则,例如需要通知该人并给予他们选择退出的权利。最好咨询律师,以确保您的操作合法。
如何选择 Facebook 爬取工具
Facebook 爬取的一种方法是使用Selenium 和 Playwright等框架构建自己的爬取工具。两者都是控制无头浏览器的流行工具,对于爬取 Facebook 来说是必需的。然而,该平台对爬虫不利,因此自建工具最适合中级到高级用户。
一个更简单的解决方案是使用预制的爬虫。让我们以 Facebook-page-scraper 为例。它是一个 Python 包,旨在爬取 Facebook 页面的前端。此类爬取工具已经包含提取和构建相关数据的逻辑。 然而,如果没有额外的工具(例如有助于掩盖网络爬取工具数字指纹的代理),它们就无法工作。
最直接的选择是购买商业网络爬取工具。 根据您的技术知识和需求,有多种选项可供选择:
- 如果您不想涉及代码,可以选择无代码爬虫。服务如Parsehub、PhantomBuster或Octoparse提供的爬虫允许您通过单击可视元素来提取数据。它们非常适合小规模数据收集或在不需要运行复杂设置时使用。
- 或者,您可以获取一个网络爬虫API。它们类似于预制的网络爬虫,但维护更好,并且内置了所有必要的元素。因此,您只需要发送请求并存储输出。像Smartproxy或Bright Data这样的公司都提供可以爬取Facebook的API。
如何爬取 Facebook 帖子:使用 Python 的分步示例
在此示例中,我们将使用基于 Python 的爬取工具 – Facebook-page-scraper 3.0.1。它预先编写了大部分网络爬取逻辑,不限制您可以发出的请求数量,并且您不需要注册或拥有 API 密钥。
开始爬取 Facebook 的必要工具
为了使爬取工具正常工作,您需要使用代理服务器和无头浏览器库。
Facebook 对爬取工具采取了各种行动,从请求限制到 IP 地址封锁。代理可以通过屏蔽您的 IP 地址和位置来帮助规避这种结果。如果您不知道在哪里可以找到优质 IP,我们列出了最佳Facebook 代理提供商列表 。
我们需要一个无头浏览器有两个原因。首先,它将帮助我们加载动态元素。其次,由于 Facebook 使用反机器人保护,它将使我们能够模仿真实的浏览器指纹。
管理期望
在进入代码之前,您需要了解一些事情。
Facebook 爬取工具仅限于公开可用的数据。我们不鼓励您在登录后爬取数据,但有些人可能会发现这是一个缺点。
最近,Facebook 进行了一些更新,影响了我们将使用的爬取工具。如果您想爬取多个页面或避免出现 cookie 同意提示,则必须对爬取文件进行一些调整。但别担心——我们会指导您完成每一步。
如果您想了解有关网络爬取的更多详细信息,请查看我们指南中的最佳网络爬取实践。
预备工作
在开始之前,您需要拥有 Python 和 JSON 库。然后,您需要安装 Facebook-page-scraper。 您可以通过在终端中输入 pip install 命令来完成此操作:
pip install facebook-page-scraper
代码的修改
现在,让我们对 scraper 文件进行一些更改。
为了避免出现 cookie 同意提示,您首先需要修改driver_utilities.py文件。否则,爬取工具将继续滚动提示,而您将不会得到任何结果。
步骤1 在控制台中使用 show 命令查找文件。它将返回保存文件的目录。
pip show facebook_page_scraper
步骤2 现在,在driver_utilities.py中,将代码添加到wait_for_element_to_appear定义的末尾。
allow_span = driver.find_element( By.XPATH, '//div[contains(@aria-label, "Allow")]/../following-sibling::div') allow_span.click()
整个函数如下所示:
@staticmethod def __wait_for_element_to_appear(driver, layout): """expects driver's instance, wait for posts to show. post's CSS class name is userContentWrapper """ try: if layout == "old": # wait for page to load so posts are visible body = driver.find_element(By.CSS_SELECTOR, "body") for _ in range(randint(3, 5)): body.send_keys(Keys.PAGE_DOWN) WebDriverWait(driver, 30).until(EC.presence_of_element_located( (By.CSS_SELECTOR, '.userContentWrapper'))) elif layout == "new": WebDriverWait(driver, 30).until( EC.presence_of_element_located((By.CSS_SELECTOR, "[aria-posinset]"))) except WebDriverException: # if it was not found,it means either page is not loading or it does not exists print("No posts were found!") Utilities.__close_driver(driver) # exit the program, because if posts does not exists,we cannot go further sys.exit(1) except Exception as ex: print("error at wait_for_element_to_appear method : {}".format(ex)) Utilities.__close_driver(driver) allow_span = driver.find_element( By.XPATH, '//div[contains(@aria-label, "Allow")]/../following-sibling::div') allow_span.click()
步骤4。继续修改scraper.py文件以支持从多个页面中爬取信息并将其保存到单独的文件中。
- 将以下行移动到init()方法中,并在这些行的开头添加self参数,以便可以实例化这些变量。
这将使数据字典和已提取帖子的集合在每个实例中都可用。
更新后的scraper.py文件应如下所示:
from webdriver_utilities import Utilities from page_utilities import Pages from page_utilities import PagesType from time import sleep from random import randint from datetime import datetime import os import json import sys class Scraper: def __init__(self, page_name, number_of_posts, browser="chrome", proxy=None, timeout=60, headless=True): self.__page_name = page_name self.__number_of_posts = number_of_posts self.__browser = browser self.__proxy = proxy self.__timeout = timeout self.__headless = headless self.__current_path = os.path.dirname(os.path.realpath(__file__)) self.__data_dict = {} self.__extracted_post = set() def scrap(self): try: # Initialize the web driver driver = Utilities.get_driver( self.__browser, self.__proxy, self.__headless) Utilities.go_to_url( driver, Pages.get_url(self.__page_name, PagesType.PAGE)) Utilities.__scroll_page( driver, self.__number_of_posts // 10, self.__page_name) # Rest of the scraping logic here... except Exception as ex: print(f"An error occurred: {str(ex)}") finally: Utilities.__close_driver(driver) # Other methods...
步骤5。现在,您可以在scraper.py中添加一个新的方法,以将数据保存到单独的文件中。
在Scraper类中添加一个新的方法,用于将数据保存到文件中。我们将这个方法命名为save_to_file
。这个方法将接受一个文件名作为参数,并将数据保存到以该文件名为名称的JSON文件中。
def save_to_file(self, filename): if not filename.endswith('.json'): filename += '.json' try: with open(filename, 'w', encoding='utf-8') as file: json.dump(self.__data_dict, file, ensure_ascii=False, indent=4) print(f"Data saved to {filename}") except Exception as ex: print(f"An error occurred while saving data: {str(ex)}")
步骤6。现在,您可以在scraper.py中修改scrap
方法,以在爬取完毕后调用save_to_file
方法。
在Scraper类的scrap
方法中,添加一行代码,以在爬取完毕后调用save_to_file
方法,将数据保存到文件中。您可以选择在任何方便的时候调用此方法,但在示例中,我们将其放在数据爬取完成后。
def scrap(self): try: # Initialize the web driver driver = Utilities.get_driver( self.__browser, self.__proxy, self.__headless) Utilities.go_to_url( driver, Pages.get_url(self.__page_name, PagesType.PAGE)) Utilities.__scroll_page( driver, self.__number_of_posts // 10, self.__page_name) # Rest of the scraping logic here... # Save data to file self.save_to_file(f'{self.__page_name}_data') except Exception as ex: print(f"An error occurred: {str(ex)}") finally: Utilities.__close_driver(driver) # Other methods...
步骤7。最后,您可以在您的主程序中使用新的Scraper
类来爬取数据并将其保存到文件中。在主程序中,您首先需要创建一个Scraper
实例,然后调用其scrap
方法来执行爬取和保存操作。
# Import the Scraper class from scraper.py from scraper import Scraper # Define the page name, number of posts, and other parameters page_name = 'example_page' number_of_posts = 100 # Change this to the desired number of posts browser = 'chrome' # You can change the browser if needed proxy = None # Add your proxy configuration if necessary timeout = 60 # Adjust the timeout as needed headless = True # Set to False if you want to see the browser in action # Create a Scraper instance scraper = Scraper(page_name, number_of_posts, browser, proxy, timeout, headless) # Call the scrap method to start scraping scraper.scrap() # The data will be saved to a JSON file automatically
这样,您就可以使用新的Scraper
类轻松爬取数据并将其保存到单独的JSON文件中。只需在主程序中设置适当的参数,然后调用scrap
方法即可。希望这些步骤有助于您成功地爬取Facebook数据并保存到文件中.
总结
完整的如何在2024年爬取Facebook数据的代码示例
# 导入所需的库和模块 from webdriver_utilities import Utilities from page_utilities import Pages, PagesType from time import sleep from random import randint from datetime import datetime import os import json import sys # Scraper 类用于爬取 Facebook 数据 class Scraper: def __init__(self, page_name, number_of_posts, browser="chrome", proxy=None, timeout=60, headless=True): self.__page_name = page_name self.__number_of_posts = number_of_posts self.__browser = browser self.__proxy = proxy self.__timeout = timeout self.__headless = headless self.__current_path = os.path.dirname(os.path.realpath(__file__)) self.__data_dict = {} self.__extracted_post = set() def scrap(self): try: # 初始化 Web 驱动程序 driver = Utilities.get_driver( self.__browser, self.__proxy, self.__headless) Utilities.go_to_url( driver, Pages.get_url(self.__page_name, PagesType.PAGE)) Utilities.__scroll_page( driver, self.__number_of_posts // 10, self.__page_name) # 其余的爬取逻辑在这里... # 将数据保存到文件 self.save_to_file(f'{self.__page_name}_data') except Exception as ex: print(f"发生错误: {str(ex)}") finally: Utilities.__close_driver(driver) def save_to_file(self, filename): if not filename.endswith('.json'): filename += '.json' try: with open(filename, 'w', encoding='utf-8') as file: json.dump(self.__data_dict, file, ensure_ascii=False, indent=4) print(f"数据已保存至 {filename}") except Exception as ex: print(f"保存数据时发生错误: {str(ex)}") # 主程序 if __name__ == "__main__": # 定义页面名称、要爬取的帖子数量和其他参数 page_name = 'example_page' number_of_posts = 100 # 更改为所需的帖子数量 browser = 'chrome' # 如有需要,可以更改浏览器 proxy = None # 如果需要,添加代理配置 timeout = 60 # 根据需要调整超时时间 headless = True # 如果想要查看浏览器操作,设置为 False # 创建 Scraper 实例 scraper = Scraper(page_name, number_of_posts, browser, proxy, timeout, headless) # 调用 scrap 方法开始爬取 scraper.scrap()
常见问题解答(FAQs)
Q1:我如何更改要爬取的页面和帖子数量?
在主程序的page_name
和number_of_posts
变量中设置所需的页面名称和帖子数量。
Q2:如何更改浏览器和代理配置?
您可以在主程序中的browser
和proxy
变量中设置浏览器类型和代理配置,以满足您的需求。
Q3:如何调整超时时间?
在timeout
变量中设置所需的超时时间(以秒为单位)。
Q4:我可以看到浏览器操作吗?
如果要查看浏览器操作,请将headless
变量设置为False
。否则,将其保持为True
以在后台运行。
Q5:数据将保存在哪个文件中?
数据将保存在与页面名称相关的JSON文件中,文件名为page_name_data.json
。
希望这些信息有助于您成功地爬取Facebook数据。如果您有任何其他问题,请随时提问。请注意,爬取Facebook数据时需要遵守法律和Facebook的政策,并仅爬取公开可用的数据。