如何用Python抓取GitHub仓库

有没有想过如何抓取GitHub?在这里找到答案!
6 min read
GitHub抓取指南

本教程将涵盖以下内容:

  • 为什么要抓取GitHub仓库?
  • GitHub抓取库和工具
  • 使用Beautiful Soup构建GitHub仓库抓取器

为什么要抓取GitHub仓库?为什么要抓取GitHub仓库?

抓取GitHub仓库有几个原因。最流行的原因是:

  • 跟踪技术趋势:通过跟踪仓库的星标和发布,你可以了解编程语言、框架和库的当前趋势。抓取GitHub可以分析哪些技术正在流行,以监测它们的增长并识别新兴趋势。这些数据可以指导关于技术采用、技能发展和资源分配的决策。
  • 获取丰富的编程知识库:GitHub是开源项目、代码示例和解决方案的宝库。这意味着你可以从平台上收集大量编程知识和最佳实践。这对于教育目的、提高编码技能和理解不同技术的实现方式非常有用。
  • 获得协作开发的见解:仓库提供了开发者如何通过拉取请求、问题和讨论进行协作的见解。通过收集这些数据,你可以研究协作模式,以帮助制定团队合作策略、改进项目管理和完善软件开发流程。

GitHub不是唯一的基于云的git仓库托管平台,还有很多替代品。然而,由于以下原因,它仍然是数据抓取的首选:

  • 庞大的用户群
  • 高用户活跃度
  • 建立的声誉

特别是,GitHub数据对于监控技术趋势、发现库和框架以及改进软件开发过程非常有价值。这些信息在IT世界中保持竞争优势起着关键作用。

GitHub抓取库和工具

Python被广泛认为是进行网页抓取的优秀语言,因为它的语法简单、对开发者友好以及丰富的库。在我们的深入指南中了解更多关于如何使用Python进行网页抓取的内容。

下一步是从广泛的选项中选择最合适的抓取库。为了做出明智的决定,你应该首先在浏览器中探索平台。打开开发者工具,查看GitHub仓库页面所发出的AJAX请求。你会注意到大部分可以忽略。实际上,大多数页面数据都嵌入在服务器返回的HTML文档中。

这意味着一个用于向服务器发送HTTP请求的库与一个HTML解析器结合就足够完成任务。因此,你应该选择:

  • Requests:Python生态系统中最流行的HTTP客户端库。它简化了发送HTTP请求和处理相应响应的过程。
  • Beautiful Soup:一个全面的HTML和XML解析库。它提供了强大的DOM导航和数据提取API,用于网页抓取。

借助RequestsBeautiful Soup,你可以有效地使用Python进行GitHub抓取。让我们深入了解如何实现这一目标!

使用Beautiful Soup构建GitHub仓库抓取器

按照这一步步教程,学习如何用Python抓取GitHub。想跳过整个编码和抓取过程吗?购买GitHub数据集

步骤1:Python项目设置

在开始之前,请确保你满足以下先决条件:

现在你已经具备了在Python中设置项目的所有必要条件!

在终端中运行以下命令,创建一个github-scraper文件夹并使用Python虚拟环境初始化它:

mkdir github-scraper
cd github-scraper
python -m venv env

在Windows上,运行以下命令来激活环境:

env\Scripts\activate.ps1

在Linux或macOS上,执行:

./env/bin/activate

然后,在项目文件夹中添加一个scraper.py文件,其中包含以下行:

print('Hello World!')

现在,你的GitHub抓取器只打印“Hello World!”但它很快就会包含从公共仓库中提取数据的逻辑。

你可以使用以下命令启动脚本:

python scraper.py

如果一切顺利,它应该在终端中打印以下信息:

Hello World!

现在你知道它可以正常工作了,打开你喜欢的Python IDE中的项目文件夹。

太棒了!准备好编写一些Python代码吧。

步骤2:安装抓取库

如前所述,Beautiful SoupRequests帮助你在GitHub上进行网页抓取。在激活的虚拟环境中,执行以下命令将它们添加到项目的依赖项中:

pip install beautifulsoup4 requests

清空scraper.py,然后用以下代码行导入这两个包:

import requests
from bs4 import BeautifulSoup

确保你的Python IDE没有报告任何错误。你可能会收到一些未使用的导入警告。忽略它们,因为你即将使用这些抓取库来提取GitHub上的仓库数据!

步骤3:下载目标页面

选择一个你想要从中提取数据的GitHub仓库。在本指南中,你将学习如何抓取luminati-proxy仓库。请记住,任何其他仓库都可以,因为抓取逻辑是相同的。

目标页面在浏览器中的样子如下:

GitHub仓库选择指南

将目标页面的URL存储在一个变量中:

