How can I upload a PIL image object to Imgur API on python3? - imgur

I am getting the following error when I try to upload an image to imgur api.
b'{"data":{"error":"Invalid URL (<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=1600x6495 at 0x10E726050>)","request":"\\/3\\/upload","method":"POST"},"success":false,"status":400}'
My code is given below. Client ID is redacted.
#!/usr/bin/env python3
import io
from PIL import Image
import requests
import json
import base64
url = "http://www.tallheights.com/wp-content/uploads/2016/06/background_purple.jpg"
r = requests.get(url)
image = Image.open(io.BytesIO(r.content))
imagestring = str(image)
url = 'https://api.imgur.com/3/upload'
body = {'type':'file','image': imagestring , 'name' : 'abc.jpeg'}
headers = {'Authorization': 'Client-ID <redacted>'}
req = requests.post(url, data=body, headers=headers)
print (req.content)
My code is in Python3 and I am not using the official client library provided by Imgur for two reasons.
The library provides me with only two options - a) Upload by specifying a URL and b) Upload from a local file. In my case, the image I want to upload is neither. It is an image processed by PIL, existing as a PIL object in memory. I do not want to use file system for this particular implementation.
A simple POST request to the API would do the job for me and I want to avoid the dependency to the library and keep the package as light as possible.

This Works:
# imports
import requests
import io
from PIL import Image
# Get Image from request
img_response = requests.get(
"https://encrypted-tbn0.gstatic.com/images? q=tbn%3AANd9GcTVYP3ZsF72FSKPzxJghYkjz_-a1op7YxBK45O0Y4nTjAQ7PZKD"
)
# Some Pillow Resizing
img = Image.open(io.BytesIO(img_response.content))
img_width, img_height = img.size
crop = min(img.size)
square_img = img.crop(
(
(img_width - crop) // 2,
(img_height - crop) // 2,
(img_width + crop) // 2,
(img_height + crop) // 2,
)
) # Square Image is of type Pil Image
imgByteArr = io.BytesIO()
square_img.save(imgByteArr, format="PNG")
imgByteArr = imgByteArr.getvalue()
url = "https://api.imgur.com/3/image"
payload = {"image": imgByteArr}
headers = {"Authorization": "Client-ID xxxxxxxxx"}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text.encode("utf8"))

Checking the API documentation, it seems like the /upload part of your url was changed to /image.
https://apidocs.imgur.com/?version=latest#c85c9dfc-7487-4de2-9ecd-66f727cf3139
(see the "sample request" on the right side)
But it seems like this is all deprecated in general and the information on the very same page contradicts itself.

Related

How to receive an image from a POST request on Google Cloud Function with Python?

I'm struggling to reassemble an image sent via a POST request to a GCP Cloud Function.
I've looked at advice here about how to package a file with POST request.
I would like the function to reconstruct the image from bytes for further processing, everytime I send the request I get 'Failure' back. Any help would be really appreciated!
### client_side.py
import requests
url = 'https://region-project.cloudfunctions.net/function' # Generic GCP functions URL
files = {'file': ('my_image.jpg', open('my_image.jpg', 'rb').read(), 'application/octet-stream')}
r = requests.post(url, files=files)
### gcp_function.py
from io import BytesIO
def handler(request):
try:
incoming = request.files.get('file')
bytes = BytesIO(incoming)
image = open_image(bytes)
message = 'Success'
except:
message = 'Failure'
return message
Sorted it.
Needed the read method to convert FileStorage Object to bytes.
### gcp_function.py
from io import BytesIO
import logging
def handler(request):
try:
incoming = request.files['file'].read()
bytes = BytesIO(incoming)
image = open_image(bytes)
message = 'Success'
except Exception as e:
message = 'Failure'
logging.critical(str(e))
return message

Can't send proper post request with file using python3 requests

I was using Postman to send post request like on the screenshot
Now I need to implement it in python. This is what i've got for now:
import requests
data = {"sendRequest": {"apiKey": 12345, "field1": "field1value"}}
files = {"attachment": ("file.txt", open("file.txt", "rb"))}
headers = {"Content-type": "multipart/form-data"}
response = requests.post(endpoint, data=data, headers=headers, files=files)
But still it's not working - server doesn't accept it as valid request. I've tried more combinations but without any results and I really couldn't find a solution.
I need this request to be exactly like that one in postman
I finally found a solution. I used MultipartEncoder from requests_toolbelt library.
from requests_toolbelt import MultipartEncoder
import requests
import json
data = {"apiKey": 12345, "field1": "field1value"}}
mp = MultipartEncoder(
fields={
'sendRequest': json.dumps(data), # it is important to convert dict into json
'attachment': ('file.pdf', open('file.pdf', 'rb'), 'multipart/form-data'),
}
)
r = requests.post(ENDPOINT, data=mp, headers={'Content-Type': mp.content_type})

Download file from URL in Python

