Last active
March 30, 2023 09:33
-
-
Save kphanipavan/6b2d52b0e8c115f6834817a32049ba24 to your computer and use it in GitHub Desktop.
Script to scrape Nvidia's website to get the latest Nvidia driver available for a given GPU.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
""" | |
from typing import List | |
import subprocess as sp | |
import re | |
import requests as req | |
from bs4 import BeautifulSoup as bs | |
from random_user_agent.user_agent import UserAgent | |
from random_user_agent.params import SoftwareName, OperatingSystem | |
""" | |
This program requires the following python packages | |
typing : Builtin: Used for type annotations for some functions. | |
subprocess: Builtin: Required to run bash commands for listing devices. | |
re : Builtin: Required for slicing text at various locations. | |
requests : Addon : Used for downloading web pages. | |
bs4 : Addon : Package used for traversing the downloaded webpage. | |
random_user_agent: Addon: Randomising user agent for requests pakage. | |
""" | |
lspciRegex = r'(.*?)\s(VGA|3D).*\[\S{4}:(\S{4})\]' | |
latestTxt = "https://download.nvidia.com/XFree86/Linux-x86_64/latest.txt" | |
latestVerRegex = r"([\d.]*) " | |
supportedGPUList = "https://download.nvidia.com/XFree86/Linux-x86_64/{}/README/supportedchips.html" | |
class NvidiaGPU: | |
""" | |
Custom class made for defining an Nvidia GPU. | |
Attributes: | |
pciBus: str: required: PCI bus location where the said GPU is located, ex: "01:00.0" | |
cont : str: required: States whether the GPU has a VGA or a 3D controller | |
devID : str: required: GPU device ID used for searching from the downloaded GPU list. | |
driverVer: str : Driver version assigned after searching the GPU driver list. | |
searchedName: str : Name as defined by the downloaded GPU list. | |
Custom Methods: | |
__str__: Overridden menthod, useful when printing an NvidiaGPU object. | |
""" | |
def __init__(self, pciBus: str, controller: str, deviceID: str): | |
self.pciBus = pciBus | |
self.cont = controller | |
self.devID = deviceID.upper() | |
self.driverVer = '' | |
self.searchedName = '' | |
def __str__(self) -> str: | |
if self.driverVer == '': | |
return 'Nvidia GPU with {} controller located at {} with device ID {}'\ | |
.format(self.cont, self.pciBus, self.devID) | |
else: | |
return 'GPU labeled {} with device ID {} found as a {} controller at {} has a latest driver version {}'\ | |
.format(self.searchedName, self.devID, self.cont, self.pciBus, self.driverVer) | |
def getGPUList() -> List[NvidiaGPU]: | |
""" | |
Function to get a list of NvidiaGPU objects, each containing info about the Nvidia GPUs found on the device this script is run on. | |
""" | |
lspciOutput = list(filter(None, sp.run(['lspci -nn | grep -E \'(3[Dd] | [Vv][Gg][Aa])\' | grep -i nvidia'], | |
shell=True, text=True, capture_output=True, check=True) | |
.stdout.split('\n'))) | |
devs = [] | |
for dev in lspciOutput: | |
devData = re.search(lspciRegex, dev).groups() | |
if len(devData) == 2: | |
devData.insert(1, 'Unknown') | |
devs.append(NvidiaGPU(*devData)) | |
return devs | |
def getRandomUA() -> str: | |
""" | |
Get a randomized User Agent as a string. | |
""" | |
return UserAgent(software_names=[SoftwareName.CHROME.value, SoftwareName.FIREFOX.value, | |
SoftwareName.OPERA.value, SoftwareName.BRAVE.value, SoftwareName.EPIPHANY.value, SoftwareName.CHROMIUM.value], | |
operating_systems=[OperatingSystem.LINUX.value, OperatingSystem.UNIX.value]).get_random_user_agent() | |
def getDriverVersion(useGPUOnDevice: bool = True, customGPUs: List[NvidiaGPU] = None): | |
""" | |
Function to return a list of NvidiaGPU objects containing the device info | |
as well as the latest driver available for the device. | |
The objects also contain the Device Name as stated on the Nvidia Database. | |
""" | |
devices = [] | |
if useGPUOnDevice: | |
devices = getGPUList() | |
if customGPUs: | |
devices.extend(customGPUs) | |
ua = getRandomUA() | |
latestData = req.get(latestTxt, headers={'User-Agent': ua}).text | |
latestVer = re.search(latestVerRegex, latestData).group(0).strip() | |
supportedGPUPage = req.get(supportedGPUList.format( | |
latestVer), headers={'User-Agent': getRandomUA()}).text | |
bsData = bs(supportedGPUPage, 'html.parser') | |
searchedDevices = [] | |
tableTag = bsData.find_all('h3')[0] | |
currentVersion = latestVer | |
while True: | |
tableTag = tableTag.findNext('tbody') | |
for i in tableTag.children: | |
if i == '\n': | |
continue | |
else: | |
tempdev = [] | |
for j in i.children: | |
if j == '\n': | |
pass | |
else: | |
tempdev.append(j.text) | |
for j in devices: | |
if j.devID == tempdev[1][:4]: | |
tempj = j | |
tempj.driverVer = currentVersion | |
tempj.searchedName = tempdev[0] | |
searchedDevices.append(tempj) | |
devices.remove(j) | |
else: | |
pass | |
while True: | |
try: | |
if 'driver supports the following set of' in tableTag.findNext('p').text: | |
tableTag = tableTag.findNext('p') | |
break | |
else: | |
tableTag = tableTag.findNext('p') | |
except AttributeError as noMorePeesFound: | |
break | |
if len(devices) == 0: | |
break | |
currentVersion = re.search( | |
r'The[\n\s](.*)[\n\s]driver', tableTag.text).group(1) | |
tableTag = tableTag.findNext('table') | |
return searchedDevices | |
if __name__ == '__main__': | |
for device in getDriverVersion(): | |
print(device) | |
""" | |
This program follows the API restrictions found at https://download.nvidia.com/robots.txt | |
This program is originally written by Phani Pavan K <[email protected]>. In case of a fork, please add your name and email below, which can help track the evolution of said forks. | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Update 1, 30th March 2023:
Change in line 56, capitalizes device ID, fails if it isn't.