What would be the total size of all PDB files in RCSB?

Can I traverse/enumerate them one at a time using a Python script without downloading all of them to my local disk?

If YES, what would be the Python script like?


3 Answers 3


The page https://www.wwpdb.org/ftp/pdb-ftp-sites gives the addresses of interest. PDB has an FTP site downloadable via rsync and the latter has a dry run mode.

rsync --port=33444 -rlpt -v -z --dry-run --stats rsync.rcsb.org::ftp_data/structures/divided/pdb/

You get a bunch of folders names and the following:

Number of files: 182479
Number of files transferred: 0
Total file size: 38382243431 bytes
Total transferred file size: 0 bytes
Literal data: 0 bytes
Matched data: 0 bytes
File list size: 3777395
File list generation time: 52.909 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 16
Total bytes received: 3777651

sent 16 bytes  received 3777651 bytes  66861.36 bytes/sec
total size is 38382243431  speedup is 10160.30

So there are 182,479 *.ent.gz in various folders. The total is 38,382,243,431 bytes, which is 38 GB, so not too much. In Python it is easy to iterate across gzip files with the gzip module, so uncompressing them is generally a thing to avoid as it will bloat up greatly. The problem arise when dealing with the density maps, which do take up a lot of space...

Download without saving

The PDBe is easier to for downloading things than the RCSB PDB and the API are much more comprehensive.

Given a list of PDB codes one could

pdbcode : str = '👾👾👾👾'

import requests
r = requests.get(f'https://www.ebi.ac.uk/pdbe/entry-files/download/pdb{pdbcode.lower()}.ent', stream=True)
assert r.status_code == 200, f'something ({r.status_code} is wrong: {r.text}'
pdb_code = r.text
  • $\begingroup$ There is >180,000 PDB entries, see rcsb.org/stats/growth/growth-released-structures $\endgroup$
    – marcin
    Nov 4, 2021 at 8:25
  • $\begingroup$ Thanks for pointing that out! I thought that was suspicious. I forgot the recursive flag. Now the output is 38 GB, which is more reasonable. I don't have a folder to check in PDB format, but I thought it was a lot less... $\endgroup$ Nov 4, 2021 at 8:51
  • $\begingroup$ I'll only add that there are entries (currently, 2375) that have coordinates in the mmCIF format (which is the primary format) and not in the PDB format. MmCIF files are somewhat bigger, the compressed archive is 52GB. $\endgroup$
    – marcin
    Nov 4, 2021 at 10:27
  • $\begingroup$ is rsync a Python builtin ?? $\endgroup$
    – pippo1980
    Jan 17, 2023 at 0:12
  • $\begingroup$ It's a classic Unix command $\endgroup$ Jan 17, 2023 at 11:20

Not Python, but you can do this with BioStructures.jl in Julia:

using BioStructures
pdblist = pdbentrylist()
for pdbid in pdblist
    # Download a file and delete it after use
    downloadpdb(pdbid, format=MMCIF) do fp
        s = read(fp, MMCIF)
        # Do something with the file, e.g. print the cysteine fraction
        nres = countresidues(s, standardselector)
        if nres > 0
            frac = countresidues(s, standardselector, x -> resname(x) == "CYS") / nres
            println(pdbid, "  ", round(frac; digits=2))

If you want to get all the PDB entries you should use the mmCIF format, though it does lead to larger file sizes.


my attempt working as of the 17th January 2023 using RCSB PDB Search API:

import json

# import urllib.parse

import requests

import sys

# data = {"query":{"type":"terminal","service":"text","parameters":{"attribute":"rcsb_entry_container_identifiers.entry_id",
            # "operator":"exists","negation":False}},"return_type":"entry"}

data = {"query":{"type":"terminal","service":"text","parameters":{"attribute":"rcsb_entry_container_identifiers.entry_id",

data = json.dumps(data)

headers = {'content-type': 'application/json'}
url = 'https://search.rcsb.org/rcsbsearch/v2/query?json='

params = {}

risposta = requests.post(url, params=params, data = data, headers=headers)

# print(risposta.status_code,'\n', risposta.content.decode())

rispo = json.loads(risposta.content.decode())

# print(rispo["result_set"], type(rispo["result_set"]), len(rispo["result_set"]))

id_list = []
for i in rispo["result_set"] :

print(id_list, type(id_list) , 'lenght : ', len(id_list), 'size bytes  : ' ,sys.getsizeof(id_list))

you get a huge list :

'2V0H', '2V0G', '2V0F', '2V0E', '2V0D', '370D', '2ULL', '2UKD', '2UGI', '2UDP', '2UCZ', '2UBP', '2UAG', '2TYS', '369D', '368D', '367D', '366D', '2TUN', '2TSS', '2TSR', '2TSY', '365D', '2TRT', '2TRS', '2TS1', '2TRY', '2TRX', '364D', '2TSC', '2TSB', '2TSA', '363D', '2TRC', '2TRA', '2TRM', '2TRH'] 

<class 'list'> lenght :  200069 size bytes  :  1671784

Using the requests GET endpoints :

import requests

import sys

url = 'https://search.rcsb.org/rcsbsearch/v2/query?json=%7B%22query%22%3A+%7B%22type%22%3A+%22terminal%22%2C+%22service%22%3A+%22text%22%2C+%22parameters%22%3A+%7B%22attribute%22%3A+%22rcsb_entry_container_identifiers.entry_id%22%2C+%22operator%22%3A+%22exists%22%2C+%22negation%22%3A+false%7D%7D%2C+%22request_options%22%3A+%7B%22return_all_hits%22%3A+true%7D%2C+%22return_type%22%3A+%22entry%22%7D'

risposta = requests.get(url)


rispo = risposta.json()

id_list = []
for i in rispo["result_set"] :

print(id_list, type(id_list) , 'lenght : ', len(id_list), 'size bytes  : ' ,sys.getsizeof(id_list))




getting as of the 19th January 2023 --> 200375 entries


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.