I am logged in in a page and I use a bookmark to download a CSV file. I just click on the link and after some seconds, the file gets downloaded in my PC. I am now trying to automate the "downloading file" process from the URL in Python.
The URL that triggers a file download is the following:
app.example.com/export/org.jsp?media=yes&csv=yes
What I tried in Python3 is shown below:
##First way
import requests
payload = {'inUserName': 'test.test#test.com','inUserPass': 'test'}
with requests.Session() as s:
p = s.post('https://app.example.com/', data=payload)
#print(p.text)
r = s.get('https://app.example.com/export/org.jsp?media=yes&csv=yes')
###Second way
import urllib
import requests
payload = {'inUserName': 'test.test#test.com', 'inUserPass': 'test'}
url = 'https://app.example.com/'
requests.post(url, data=payload)
###Third way
import urllib.request
with urllib.request.urlopen("http://app.example.com/export/org.jsp?media=yes&csv=yes") as url:
s = url.read()
#print(s)
I want to avoid the page scraping technique where I will login in the page and then visit the url. The platform used does not have an API where I can request the file in a different way.

Unable to read the buffer from BytesIO in google app engine flex environment

Here is the related code
import logging
logging.getLogger('googleapicliet.discovery_cache').setLevel(logging.ERROR)
import datetime
import json
from flask import Flask, render_template, request
from flask import make_response
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload
from oauth2client.client import AccessTokenCredentials
...
#app.route('/callback_download')
def userselectioncallback_with_drive_api():
"""
Need to make it a background process
"""
logging.info("In download callback...")
code = request.args.get('code')
fileId = request.args.get('fileId')
logging.info("code %s", code)
logging.info("fileId %s", fileId)
credentials = AccessTokenCredentials(
code,
'flex-env/1.0')
http = httplib2.Http()
http_auth = credentials.authorize(http)
# Exports a Google Doc to the requested MIME type and returns the exported content. Please note that the exported content is limited to 10MB.
# v3 does not work? over quota?
drive_service = build('drive', 'v3', http=http_auth)
drive_request = drive_service.files().export(
fileId=fileId,
mimeType='application/pdf')
b = bytes()
fh = io.BytesIO(b)
downloader = MediaIoBaseDownload(fh, drive_request)
done = False
try:
while done is False:
status, done = downloader.next_chunk()
logging.log("Download %d%%.", int(status.progress() * 100))
except Exception as err:
logging.error(err)
logging.error(err.__class__)
response = make_response(fh.getbuffer())
response.headers['Content-Type'] = 'application/pdf'
response.headers['Content-Disposition'] = \
'inline; filename=%s.pdf' % 'yourfilename'
return response
It is based on some code example of drive api. I am trying to export some files from google drive to pdf format.
The exception comes from the line
response = make_response(fh.getbuffer())
It throws the exception:
TypeError: 'memoryview' object is not callable
How can I retrieve the pdf content properly from the fh? Do I need to further apply some base 64 encoding?
My local runtime is python 3.4.3
I have used an incorrect API. I should do this instead:
response = make_response(fh.getvalue())

Create Google Shortened URLs, Update My CSV File

I've got a list of ~3,000 URLs I'm trying to create Google shortened links of, the idea is this CSV has a list of links and I want my code to output the shortened links in the column next to the original URLs.
I've been trying to modify the code found on this site here but I'm not skilled enough to get it to work.
Here's my code (I would not normally post an API key but the original person who asked this already posted it publicly on this site) :
import json
import pandas as pd
df = pd.read_csv('Links_Test.csv')
def shorternUrl(my_URL):
API_KEY = "AIzaSyCvhcU63u5OTnUsdYaCFtDkcutNm6lIEpw"
apiUrl = 'https://www.googleapis.com/urlshortener/v1/url'
longUrl = my_URL
headers = {"Content-type": "application/json"}
data = {"longUrl": longUrl}
h = httplib2.Http('.cache')
headers, response = h.request(apiUrl, "POST", json.dumps(data), headers)
return response
for url in df['URL']:
x = shorternUrl(url)
# Then I want it to write x into the column next to the original URL
But I only get errors at this point, before I even started figuring out how to write the new URLs to the CSV file.
Here's some sample data:
URL
www.apple.com
www.google.com
www.microsoft.com
www.linux.org
Thank you for your help,
Me
I think the issue is that you didnot include the API key in the request. By the way, the certifi package allows you to secure a connection to a link. You can get it using pip install certifi or pip urllib3[secure].
Here I create my own API key, so you might want to replace it with yours.
from urllib3 import PoolManager
import json
import certifi
sampleURL = 'http://www.apple.com'
APIkey = 'AIzaSyD8F41CL3nJBpEf0avqdQELKO2n962VXpA'
APIurl = 'https://www.googleapis.com/urlshortener/v1/url?key=' + APIkey
http = PoolManager(cert_reqs = 'CERT_REQUIRED', ca_certs=certifi.where())
def shortenURL(url):
data = {'key': APIkey, 'longUrl' : url}
response = http.request("POST", APIurl, body=json.dumps(data), headers= {'Content-Type' : 'application/json'}).data.decode('utf-8')
r = json.loads(response)
return (r['id'])
The decoding part converts the response object into a string so that we can convert it to a JSON and retrieve data.
From there on, you can store the data into another column and so on.
For the sampleUrl, I got back https(goo.gl/nujb) from the function.
I found a solution here:
https://pypi.python.org/pypi/pyshorteners
Example copied from linked page:
from pyshorteners import Shortener
url = 'http://www.google.com'
api_key = 'YOUR_API_KEY'
shortener = Shortener('Google', api_key=api_key)
print "My short url is {}".format(shortener.short(url))

Resources