url = 'https://github.com/luminati-io/luminati-proxy'

然后,用requests.get()下载页面:

page = requests.get(url)

在后台,requests向该URL发送一个HTTP GET请求,并将服务器生成的响应保存在page变量中。你应该关注的是它的text属性。这包含了与目标网页关联的HTML文档。用一个简单的print指令来验证:

print(page.text)

运行抓取器,你应该在终端中看到:

<!DOCTYPE html>
<html lang="en" data-color-mode="dark" data-light-theme="light" data-dark-theme="dark"  data-a11y-animated-images="system" data-a11y-link-underlines="false">
      <head>
        <meta charset="utf-8">
      <link rel="dns-prefetch" href="https://github.githubassets.com">
      <link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
      <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
      <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
      <link rel="preconnect" href="https://github.githubassets.com" crossorigin>
      <link rel="preconnect" href="https://avatars.githubusercontent.com">
<!-- Omitted for brevity... -->
Awesome! Let’s now learn how to parse this

太棒了!现在让我们学习如何解析这些HTML文档。

步骤4:解析HTML文档

要解析上面检索到的HTML文档,将其传递给Beautiful Soup

soup = BeautifulSoup(page.text, 'html.parser')

BeautifulSoup()构造函数接受两个参数:

  • 包含HTML内容的字符串:这里存储在page.text变量中。
  • Beautiful Soup将使用的解析器:“html.parser”是Python内置HTML解析器的名称。

BeautifulSoup()将解析HTML并返回一个可探索的树结构。详细来说,soup变量提供了有效的方法来选择DOM树中的元素,例如:

  • find():返回与传递的选择策略匹配的第一个HTML元素。
  • find_all():返回与输入选择策略匹配的HTML元素列表。
  • select_one():返回与传递的CSS选择器匹配的第一个HTML元素。
  • select():返回与输入CSS选择器匹配的HTML元素列表。

注意,这些方法也可以在树中的单个节点上调用。除了这些方法外,Beautiful Soup节点对象还公开了:

  • find_next_sibling():返回元素的兄弟节点中与给定CSS选择器匹配的第一个HTML节点。
  • find_next_siblings():返回元素的兄弟节点中与传递的CSS选择器匹配的所有HTML节点。

有了这些功能,你已经准备好抓取GitHub了。让我们看看怎么做!

步骤5:熟悉目标页面

在编码之前,还有一个重要步骤要完成。从站点抓取数据是关于选择感兴趣的HTML元素并从中提取数据。定义一个有效的选择策略并不总是容易的,你必须花一些时间来分析你的目标网页的结构。

因此,在浏览器中打开GitHub目标页面,并熟悉它。右键点击并选择“检查”以打开开发者工具:

使用开发者工具检查GitHub页面

在HTML代码中深入挖掘,你会注意到该站点没有用唯一的类或属性限定很多元素。因此,通常很难导航到所需元素,你可能需要通过兄弟节点以一种棘手的方式进行操作。

别担心。为GitHub制定有效的选择策略可能并不容易,但也不是不可能。继续在开发者工具中检查页面,直到你感觉准备好抓取它!

步骤6:提取仓库数据

目标是从GitHub仓库中提取有用的数据,如星标、描述、最新提交等。因此,你需要初始化一个Python字典来跟踪这些数据。将以下代码添加到你的代码中:

repo = {}

首先,检查名称元素:

初始化用于提取仓库数据的Python字典

注意它具有一个独特的itemprop="name"属性。选择它并用以下代码提取其文本内容:

name_html_element = soup.select_one('[itemprop="name"]')name = name_html_element.text.strip()

给定一个Beautiful Soup节点,用get_text()方法来访问其文本内容。

如果你在调试器中检查name_html_element.text,你会看到:

\nluminati-proxy\n

GitHub文本字段往往包含空格和换行符。用Python的strip()函数来删除它们。

在仓库名称下方,有一个分支选择器:

注意没有简单的方法来选择存储主分支名称的HTML元素。你可以选择.octicon-git-branch节点,然后在其兄弟节点中查找目标span

git_branch_icon_html_element = soup.select_one('.octicon-git-branch')
main_branch_html_element = git_branch_icon_html_element.find_next_sibling('span')
main_branch = main_branch_html_element.get_text().strip()

通过图标到达感兴趣的元素的模式在GitHub上非常有效。在本节中,你会看到它被多次使用。

现在,关注分支头:

通过GitHub中的兄弟元素选择主分支名称
通过GitHub中的兄弟元素选择主分支名称

用以下代码提取最新提交时间:

relative_time_html_element = boxheader_html_element.select_one('relative-time')
latest_commit = relative_time_html_element['datetime']

