The ecmwf-opendata package handles the naming convention and downloads for you, the simplest route for most users. A set of Jupyter notebooks demonstrates it.
Files follow one pattern. Replace [ROOT] with a location from Where to get it on the overview page, and set stream, type, step and the run time from the What's available table.
Each GRIB file has a matching index file: swap the .grib2 extension for .index. The index is text, one JSON record per field, each carrying _offset and _length — the byte range of that field. Use those to fetch a single field with an HTTP byte-range request.
1. Download the index and find the record for 2m temperature ("param": "2t"):