Error with json VirusTotal API call in python
<p>I need to retrieve the result of VirusTotal scans already performed, providing the hash of the files, without sending the file again.
You can find the documentation of the API <a href="https://www.virustotal.com/it/documentation/public-api/" rel="nofollow noreferrer">here</a>.</p>
<p>I basically need to send a json of this format: <code>{&quot;resource&quot;: &quot;hash&quot;, &quot;apikey&quot;: api}</code>.
I'm using <strong>requests</strong>, it's very useful and it should handle json even without using the <strong>json</strong> or <strong>simplejson</strong> module.</p>
<p>if I send a request like this it works:</p>
<pre><code>r = requests.post(url, data = {&quot;resource&quot;: &quot;dbbe9c39df7c355f970e3a9636fbac04&quot; , &quot;apikey&quot;: &quot;myapikey&quot;}
print(r.json())
</code></pre>
<p>but I have many hashes so I need to generate the json programmatically instead of hardcoding it in the program.</p>
<p>First I tried using a dictionary:
the <strong>api</strong> key doesn't change so I put the assignment out of the loop, instead for the <strong>hash</strong> I loop through a <strong>list</strong> of hashes called <strong>md5</strong>.</p>
<pre><code>params = {}
params[&quot;apikey&quot;] = api
for hash in md5:
    params[&quot;resource&quot;] = hash
</code></pre>
<p>I get a dictionary for every loop that I pass to <strong>requests</strong> for the API call.
The dictionary representing the json is of this format:</p>
<pre><code>{'apikey': myapikey', 'resource': 'hash'}
</code></pre>
<p>The documentation shows <code>resource</code> as first element of the json, instead in my generated dictionary I get the <code>apikey</code> first, anyway if they implement correctly the json standard, order shouldn't matter. Anyway that isn't a valid json format because it contains single quotes, it should contain double quotes. I wanted to avoid using another module but I tried using <code>json</code> or <code>simplejson</code> module for converting the dictionary in a valid json (with double quotes) and it works apparently. I know that requests also has a <code>json =</code> paramenter where you can pass a dictionary and it should encode it as json for you but I'm not sure it worked. Otherwise you can just use the <code>data =</code> paramenter and assign the json to it when you make the request.</p>
<p>If I make a request like this:</p>
<pre><code>params = {}
params[&quot;apikey&quot;] = api
for hash in md5:
    params[&quot;resource&quot;] = hash
    json_params = json.dumps(params)
    r = requests.post(url, data = json_params)
    print(r.json())
</code></pre>
<p>I get this error:</p>
<pre><code>Traceback (most recent call last):
  File &quot;C:/Users/Fabio/PycharmProjects/dfir/requests-try-prova.py&quot;, line 15, in &lt;module&gt;
    print(r.json())
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\requests\models.py&quot;, line 812, in json
    return complexjson.loads(self.text, **kwargs)
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\simplejson\__init__.py&quot;, line 516, in loads
    return _default_decoder.decode(s)
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\simplejson\decoder.py&quot;, line 370, in decode
    obj, end = self.raw_decode(s)
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\simplejson\decoder.py&quot;, line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.scanner.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
</code></pre>
<p>line 15 in my code is represented by <code>print(r.json())</code></p>
<p>if I <code>print(r.text())</code> instead it says <code>TypeError: 'str' object is not callable</code></p>
<hr />
<p>Then I tried a slightly different approach still using the <code>json</code> module without passing a pre-defined dictionary:</p>
<pre><code>for hash in md5:
    r = requests.post(url, data = json.dumps({&quot;resource&quot;: hash, &quot;apikey&quot;: api}))
    print(r.json())
</code></pre>
<p>where <code>hash</code> and <code>api</code> are 2 strings.</p>
<p>I still get the same error:</p>
<pre><code>Traceback (most recent call last):
  File &quot;C:/Users/Fabio/PycharmProjects/dfir/requests-try-prova.py&quot;, line 15, in &lt;module&gt;
    print(r.json())
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\requests\models.py&quot;, line 812, in json
    return complexjson.loads(self.text, **kwargs)
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\simplejson\__init__.py&quot;, line 516, in loads
    return _default_decoder.decode(s)
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\simplejson\decoder.py&quot;, line 370, in decode
    obj, end = self.raw_decode(s)
  File &quot;C:\Users\Fabio\AppData\Local\Programs\Python\Python35\lib\site-packages\simplejson\decoder.py&quot;, line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.scanner.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
</code></pre>
<p>From the error it seems the problem is in getting or decoding the json response, but I wonder if the problem is that the request isn't sent correctly in the first place.
If instead of printing the json response I do <code>print(r.status_code())</code> I get a <strong>403</strong> status.</p>
<p>It's a typical HTTP status that means &quot;<code>Forbidden</code>&quot; and also the Virus Total API documentation says: <code>If you try to perform calls to functions for which you do not have the required privileges an HTTP Error 403 Forbidden is raised</code>.</p>