给定一个节点,你可以像在Python字典中一样访问其HTML属性。

本节中的另一个重要信息是提交数量:

从GitHub提取最新提交时间和提交数量

用前面描述的图标模式收集它:

history_icon_html_element = boxheader_html_element.select_one('.octicon-history')
commits_span_html_element = history_icon_html_element.find_next_sibling('span')
commits_html_element = commits_span_html_element.select_one('strong')
commits = commits_html_element.get_text().strip().replace(',', '')

注意find_next_sibling()只能访问顶级兄弟节点。要选择它们的子节点之一,你必须首先获取兄弟元素,然后调用select_one(),如上所示。

由于GitHub上超过一千的数字包含逗号,用Python的replace()方法删除它。

接下来,关注右侧的信息框:

使用图标模式从GitHub提取提交数量

用以下代码选择它:

bordergrid_html_element = soup.select_one('.BorderGrid')

检查描述元素:

选择并检查GitHub上的描述元素

再次通过兄弟节点选择它:

about_html_element = bordergrid_html_element.select_one('h2')
description_html_element = about_html_element.find_next_sibling('p')
description = description_html_element.get_text().strip()

然后,应用图标模式来检索仓库的星标、观察者和分叉数量。

提取仓库描述并在GitHub上应用图标模式获取统计数据

关注图标,然后是它们的文本兄弟节点:

star_icon_html_element = bordergrid_html_element.select_one('.octicon-star')
stars_html_element = star_icon_html_element.find_next_sibling('strong')
stars = stars_html_element.get_text().strip().replace(',', '')

eye_icon_html_element = bordergrid_html_element.select_one('.octicon-eye')
watchers_html_element = eye_icon_html_element.find_next_sibling('strong')
watchers = watchers_html_element.get_text().strip().replace(',', '')

fork_icon_html_element = bordergrid_html_element.select_one('.octicon-repo-forked')
forks_html_element = fork_icon_html_element.find_next_sibling('strong')
forks = forks_html_element.get_text().strip().replace(',', '')

干得好!你刚刚抓取了一个GitHub仓库。

步骤7:抓取readme

另一个需要提取的重要信息是README.md文件。这是一个可选的文本文件,描述了GitHub仓库并解释了如何使用代码。

如果你点击README.md文件,然后点击“原始”按钮,你将被重定向到以下URL:

https://raw.githubusercontent.com/luminati-io/luminati-proxy/master/README.md
提取星标、观察者和分叉数量并访问GitHub上的README.md

因此可以推断,GitHub仓库的readme文件的URL遵循以下格式:

https://raw.githubusercontent.com/<repo_id>/<repo_main_branch>/README.md

由于你在main_branch变量中存储了<repo_main_branch>信息,你可以用Python的f字符串来编程构建这个URL:

readme_url = f'https://raw.githubusercontent.com/luminati-io/luminati-proxy/{main_branch}/README.md'

然后,用requests来检索readme的原始Markdown内容:

readme_url = f'https://raw.githubusercontent.com/luminati-io/luminati-proxy/{main_branch}/README.md'
readme_page = requests.get(readme_url)

readme = None
# if there is a README.md file
if readme_page.status_code != 404:
    readme = readme_page.text

注意404检查,以避免在仓库没有readme文件时存储GitHub的404页面内容。

步骤8:存储抓取的数据

不要忘记将抓取的数据变量添加到repo字典中:

repo['name'] = name
repo['latest_commit'] = latest_commit
repo['commits'] = commits
repo['main_branch'] = main_branch
repo['description'] = description
repo['stars'] = stars
repo['watchers'] = watchers
repo['forks'] = forks
repo['readme'] = readme

print(repo)来确保数据提取过程按预期工作。运行Python GitHub抓取器,你将得到:

{'name': 'luminati-proxy', 'latest_commit': '2023-08-09T08:25:15Z', 'commits': '1079', 'main_branch': 'master', 'description': 'Luminati HTTP/HTTPS Proxy manager', 'stars': '645', 'watchers': '55', 'forks': '196', 'readme': '# Proxy manager\n\n (omitted for brevity...)'}

太棒了!你知道如何抓取GitHub了!

步骤9:将抓取的数据导出为JSON

最后一步是使收集的数据更容易分享、阅读和分析。最好的方法是将数据导出为一种人类可读的格式,如JSON:

import json

# ...

with open('repo.json', 'w') as file:
    json.dump(repo, file, indent=4)

从Python标准库中导入json,用open()初始化一个repo.json文件,最后用json.dump()填充它。查看我们的指南,了解更多关于如何在Python中解析JSON的内容。

完美!是时候看看整个GitHub Python抓取器了。

步骤10:把所有东西放在一起

