116 lines
4.2 KiB
Python
116 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import re
|
|
import sys
|
|
import requests
|
|
from bs4 import BeautifulSoup
|
|
|
|
# The target URLs. You can freely add any new Intel GPU driver documentation links here.
|
|
URLS = [
|
|
"https://dgpu-docs.intel.com/overview/supported-hardware/xe-driver-gpus.html"
|
|
]
|
|
|
|
def get_filename_from_url(url):
|
|
"""
|
|
Derives a clean .ids filename from the URL slug.
|
|
Examples:
|
|
.../legacy-gpus.html -> legacy.ids
|
|
.../i915-driver-gpus.html -> i915.ids
|
|
.../xe2-driver-gpus.html -> xe2.ids (for future updates)
|
|
"""
|
|
slug = url.split('/')[-1].replace('.html', '')
|
|
for suffix in ['-driver-gpus', '-gpus', '-driver']:
|
|
if slug.endswith(suffix):
|
|
return slug[:-len(suffix)] + '.ids'
|
|
return slug + '.ids'
|
|
|
|
def extract_pci_ids(url):
|
|
"""
|
|
Scrapes the URL, dynamically locates the PCI ID column, and extracts
|
|
unique, clean 4-digit hexadecimal PCI IDs.
|
|
"""
|
|
print(f"Scraping: {url}")
|
|
headers = {
|
|
'User-Agent': 'Mozilla/5.0 (NixOS Intel-detect Tool)'
|
|
}
|
|
|
|
try:
|
|
response = requests.get(url, headers=headers, timeout=15)
|
|
response.raise_for_status()
|
|
except requests.RequestException as e:
|
|
print(f"Error fetching {url}: {e}", file=sys.stderr)
|
|
return []
|
|
|
|
soup = BeautifulSoup(response.text, 'html.parser')
|
|
pci_ids = set()
|
|
|
|
tables = soup.find_all('table')
|
|
if not tables:
|
|
print(f"Warning: No data tables found on {url}", file=sys.stderr)
|
|
return []
|
|
|
|
for table in tables:
|
|
# 1. Inspect headers to locate the exact index of the PCI/Device ID column
|
|
thead = table.find('thead')
|
|
if thead:
|
|
headers_text = [th.get_text(strip=True).lower() for th in thead.find_all('th')]
|
|
else:
|
|
first_tr = table.find('tr')
|
|
headers_text = [th.get_text(strip=True).lower() for th in first_tr.find_all(['th', 'td'])] if first_tr else []
|
|
|
|
pci_col_idx = -1
|
|
for idx, text in enumerate(headers_text):
|
|
if any(kwd in text for kwd in ['pci', 'device id', 'dev id', 'did']):
|
|
pci_col_idx = idx
|
|
break
|
|
|
|
# Soft fallback: check if header just contains 'id'
|
|
if pci_col_idx == -1:
|
|
for idx, text in enumerate(headers_text):
|
|
if 'id' in text:
|
|
pci_col_idx = idx
|
|
break
|
|
|
|
# 2. Iterate through rows and pull data
|
|
tbody = table.find('tbody')
|
|
rows = tbody.find_all('tr') if tbody else table.find_all('tr')
|
|
|
|
for row in rows:
|
|
cells = row.find_all('td')
|
|
if not cells:
|
|
continue
|
|
|
|
# Extract strictly from the matching column if found
|
|
if pci_col_idx != -1 and pci_col_idx < len(cells):
|
|
cell_text = cells[pci_col_idx].get_text(strip=True)
|
|
# Matches standalone 4-char hex strings, ignoring optional '0x' prefix
|
|
matches = re.findall(r'\b(?:0x)?([0-9a-fA-F]{4})\b', cell_text)
|
|
for match in matches:
|
|
pci_ids.add(match.lower())
|
|
else:
|
|
# Absolute fallback: Scan all cells but guard heavily against false-positive string matches
|
|
for cell in cells:
|
|
cell_text = cell.get_text(strip=True)
|
|
matches = re.findall(r'\b(?:0x)?([0-9a-fA-F]{4})\b', cell_text)
|
|
for match in matches:
|
|
# Only accept if the cell text is short (an ID cell) or explicitly contains 0x
|
|
if len(cell_text) < 15 or '0x' in cell_text.lower():
|
|
pci_ids.add(match.lower())
|
|
|
|
return sorted(list(pci_ids))
|
|
|
|
def main():
|
|
for url in URLS:
|
|
filename = get_filename_from_url(url)
|
|
ids = extract_pci_ids(url)
|
|
|
|
if ids:
|
|
with open(filename, 'w', encoding='utf-8') as f:
|
|
for pci_id in ids:
|
|
f.write(f"{pci_id}\n")
|
|
print(f"-> Successfully saved {len(ids)} IDs to {filename}\n")
|
|
else:
|
|
print(f"-> No IDs extracted for {url}. Skipping file write.\n")
|
|
|
|
if __name__ == "__main__":
|
|
main() |