2024 年使用 Python 抓取 Reddit 的终极指南

对于希望收集见解和训练人工智能模型的企业、研究人员和开发人员来说,Reddit 是一个宝贵数据的金矿。但到了 2023 年,Reddit 对 API 访问收取了巨额费用,打乱了许多人的计划。幸运的是,网页抓取提供了一种更有效、更经济、更灵活的替代方案。在本深入指南中,我们将引导您准确了解如何使用 Python 和 Selenium 从 Reddit 中抓取数据。

2023 年 4 月,Reddit 宣布他们将开始对 API 访问收取高额费用——每 1000 次调用 0.24 美元。对于大多数用例来说,这一更改立即导致 API 成本过高。许多像 Apollo 这样依赖 API 的应用程序被迫关闭。

但 Reddit 上的大量有用数据并没有突然消失或失去价值。人们仍然需要访问它来进行商业智能、科学研究、训练大型语言模型等。网络抓取现在是大规模获取这些数据的最可行和最具吸引力的方法。

与使用官方 API 相比,以下是抓取 Reddit 的一些主要优势:

  1. 节省成本——通过抓取,您可以收集 Reddit 数据,而无需支付高昂的 API 费用。唯一的成本是您自己的计算资源。

  2. 提高灵活性 – 通过抓取,您可以精确定位所需的确切数据,而不受 API 约束的限制。自定义您的抓取工具以提取您想要的字段。

  3. 访问更多数据 – API 通常会限制可用数据的范围。抓取时,您可以访问网站上的任何公共数据,包括未通过官方渠道提供的信息。

因此,在 2024 年的后 API 世界中,网络抓取是从 Reddit 收集数据的明智选择。让我们深入了解如何使用 Python 实现这一点的技术细节!

抓取 Reddit 所需的工具

要学习本教程,请确保您具备以下条件:

  • 已安装 Python 3.7+
  • Python IDE(PyCharm、VS Code 等)
  • Chrome 网络浏览器
  • 用于 Selenium 的 ChromeDriver

我们将使用 Python Selenium 库来自动化 Chrome 浏览器并从 Reddit 抓取数据。 Selenium 是理想的选择,因为它可以呈现 Reddit 页面上常见的动态 JavaScript 内容。

您还需要设置一个虚拟环境来管理 Reddit 抓取项目的依赖项。通过运行以下命令来执行此操作:

python -m venv env 
source env/bin/activate

然后安装必要的Python包:

pip install selenium webdriver-manager

太棒了,你已经准备好了!让我们开始构建 Reddit 抓取工具。

Reddit 抓取分步教程

我们将从 r/technology subreddit 中抓取数据作为示例。但您可以轻松地调整此代码以从任何公共 subreddit 中提取帖子和信息。

第 1 步 – 设置 Selenium

首先,导入所需的 Selenium 模块并将 Chrome 配置为以无头模式运行。这会隐藏浏览器 UI,从而节省资源。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService 
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options

options = Options()
options.headless = True 

driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), 
                          options=options)

第 2 步 – 导航至 Reddit 子版块

指定您要抓取的 Reddit 子版块的 URL。在本例中,我们将获取过去一周有关 r/technology 的热门帖子。

url = "https://www.reddit.com/r/technology/top/?t=week"
driver.get(url)

第 3 步 – 抓取 Subreddit 元数据

Reddit 子页面的顶部包含有用的元数据。让我们抓取名称、描述、创建日期和成员数量。

subreddit = {}

subreddit[‘name‘] = driver.find_element(By.TAG_NAME, ‘h1‘).text

subreddit[‘description‘] = driver.find_element(By.XPATH, 
    "//div[@data-testid=‘DescriptionComment‘]").text

subreddit[‘created‘] = driver.find_element(By.XPATH,
    "//span[contains(text(), ‘Created‘)]/following-sibling::span").text

subreddit[‘members‘] = driver.find_element(By.XPATH, 
    "//div[@id=‘MembershipButton‘]//span[@class=‘_vaFo96phV6L5Hltvwcox‘]").text    

第 4 步 – 抓取帖子数据

接下来,让我们收集 Reddit 子版块中每个帖子的数据。我们将获取热门帖子的标题、作者、点赞数、评论数和目标 URL。

检查 HTML 以查找包含此数据的元素。 Reddit 通过使用随机生成的 CSS 类使其变得棘手。但是我们可以使用语义属性可靠地选择元素,例如data-testid

posts = []

post_elems = driver.find_elements(By.CSS_SELECTOR, 
                                 ‘[data-testid="post-container"]‘)

for post in post_elems:
    post_data = {}

    post_data[‘title‘] = post.find_element(By.TAG_NAME, ‘h3‘).text

    post_data[‘author‘] = post.find_element(By.CSS_SELECTOR, 
        ‘[data-testid="post_author_link"]‘).text

    post_data[‘upvotes‘] = post.find_element(By.XPATH,
        "//div[@data-click-id=‘upvote‘]/following-sibling::div").text

    post_data[‘comments‘] = post.find_element(By.XPATH,
       "//a[@data-click-id=‘comments‘]/span").text

    post_data[‘url‘] = post.find_element(By.CSS_SELECTOR,  
        ‘[data-testid="outbound-link"]‘).get_attribute(‘href‘)

    posts.append(post_data)

