Im iterating through and scraping images off a website... but for some reason the "write" isn't working and saving the image. Am I supposed to declare a directory to save them to or something? here's my request. Im using python 2.7
for img in imgs:
image = img['href']
img_url = my_url + image
resource = urllib.urlretrieve(img_url)
resource = resource[0]
output = open(resource, "wb")
output.write(resource)
output.close()
You're working too hard! urlretrieve will already have written the file to disk, all you need to do is copy it to somewhere more permanent.
filename,headers = urllib.urlretreive(img_url)
import shutil
shutil.copy(filename, "/path/to/somewhere")
But to answer your question about what is going on...
resource = urllib.urlretrieve(img_url) # the file is on disk at /tmp/foobar
resource = resource[0] # resource now contains "/tmp/foobar"
output = open(resource, "wb") # oops! You just opened "/tmp/foobar" for writing, which clears the file
Related
I have been trying to speed up our date stamping process by adding a stamp as a watermark to PDFs through PyPDF2. I found the code below online as I'm pretty new to coding.
When I run this it seems to work, but the file is corrupted and won't open. Does anyone have any ideas where I am going wrong?
from PyPDF2 import PdfFileWriter, PdfFileReader
def create_watermark(input_pdf, output_pdf, watermark):
watermark_obj = PdfFileReader(watermark,False,)
watermark_page = watermark_obj.getPage(0)
pdf_reader = PdfFileReader(input_pdf)
pdf_writer = PdfFileWriter()
# Watermark all the pages
for page in range(pdf_reader.getNumPages()):
page = pdf_reader.getPage(page)
page.mergePage(watermark_page)
pdf_writer.addPage(page)
with open(input_pdf, 'wb') as out:
pdf_writer.write(out)
if __name__ == '__main__':
input_pdf = "C:\\Users\\A***\\OneDrive - ***\\Desktop\\Invoice hold\\Test\\1.pdf"
output_pdf = "C:\\Users\\A***\\OneDrive - ***\\Desktop\\Invoice hold\\Test\\1 WM.pdf"
watermark = "C:\\Users\\A***\\OneDrive - ***\\Desktop\\Invoice hold\\WM.pdf"
create_watermark(input_pdf,output_pdf,watermark)
If you want to save pdf file under the name of output_pdf,
try this :
result = open(output_pdf, 'wb')
pdf_writer.write(result)
your code :
with open(input_pdf, 'wb') as out:
pdf_writer.write(out)
Your code is to overwrite input_pdf.
And if there is a problem while working, the pdf file will be damaged.
I succeeded in inserting the watermark by applying your code and my proposed method.
I recommend checking if the pdf file is not damaged.
I see that there are two ways to download images using python-reuqests.
Uisng PIL as stated in docs (https://requests.readthedocs.io/en/master/user/quickstart/#binary-response-content):
from PIL import Image
from io import BytesIO
i = Image.open(BytesIO(r.content))
using streamed response content:
r = requests.get(url, stream=True)
with open(image_name, 'wb') as f:
for chunk in r.iter_content():
f.write(chunk)
Which is the recommended wya to download images however? both have its merits I suyppose, and I was wondering what is the optimal approach.
I love the minimalist way. There is nothing called right way. It depends on the task you want to perform and the constraints you have.
import requests
with open('file.png', 'wb') as f:
f.write(requests.get(url).content)
# if you change png to jpg, there will be no error
I did use the below lines of code in a function to save images.
# import the required libraries from Python
import pathlib,urllib.request,os,uuid
# URL of the image you want to download
image_url = "https://example.com/image.png"
# Using the uuid generate new and unique names for your images
filename = str(uuid.uuid4())
# Strip the image extension from it's original name
file_ext = pathlib.Path(image_url).suffix
# Join the new image name to the extension
picture_filename = filename + file_ext
# Using pathlib, specify where the image is to be saved
downloads_path = str(pathlib.Path.home() / "Downloads")
# Form a full image path by joining the path to the
# images' new name
picture_path = os.path.join(downloads_path, picture_filename)
# Using "urlretrieve()" from urllib.request save the image
urllib.request.urlretrieve(image_url, picture_path)
# urlretrieve() takes in 2 arguments
# 1. The URL of the image to be downloaded
# 2. The image new name after download. By default, the image is
# saved inside your current working directory
Context
I have made a simple web app for uploading content to a blog. The front sends AJAX requests (using FormData) to the backend which is Bottle running on Python 3.7. Text content is saved to a MySQL database and images are saved to a folder on the server. Everything works fine.
Image processing and PIL/Pillow
Now, I want to enable processing of uploaded images to standardise them (I need them all resized and/or cropped to 700x400px).
I was hoping to use Pillow for this. My problem is creating a PIL Image object from the file object in Bottle. I cannot initialise a valid Image object.
Code
# AJAX sends request to this route
#post('/update')
def update():
# Form data
title = request.forms.get("title")
body = request.forms.get("body")
image = request.forms.get("image")
author = request.forms.get("author")
# Image upload
file = request.files.get("file")
if file:
extension = file.filename.split(".")[-1]
if extension not in ('png', 'jpg', 'jpeg'):
return {"result" : 0, "message": "File Format Error"}
save_path = "my/save/path"
file.save(save_path)
The problem
This all works as expected, but I cannot create a valid Image object with pillow for processing. I even tried reloading the saved image using the save path but this did not work either.
Other attempts
The code below did not work. It caused an internal server error, though I am having trouble setting up more detailed Python debugging.
path = save_path + "/" + file.filename
image_data = open(path, "rb")
image = Image.open(image_data)
When logged manually, the path is a valid relative URL ("../domain-folder/images") and I have checked that I am definitely importing PIL (Pillow) correctly using PIL.PILLOW_VERSION.
I tried adapting this answer:
image = Image.frombytes('RGBA', (128,128), image_data, 'raw')
However, I won’t know the size until I have created the Image object. I also tried using io:
image = Image.open(io.BytesIO(image_data))
This did not work either. In each case, it is only the line trying to initialise the Image object that causes problems.
Summary
The Bottle documentation says the uploaded file is a file-like object, but I am not having much success in creating an Image object that I can process.
How should I go about this? I do not have a preference about processing before or after saving. I am comfortable with the processing, it is initialising the Image object that is causing the problem.
Edit - Solution
I got this to work by adapting the answer from eatmeimadanish. I had to use a io.BytesIO object to save the file from Bottle, then load it with Pillow from there. After processing, it could be saved in the usual way.
obj = io.BytesIO()
file.save(obj) # This saves the file retrieved by Bottle to the BytesIO object
path = save_path + "/" + file.filename
# Image processing
im = Image.open(obj) # Reopen the object with PIL
im = im.resize((700,400))
im.save(path, optimize=True)
I found this from the Pillow documentation about a different function that may also be of use.
PIL.Image.frombuffer(mode, size, data, decoder_name='raw', *args)
Note that this function decodes pixel data only, not entire images.
If you have an entire image file in a string, wrap it in a BytesIO object, and use open() to load it.
Use StringIO instead.
From PIL import Image
try:
import cStringIO as StringIO
except ImportError:
import StringIO
s = StringIO.StringIO()
#save your in memory file to this instead of a regular file
file = request.files.get("file")
if file:
extension = file.filename.split(".")[-1]
if extension not in ('png', 'jpg', 'jpeg'):
return {"result" : 0, "message": "File Format Error"}
file.save(s)
im = Image.open(s)
im.resize((700,400))
im.save(s, 'png', optimize=True)
s64 = base64.b64encode(s.getvalue())
From what I understand, you're trying to resize the image after it has been saved locally (note that you could try to do the resize before it is saved). If this is what you want to achieve here, you can open the image directly using Pillow, it does the job for you (you do not have to open(path, "rb"):
image = Image.open(path)
image.resize((700,400)).save(path)
I am using the Drive API to download an image. Following their file downloading documentation in Python, I end up with a variable fh that is a populated io.BytesIO instance. I try to save it as an image:
file_id = "0BwyLGoHzn5uIOHVycFZpSEwycnViUjFYQXR5Nnp6QjBrLXJR"
request = service.files().get_media(fileId=file_id)
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print('Download {} {}%.'.format(file['name'],
int(status.progress() * 100)))
fh.seek(0)
image = Image.open(fh) # error
The error is: cannot identify image file <_io.BytesIO object at 0x106cba890>. Actually, the error does not occur with another image but is thrown with most images, including the one I linked at the beginning of this post.
After reading this answer I change that last line to:
byteImg = fh.read()
dataBytesIO = io.BytesIO(byteImg)
image = Image.open(dataBytesIO) # still the same error
I've also tried this answer, where I change the last line of my first code block to
byteImg = fh.read()
image = Image.open(StringIO(byteImg))
But I still get a cannot identify image file <StringIO.StringIO instance at 0x106471e60> error.
I've tried using alternates (requests, urllib) with no fruition. I can Image.open the the image if I download it manually.
This error was not present a month ago, and has recently popped up into the application this code is in. I've spent days debugging this error with no success and have finally brought the issue to Stack Overflow. I am using from PIL import Image.
Ditch the Drive service's MediaIOBaseDownload. Instead, use the webContentLink property of a media file (a link for downloading the content of the file in a browser, only available for files with binary content). Read more here.
With that content link, we can use an alternate form of streaming—the requests and shutil libraries and the —to get the image.
import requests
import shutil
r = requests.get(file['webContentLink'], stream=True)
with open('output_file', 'wb') as f:
shutil.copyfileobj(r.raw, f)
I have a stored picture on my computer. I open it using the Python Image module. Then I crop this image into several pieces using this module. To conclude, I would like to upload the image via a POST request on a website.
Because that small images are PIL object, I converted each of them into StringIO to be able to send the form without having to save them on my PC.
Unfortunately, I encounter an error, whereas if the images are physically stored on my PC, there is no problem. I do not understand why.
You can visit the website here: http://www.noelshack.com/api.php
This is a very basic API that returns the link to the uploaded picture.
In my case, the problem is that returns nothing, at the end of the second image (no problem for the first).
Here is the programming code to crop the image into 100 pieces.
import requests
import Image
import StringIO
import os
image = Image.open("test.jpg")
width, height = image.size
images = []
for i in range(10):
for j in range(10):
crop = image.crop((i * 10, j * 10, (i + 1) * 10, (j + 1) * 10))
images.append(crop)
The function to upload an image:
def upload(my_file):
api_url = 'http://www.noelshack.com/api.php'
r = requests.post(api_url, files={'fichier': my_file})
if not 'www.noelshack.com' in r.text:
raise Exception(r.text)
return r.text
Now we have two possibilities. The first is to save each of the 100 images on disk and upload them.
if not os.path.exists("directory"):
os.makedirs("directory")
i = 0
for img in images:
img.save("directory/" + str(i) + ".jpg")
i += 1
for file in os.listdir("directory"):
with open("directory/" + file, "rb") as f:
print upload(f)
It works like a charm, but it is not very convenient. So, I thought to use StringIO.
for img in images:
my_file = StringIO.StringIO()
img.save(my_file, "JPEG")
print upload(my_file.getvalue())
# my_file.close() -> Does not change anything
The first link is printed, but the function raise the exception then.
I think the problem lies in the img.save(), because the same kind of for loop was not working to save to disk and then upload. In addition, if you add a time.sleep(1) between the uploads, it seems to work.
Any help would be welcome please, because I'm really stuck.
my_file.getvalue() returns a string. What you need is a file-like object, which my_file already is. And file like objects have a cursor, so to speak, which says where to read from or write to. So, if you do my_file.seek(0) before the upload, it should get fixed.
modify the code to:
for img in images:
my_file = StringIO.StringIO()
img.save(my_file, "JPEG")
my_file.seek(0)
print upload(my_file)