<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gug</title>
    <description>The latest articles on DEV Community by Gug (@gug_31c7ba64d1c563490bc42).</description>
    <link>https://dev.to/gug_31c7ba64d1c563490bc42</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3735556%2Fd071ff1a-199f-41d8-8cba-477b1922acae.png</url>
      <title>DEV Community: Gug</title>
      <link>https://dev.to/gug_31c7ba64d1c563490bc42</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gug_31c7ba64d1c563490bc42"/>
    <language>en</language>
    <item>
      <title>Fetching and Storing CVE Data from NVD API using Python</title>
      <dc:creator>Gug</dc:creator>
      <pubDate>Tue, 27 Jan 2026 15:41:30 +0000</pubDate>
      <link>https://dev.to/gug_31c7ba64d1c563490bc42/fetching-and-storing-cve-data-from-nvd-api-using-python-4dog</link>
      <guid>https://dev.to/gug_31c7ba64d1c563490bc42/fetching-and-storing-cve-data-from-nvd-api-using-python-4dog</guid>
      <description>&lt;p&gt;import requests&lt;br&gt;
import time&lt;br&gt;
from database import get_db_connection&lt;br&gt;
import json&lt;/p&gt;

&lt;h1&gt;
  
  
  NVD API URL
&lt;/h1&gt;

&lt;p&gt;BASE_URL = "&lt;a href="https://services.nvd.nist.gov/rest/json/cves/2.0" rel="noopener noreferrer"&gt;https://services.nvd.nist.gov/rest/json/cves/2.0&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;def fetch_and_store_cves(total_to_fetch=100):&lt;br&gt;
    # NOTE: Fetching ALL NVD data takes hours. For the test, we fetch a subset (e.g., 2000 records).&lt;br&gt;
    # Remove 'total_to_fetch' limit for full production sync.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;conn = get_db_connection()
cursor = conn.cursor()   #Creates a "cursor" object. This is used to execute SQL commands (like INSERT) against the database connection.

start_index = 0
results_per_page = 2000  # Max allowed by NVD is usually 2000

print("Starting synchronization...")

while start_index &amp;lt; total_to_fetch:
    params = {
        'startIndex': start_index,
        'resultsPerPage': results_per_page
    }

    try:
        print(f"Fetching batch starting at {start_index}...")
        response = requests.get(BASE_URL, params=params, timeout=30)

        if response.status_code != 200:
            print(f"Error: API returned {response.status_code}")
            break

        data = response.json()
        vulnerabilities = data.get('vulnerabilities', [])

        if not vulnerabilities:
            break # No more data

        for item in vulnerabilities:
            cve = item['cve']
            cve_id = cve['id']
            source_id = cve.get('sourceIdentifier', 'N/A')
            published = cve.get('published', '')
            last_modified = cve.get('lastModified', '')
            status = cve.get('vulnStatus', '')

            # Extract Score (Try V3 first, then V2)
            score = None
            metrics = cve.get('metrics', {})
            if 'cvssMetricV31' in metrics:
                score = metrics['cvssMetricV31'][0]['cvssData']['baseScore']
            elif 'cvssMetricV2' in metrics:
                score = metrics['cvssMetricV2'][0]['cvssData']['baseScore']

            # Insert or Replace (Deduplication)
            cursor.execute('''
                INSERT OR REPLACE INTO cves 
                (id, sourceIdentifier, published, lastModified, vulnStatus, baseScore, details)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ''', (cve_id, source_id, published, last_modified, status, score, json.dumps(cve)))

        conn.commit()
        start_index += results_per_page

        # Sleep to avoid rate limiting (NVD is strict)
        time.sleep(2)

    except Exception as e:
        print(f"Exception occurred: {e}")
        break

conn.close()
print("Synchronization Complete.")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == "&lt;strong&gt;main&lt;/strong&gt;":&lt;br&gt;
    # Fetch 2000 records for the assessment demo&lt;br&gt;
    fetch_and_store_cves(total_to_fetch=2000)&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>cve</category>
    </item>
  </channel>
</rss>