这是完整的scraper.py文件的样子:

import requests
from bs4 import BeautifulSoup
import json

# the URL of the target repo to scrape
url = 'https://github.com/luminati-io/luminati-proxy'

# download the target page
page = requests.get(url)
# parse the HTML document returned by the server
soup = BeautifulSoup(page.text, 'html.parser')

# initialize the object that will contain
# the scraped data
repo = {}

# repo scraping logic
name_html_element = soup.select_one('[itemprop="name"]')
name = name_html_element.get_text().strip()

git_branch_icon_html_element = soup.select_one('.octicon-git-branch')
main_branch_html_element = git_branch_icon_html_element.find_next_sibling('span')
main_branch = main_branch_html_element.get_text().strip()

# scrape the repo history data
boxheader_html_element = soup.select_one('.Box .Box-header')

relative_time_html_element = boxheader_html_element.select_one('relative-time')
latest_commit = relative_time_html_element['datetime']

history_icon_html_element = boxheader_html_element.select_one('.octicon-history')
commits_span_html_element = history_icon_html_element.find_next_sibling('span')
commits_html_element = commits_span_html_element.select_one('strong')
commits = commits_html_element.get_text().strip().replace(',', '')

# scrape the repo details in the right box
bordergrid_html_element = soup.select_one('.BorderGrid')

about_html_element = bordergrid_html_element.select_one('h2')
description_html_element = about_html_element.find_next_sibling('p')
description = description_html_element.get_text().strip()

star_icon_html_element = bordergrid_html_element.select_one('.octicon-star')
stars_html_element = star_icon_html_element.find_next_sibling('strong')
stars = stars_html_element.get_text().strip().replace(',', '')

eye_icon_html_element = bordergrid_html_element.select_one('.octicon-eye')
watchers_html_element = eye_icon_html_element.find_next_sibling('strong')
watchers = watchers_html_element.get_text().strip().replace(',', '')

fork_icon_html_element = bordergrid_html_element.select_one('.octicon-repo-forked')
forks_html_element = fork_icon_html_element.find_next_sibling('strong')
forks = forks_html_element.get_text().strip().replace(',', '')

# build the URL for README.md and download it
readme_url = f'https://raw.githubusercontent.com/luminati-io/luminati-proxy/{main_branch}/README.md'
readme_page = requests.get(readme_url)

readme = None
# if there is a README.md file
if readme_page.status_code != 404:
    readme = readme_page.text

# store the scraped data
repo['name'] = name
repo['latest_commit'] = latest_commit
repo['commits'] = commits
repo['main_branch'] = main_branch
repo['description'] = description
repo['stars'] = stars
repo['watchers'] = watchers
repo['forks'] = forks
repo['readme'] = readme

# export the scraped data to a repo.json output file
with open('repo.json', 'w') as file:
    json.dump(repo, file, indent=4)

在不到100行代码中,你可以构建一个网络蜘蛛来收集仓库数据。

用以下命令运行脚本:

python scraper.py

等待抓取过程完成,你将在项目的根文件夹中找到一个repo.json文件。打开它,你会看到:

{
    "name": "luminati-proxy",
    "latest_commit": "2023-08-09T08:25:15Z",
    "commits": "1079",
    "main_branch": "master",
    "description": "Luminati HTTP/HTTPS Proxy manager",
    "stars": "645",
    "watchers": "55",
    "forks": "196",
    "readme": "# Proxy manager\n\n[![dependencies Status](https://david-dm.org/luminati-io/luminati-proxy/status.svg)](https://david-dm.org/luminati-io/luminati-proxy)\n[![devDependencies Status](https://david-dm.org/luminati-io/luminati-proxy/dev-status.svg)](https://david-dm..."
}

恭喜你!你从网页中的原始数据开始,现在在JSON文件中拥有半结构化数据。你刚刚学会了如何用Python构建一个GitHub仓库抓取器!

结论

在这份逐步指南中,你理解了构建GitHub仓库抓取器的原因。具体来说,你在一个指导性的教程中学习了如何抓取GitHub。正如这里所示,这只需要几行代码。

同时,越来越多的网站采用了反抓取技术。这些技术可以通过IP禁封和速率限制来识别和阻止请求,防止你的抓取器访问网站。避免这些技术的最好方法是代理。探索Bright Data的丰富顶级代理服务专用GitHub代理

Bright Data控制着市场上最大的、最可靠的抓取导向的代理网络之一,为财富500强公司和超过2万名客户提供服务。其全球代理网络包括:

总的来说,Bright Data是市场上最大的、最可靠的抓取导向的代理网络之一。与我们的销售代表联系,看看Bright Data的哪种产品最适合你的需求。