将此帖子数据添加到 subreddit 字典中:

subreddit[‘posts‘] = posts

步骤 5 – 输出抓取的数据

最后,将抓取的 subreddit 数据保存到 JSON 文件中,以便于在其他应用程序中使用。漂亮地打印 JSON 以使其更易于阅读。

import json

with open(‘subreddit_data.json‘, ‘w‘) as f:
    json.dump(subreddit, f, indent=4)

把它们放在一起

下面是从 Reddit subreddit 中抓取数据的完整 Python 脚本:

from selenium import webdriver 
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import json

options = Options()
options.headless = True

driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()),
                          options=options)

url = "https://www.reddit.com/r/technology/top/?t=week"
driver.get(url)

subreddit = {}

subreddit[‘name‘] = driver.find_element(By.TAG_NAME, ‘h1‘).text
subreddit[‘description‘] = driver.find_element(By.XPATH, "//div[@data-testid=‘DescriptionComment‘]").text 
subreddit[‘created‘] = driver.find_element(By.XPATH, "//span[contains(text(), ‘Created‘)]/following-sibling::span").text
subreddit[‘members‘] = driver.find_element(By.XPATH, "//div[@id=‘MembershipButton‘]//span[@class=‘_vaFo96phV6L5Hltvwcox‘]").text

posts = []

post_elems = driver.find_elements(By.CSS_SELECTOR, ‘[data-testid="post-container"]‘)

for post in post_elems:
    post_data = {}

    post_data[‘title‘] = post.find_element(By.TAG_NAME, ‘h3‘).text
    post_data[‘author‘] = post.find_element(By.CSS_SELECTOR, ‘[data-testid="post_author_link"]‘).text
    post_data[‘upvotes‘] = post.find_element(By.XPATH, "//div[@data-click-id=‘upvote‘]/following-sibling::div").text  
    post_data[‘comments‘] = post.find_element(By.XPATH, "//a[@data-click-id=‘comments‘]/span").text
    post_data[‘url‘] = post.find_element(By.CSS_SELECTOR, ‘[data-testid="outbound-link"]‘).get_attribute(‘href‘)

    posts.append(post_data)

subreddit[‘posts‘] = posts

with open(‘subreddit_data.json‘, ‘w‘) as f:
    json.dump(subreddit, f, indent=4) 

driver.quit()

运行这个脚本,你会得到一个格式良好的subreddit_data.json包含所有抓取的 Reddit 数据的文件。您现在已经准备好按照您的意愿分析数据了!

大规模抓取 Reddit 的先进技术

上面的基本脚本非常适合抓取单个 Reddit 子版块。但如果你需要收集更大规模的 Reddit 数据,你可能会遇到一些挑战:

  1. 速率限制和 IP 禁令 – 如果您过快地发出过多请求,Reddit 将限制或阻止您的 IP。这可能会让你的刮擦完全停止。

  2. 验证码和其他反机器人措施 – Reddit 采用各种防御措施来阻止机器人和抓取工具。您可能会收到验证码,以防止进一步抓取。

  3. 抓取速度慢——Selenium 可靠,但与其他抓取方法相比相对较慢。抓取大型子版块可能非常耗时。

要大规模抓取 Reddit 数据,您需要解决这些问题。以下是一些提示:

  • 使用轮换代理来避免速率限制和禁令。代理允许您从许多不同的 IP 地址发出请求。自动代理轮换让您可以继续抓取而不会遇到障碍。

寻找来自信誉良好的提供商的快速、安全、符合道德的代理。根据我所做的评论和基准测试,以下是一些值得考虑的顶级代理服务:

  1. 明亮的数据
  2. 皇家IP
  3. 代理卖家
  4. SOAX
  5. 智能代理
  6. 廉价代理
  7. 水代理
  • 使用 2Captcha 或 Anticaptcha 等服务自动处理 CAPTCHA。这些廉价的服务通过 API 为您解决验证码,以便您可以继续进行抓取。

  • 通过并行运行多个抓取器来优化抓取速度和效率。您可以将 Reddit 抓取工具部署在 Docker Swarm 或 Kubernetes 等平台上,以同时运行多个实例并更快地收集数据。

  • 或者,使用专门构建的抓取工具,例如 Bright Data 的抓取浏览器。它会自动为您处理验证码和反抓取措施,同时让您的抓取速度比 Selenium 更快。

总结

由于 API 成本过高,网络抓取现在已成为收集 Reddit 数据的首选方法。借助本指南中介绍的 Python 脚本和技术,您已经做好了充分准备,可以可靠、高效地从 Reddit 中获取大量有价值的数据。

请记住,在抓取数据时始终保持尊重,并避免同时因太多请求而导致 Reddit 服务器超载。使用代理并调整您的抓取率,成为一个好公民。

如果您想跳过自己抓取 Reddit 的棘手过程,您还可以从各种在线来源购买现成的 Reddit 数据集。但是构建自己的抓取工具可以为您提供最大的灵活性和最新的数据。

现在,您拥有了利用 Reddit 上丰富的数据进行业务、研究或编码项目所需的一切。那你还等什么?立即开始使用 Python 抓取 Reddit!