my Year Of Code
my Year Of Code

Reputation: 423

How to upload images using wordpress REST api in python?

I think I've got this 90% working, but it ends up 'uploading' a blank transparent image. I get a 201 response after the upload. I think that's probably a proxy for when WP finds a missing image. I'm unsure if i'm passing the image incorrectly (ie it doesn't leave my computer) or if I'm not tagging it properly to WP's liking.

from base64 import b64encode
import json
import requests

def imgUploadREST(imgPath):
    url = 'https://www.XXXXXXXXXX.com/wp-json/wp/v2/media'
    auth = b64encode('{}:{}'.format('USERNAME','PASS'))
    payload = {
        'type': 'image/jpeg',  # mimetype
        'title': 'title',
        "Content":"content",
        "excerpt":"Excerpt",
    }
    headers = {
        'post_content':'post_content',
        'Content':'content',
        'Content-Disposition' : 'attachment; filename=image_20170510.jpg',
        'Authorization': 'Basic {}'.format(auth),
    }
    with open(imgPath, "rb") as image_file:
        files = {'field_name': image_file}
        r = requests.post(url, files=files, headers=headers, data=payload) 
        print r
        response = json.loads(r.content)
        print response
    return response

I've seen a fair number of answers in php or node.js, but I'm having trouble understanding the syntax in python. Thank you for any help!

Upvotes: 8

Views: 16275

Answers (6)

konmaz
konmaz

Reputation: 13

An improved version to handle non-ASCII in the filename (Greek, Cyrillic etc. letters for example). What it does is convert all non-ASCII characters to a UTF-8 escape sequence. (Original code from @my Year Of Code)

def uploadImage(filePath):
    data = open(filePath, 'rb').read()
    
    fileName = os.path.basename(filePath)
    
    espSequence = bytes(fileName, "utf-8").decode("unicode_escape")  
    # Convert all non ASCII characters to UTF-8 escape sequence

    res = requests.post(url='http://xxxxxxxxxxxxx.com/wp-json/wp/v2/media',
                        data=data,
                        headers={'Content-Type': 'image/jpeg',
                                 'Content-Disposition': 'attachment; filename=%s' % espSequence,
                                 },
                        auth=('authname', 'authpass'))
    newDict=res.json()
    newID= newDict.get('id')
    link = newDict.get('guid').get("rendered")
    print newID, link
    return (newID, link)

From my understading a POST HEADER can only contain ASCII characters

Upvotes: 1

danncti
danncti

Reputation: 11

import base64
import os

import requests

def rest_image_upload(image_path):
    message = '<user_name>' + ":" + '<application password>'
    message_bytes = message.encode('ascii')
    base64_bytes = base64.b64encode(message_bytes)
    base64_message = base64_bytes.decode('ascii')

    # print(base64_message)

    data = open(image_path, 'rb').read()
    file_name = os.path.basename(image_path)
    res = requests.post(url='https://<example.com>/wp-json/wp/v2/media',
                    data=data,
                    headers={'Content-Type': 'image/jpg',
                             'Content-Disposition': 'attachment; filename=%s' % file_name,
                             'Authorization': 'Basic ' + base64_message})
    new_dict = res.json()
    new_id = new_dict.get('id')
    link = new_dict.get('guid').get("rendered")
    # print(new_id, link)
    return new_id, link

Upvotes: -1

ahmedul Kabir Omi
ahmedul Kabir Omi

Reputation: 144

This is my working code for uploading image into WordPress from local image or from url. hope someone find it useful.

import requests, json, os, base64

def wp_upload_image(domain, user, app_pass, imgPath):
    # imgPath can be local image path or can be url
    url = 'https://'+ domain + '/wp-json/wp/v2/media'
    filename = imgPath.split('/')[-1] if len(imgPath.split('/')[-1])>1 else imgPath.split('\\')[-1]
    extension = imgPath[imgPath.rfind('.')+1 : len(imgPath)]
    if imgPath.find('http') == -1:
        try: data = open(imgPath, 'rb').read()
        except:
            print('image local path not exits')
            return None
    else:
        rs = requests.get(imgPath)
        if rs.status_code == 200:
            data = rs.content
        else:
            print('url get request failed')
            return None
    headers = { "Content-Disposition": f"attachment; filename={filename}" , "Content-Type": str("image/" + extension)}
    rs = requests.post(url, auth=(user, app_pass), headers=headers, data=data)
    print(rs)
    return (rs.json()['source_url'], rs.json()['id'])

Upvotes: 0

TheoretiCAL
TheoretiCAL

Reputation: 20571

To specify additional fields supported by the api such as alt text, description ect:

from requests_toolbelt.multipart.encoder import MultipartEncoder
import requests
import os
fileName = os.path.basename(imgPath)
multipart_data = MultipartEncoder(
    fields={
        # a file upload field
        'file': (fileName, open(imgPath, 'rb'), 'image/jpg'),
        # plain text fields
        'alt_text': 'alt test',
        'caption': 'caption test',
        'description': 'description test'
    }
)

response = requests.post('http://example/wp-json/wp/v2/media', data=multipart_data,
                         headers={'Content-Type': multipart_data.content_type},
                         auth=('user', 'pass'))

Upvotes: 2

crifan
crifan

Reputation: 14328

thanks to @my Year Of Code.

my final working code:

import 
HOST = "https://www.crifan.com"
API_MEDIA = HOST + "/wp-json/wp/v2/media"
JWT_TOKEN = "eyJxxxxxxxxjLYB4"

    imgMime = gImageSuffixToMime[imgSuffix] # 'image/png'
    imgeFilename = "%s.%s" % (processedGuid, imgSuffix) # 'f6956c30ef0b475fa2b99c2f49622e35.png'
    authValue = "Bearer %s" % JWT_TOKEN
    curHeaders = {
        "Authorization": authValue,
        "Content-Type": imgMime,
        'Content-Disposition': 'attachment; filename=%s' % imgeFilename,
    }
    # curHeaders={'Authorization': 'Bearer eyJ0xxxyyy.zzzB4', 'Content-Type': 'image/png', 'Content-Disposition': 'attachment; filename=f6956c30ef0b475fa2b99c2f49622e35.png'}
    uploadImgUrl = API_MEDIA
    resp = requests.post(
        uploadImgUrl,
        # proxies=cfgProxies,
        headers=curHeaders,
        data=imgBytes,
    )

return 201 means Created OK

response json look like:

{
  "id": 70393,
  "date": "2020-03-07T18:43:47",
  "date_gmt": "2020-03-07T10:43:47",
  "guid": {
    "rendered": "https://www.crifan.com/files/pic/uploads/2020/03/f6956c30ef0b475fa2b99c2f49622e35.png",
    "raw": "https://www.crifan.com/files/pic/uploads/2020/03/f6956c30ef0b475fa2b99c2f49622e35.png"
  },
...

more details refer my (Chinese) post: 【已解决】用Python通过WordPress的REST API上传图片

Upvotes: 0

my Year Of Code
my Year Of Code

Reputation: 423

I've figured it out!

With this function I'm able to upload images via the WP REST api to my site (Photo Gear Hunter.) The function returns the ID of the image. You can then pass that id to a new post call and make it the featured image, or do whatever you wish with it.

def restImgUL(imgPath):
    url='http://xxxxxxxxxxxx.com/wp-json/wp/v2/media'
    data = open(imgPath, 'rb').read()
    fileName = os.path.basename(imgPath)
    res = requests.post(url='http://xxxxxxxxxxxxx.com/wp-json/wp/v2/media',
                        data=data,
                        headers={ 'Content-Type': 'image/jpg','Content-Disposition' : 'attachment; filename=%s'% fileName},
                        auth=('authname', 'authpass'))
    # pp = pprint.PrettyPrinter(indent=4) ## print it pretty. 
    # pp.pprint(res.json()) #this is nice when you need it
    newDict=res.json()
    newID= newDict.get('id')
    link = newDict.get('guid').get("rendered")
    print newID, link
    return (newID, link)

Upvotes: 21

Related Questions