Use Python along with the HubSpot HubDB API and the Blog Post API to create, update, and publish a batch of...











up vote
3
down vote

favorite












My program automates the process of creating and publishing 152 blog posts quarterly. The blogging platform HubSpot has a series of APIs that allow developers to access account data from a CLI in Terminal. First step is creating an excel file (must save as CSV) and importing the file for use as a new HubDB table in HubSpot (basically a google sheet built into HS). The HubDB contains all of the content for a single post in a single row.



Not all of the functions defined are used, however I expect the scope to expand and to use this program to automate content creation for other blogs on HubSpot. Therefore, my goal is to make the process agnostic so that it may be applied broadly.



import requests
import json
import time
from urllib.request import urlopen
from pprint import pprint


"""
CRUD (Create, Retrieve, Update, And Delete) HTTP methods for the
ManpowerGroup Employment Outlook Survey hosted in HubSpot
"""

# Set the API endpoint

APIKEY_VALUE = "XXX-X-X-XXX"
APIKEY = "?hapikey=" + APIKEY_VALUE
HS_API_URL = "http://api.hubapi.com"
PORTAL_ID = 2942250

# Define content group IDs as global variables
TEMPLATE_ID = 5548244265 # HubSpot Templates
MANPOWERGROUP_ID = 5548244265 # ManpowerGroup
MEOS_ID = 5664168304 # ManpowerGroup Employment Outlook Survey
WEF_ID = 5505585256 # World Economic Forum

# List all HubDB table IDs as global variables
MEOS_Q1_2019 = 1029596 # table ID
MEOS_Q2_2018 = 679969
MEOS_Q3_2018 = 700276
MEOS_Q4_2018 = 850049

# Define JSON Actions
PUBLISH = {"action": "schedule-publish"}
CANCEL = {"action": "cancel-publish"}

# Define publication details
PUBLISH_NOW = str(time.time())
DRAFT = 'draft'
LIVE = 'publish'
LIMIT = 152 # Number of rows in table to publish as posts

# CREATE BLOG POSTS
def create_batch_posts(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)

for row in table_data['objects']:
name = row["values"]["1"]
embed = row["values"]["2"]
title = row["values"]["3"]
state = row["values"]["4"]
date = row["values"]["5"]
year = row["values"]["6"]
quarter = row["values"]["7"]
country = row["values"]["9"]
forecast = row["values"]["10"]
blog_author_id = row["values"]["11"]
campaign_id = row["values"]["12"]
campaign_name = row["values"]["13"]
content_group_id = row["values"]["14"]
featured_image = row["values"]["15"]
year_id = row["values"]["19"]
quarter_id = row["values"]["20"]
market_id = row["values"]["21"]
state_id = row["values"]["22"]
epoch_date = row["values"]["23"]
embed_pdf = "<embed src='https://drive.google.com/viewerng/viewer?embedded=true&amp;url=https://go.manpowergroup.com/hubfs/MEOS/2019_Q1/" + str(embed) + ".pdf' width='500' height='675'>"

POST = {
"blog_author_id": blog_author_id,
"campaign": campaign_id,
"campaign_name": campaign_name,
"content_group_id": content_group_id,
"featured_image": featured_image,
"topic_ids": [year_id, quarter_id, market_id, state_id],
"meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name) + " | " + str(state) + ", " + str(country),
"name": str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name),
"post_body": embed_pdf,
"publish_date": str(epoch_date),
"publish_immediately": False,
"slug": str(year) + "_" + str(quarter) + "/" + str(embed),
"use_featured_image": True
}

xurl = "/content/api/v2/blog-posts"
url = HS_API_URL + xurl + APIKEY
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(POST))
pprint(response.status_code, response.content, response)


# RETRIEVE CONTENT FROM HubDB
def get_single_row(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_rows(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_tables():
"""Get the tables
GET /hubdb/api/v2/tables
"""
xurl = "/hubdb/api/v2/tables"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
all_tables = json.loads(response)
return all_tables


def get_table_by_id(table_id):
"""Get the tables
GET /hubdb/api/v2/tables/:tableId
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table = json.loads(response)
return table


# RETRIEVE BLOG POST ID
def list_all_posts():
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


def list_blog_posts(blog_id):
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_id)
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


# PUBLISH BLOG POSTS
def publish_blog_post_by_id(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
response = requests.post(url)
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(PUBLISH))
# pprint(response.status_code, response.content, response)
return response


def publish_post():
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
draft_id = blog_post['id']
# print(draft_id)
publish_blog_post_by_id(draft_id) # req. publish_post function


def publish_draft_posts(content_group_id, limit, draft):
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
+ '&content_group_id=' + str(content_group_id) # Blog ID
+ '&state=' + str(DRAFT) # DRAFT vs. LIVE
+ '&limit=' + str(LIMIT) # LIMIT TOTAL RESPONSES to ROW NUM
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
print(blog_post['id'])


def get_blog_post_by_id(post_id):
"""Get the blog by ID
GET /content/api/v2/blogs/:blog_id
"""
xurl = "/content/api/v2/blogs/" + str(post_id)
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_info = json.loads(response)
return blog_info

def cancel_post(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
# bin = "http://requestbin.fullcontact.com/1iiiiyo1"
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(CANCEL))
# pprint(response.status_code, response.content, response)
return response


# AUTOMATION FOR MANPOWERGROUP EMPLOYMENT OUTLOOK SURVEY (HUBSPOT)
def main():
# Create a draft version of the blog posts
create_batch_posts(1029596)
# Publish the drafts
publish_draft_posts(TEMPLATE_ID, 2, DRAFT)
print("Published")


main()


Please check out my gist for easier reading....










share|improve this question
























  • @200_success I have added the entire program to the post.
    – FlySpaceAge
    11 hours ago















up vote
3
down vote

favorite












My program automates the process of creating and publishing 152 blog posts quarterly. The blogging platform HubSpot has a series of APIs that allow developers to access account data from a CLI in Terminal. First step is creating an excel file (must save as CSV) and importing the file for use as a new HubDB table in HubSpot (basically a google sheet built into HS). The HubDB contains all of the content for a single post in a single row.



Not all of the functions defined are used, however I expect the scope to expand and to use this program to automate content creation for other blogs on HubSpot. Therefore, my goal is to make the process agnostic so that it may be applied broadly.



import requests
import json
import time
from urllib.request import urlopen
from pprint import pprint


"""
CRUD (Create, Retrieve, Update, And Delete) HTTP methods for the
ManpowerGroup Employment Outlook Survey hosted in HubSpot
"""

# Set the API endpoint

APIKEY_VALUE = "XXX-X-X-XXX"
APIKEY = "?hapikey=" + APIKEY_VALUE
HS_API_URL = "http://api.hubapi.com"
PORTAL_ID = 2942250

# Define content group IDs as global variables
TEMPLATE_ID = 5548244265 # HubSpot Templates
MANPOWERGROUP_ID = 5548244265 # ManpowerGroup
MEOS_ID = 5664168304 # ManpowerGroup Employment Outlook Survey
WEF_ID = 5505585256 # World Economic Forum

# List all HubDB table IDs as global variables
MEOS_Q1_2019 = 1029596 # table ID
MEOS_Q2_2018 = 679969
MEOS_Q3_2018 = 700276
MEOS_Q4_2018 = 850049

# Define JSON Actions
PUBLISH = {"action": "schedule-publish"}
CANCEL = {"action": "cancel-publish"}

# Define publication details
PUBLISH_NOW = str(time.time())
DRAFT = 'draft'
LIVE = 'publish'
LIMIT = 152 # Number of rows in table to publish as posts

# CREATE BLOG POSTS
def create_batch_posts(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)

for row in table_data['objects']:
name = row["values"]["1"]
embed = row["values"]["2"]
title = row["values"]["3"]
state = row["values"]["4"]
date = row["values"]["5"]
year = row["values"]["6"]
quarter = row["values"]["7"]
country = row["values"]["9"]
forecast = row["values"]["10"]
blog_author_id = row["values"]["11"]
campaign_id = row["values"]["12"]
campaign_name = row["values"]["13"]
content_group_id = row["values"]["14"]
featured_image = row["values"]["15"]
year_id = row["values"]["19"]
quarter_id = row["values"]["20"]
market_id = row["values"]["21"]
state_id = row["values"]["22"]
epoch_date = row["values"]["23"]
embed_pdf = "<embed src='https://drive.google.com/viewerng/viewer?embedded=true&amp;url=https://go.manpowergroup.com/hubfs/MEOS/2019_Q1/" + str(embed) + ".pdf' width='500' height='675'>"

POST = {
"blog_author_id": blog_author_id,
"campaign": campaign_id,
"campaign_name": campaign_name,
"content_group_id": content_group_id,
"featured_image": featured_image,
"topic_ids": [year_id, quarter_id, market_id, state_id],
"meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name) + " | " + str(state) + ", " + str(country),
"name": str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name),
"post_body": embed_pdf,
"publish_date": str(epoch_date),
"publish_immediately": False,
"slug": str(year) + "_" + str(quarter) + "/" + str(embed),
"use_featured_image": True
}

xurl = "/content/api/v2/blog-posts"
url = HS_API_URL + xurl + APIKEY
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(POST))
pprint(response.status_code, response.content, response)


# RETRIEVE CONTENT FROM HubDB
def get_single_row(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_rows(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_tables():
"""Get the tables
GET /hubdb/api/v2/tables
"""
xurl = "/hubdb/api/v2/tables"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
all_tables = json.loads(response)
return all_tables


def get_table_by_id(table_id):
"""Get the tables
GET /hubdb/api/v2/tables/:tableId
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table = json.loads(response)
return table


# RETRIEVE BLOG POST ID
def list_all_posts():
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


def list_blog_posts(blog_id):
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_id)
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


# PUBLISH BLOG POSTS
def publish_blog_post_by_id(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
response = requests.post(url)
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(PUBLISH))
# pprint(response.status_code, response.content, response)
return response


def publish_post():
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
draft_id = blog_post['id']
# print(draft_id)
publish_blog_post_by_id(draft_id) # req. publish_post function


def publish_draft_posts(content_group_id, limit, draft):
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
+ '&content_group_id=' + str(content_group_id) # Blog ID
+ '&state=' + str(DRAFT) # DRAFT vs. LIVE
+ '&limit=' + str(LIMIT) # LIMIT TOTAL RESPONSES to ROW NUM
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
print(blog_post['id'])


def get_blog_post_by_id(post_id):
"""Get the blog by ID
GET /content/api/v2/blogs/:blog_id
"""
xurl = "/content/api/v2/blogs/" + str(post_id)
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_info = json.loads(response)
return blog_info

def cancel_post(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
# bin = "http://requestbin.fullcontact.com/1iiiiyo1"
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(CANCEL))
# pprint(response.status_code, response.content, response)
return response


# AUTOMATION FOR MANPOWERGROUP EMPLOYMENT OUTLOOK SURVEY (HUBSPOT)
def main():
# Create a draft version of the blog posts
create_batch_posts(1029596)
# Publish the drafts
publish_draft_posts(TEMPLATE_ID, 2, DRAFT)
print("Published")


main()


Please check out my gist for easier reading....










share|improve this question
























  • @200_success I have added the entire program to the post.
    – FlySpaceAge
    11 hours ago













up vote
3
down vote

favorite









up vote
3
down vote

favorite











My program automates the process of creating and publishing 152 blog posts quarterly. The blogging platform HubSpot has a series of APIs that allow developers to access account data from a CLI in Terminal. First step is creating an excel file (must save as CSV) and importing the file for use as a new HubDB table in HubSpot (basically a google sheet built into HS). The HubDB contains all of the content for a single post in a single row.



Not all of the functions defined are used, however I expect the scope to expand and to use this program to automate content creation for other blogs on HubSpot. Therefore, my goal is to make the process agnostic so that it may be applied broadly.



import requests
import json
import time
from urllib.request import urlopen
from pprint import pprint


"""
CRUD (Create, Retrieve, Update, And Delete) HTTP methods for the
ManpowerGroup Employment Outlook Survey hosted in HubSpot
"""

# Set the API endpoint

APIKEY_VALUE = "XXX-X-X-XXX"
APIKEY = "?hapikey=" + APIKEY_VALUE
HS_API_URL = "http://api.hubapi.com"
PORTAL_ID = 2942250

# Define content group IDs as global variables
TEMPLATE_ID = 5548244265 # HubSpot Templates
MANPOWERGROUP_ID = 5548244265 # ManpowerGroup
MEOS_ID = 5664168304 # ManpowerGroup Employment Outlook Survey
WEF_ID = 5505585256 # World Economic Forum

# List all HubDB table IDs as global variables
MEOS_Q1_2019 = 1029596 # table ID
MEOS_Q2_2018 = 679969
MEOS_Q3_2018 = 700276
MEOS_Q4_2018 = 850049

# Define JSON Actions
PUBLISH = {"action": "schedule-publish"}
CANCEL = {"action": "cancel-publish"}

# Define publication details
PUBLISH_NOW = str(time.time())
DRAFT = 'draft'
LIVE = 'publish'
LIMIT = 152 # Number of rows in table to publish as posts

# CREATE BLOG POSTS
def create_batch_posts(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)

for row in table_data['objects']:
name = row["values"]["1"]
embed = row["values"]["2"]
title = row["values"]["3"]
state = row["values"]["4"]
date = row["values"]["5"]
year = row["values"]["6"]
quarter = row["values"]["7"]
country = row["values"]["9"]
forecast = row["values"]["10"]
blog_author_id = row["values"]["11"]
campaign_id = row["values"]["12"]
campaign_name = row["values"]["13"]
content_group_id = row["values"]["14"]
featured_image = row["values"]["15"]
year_id = row["values"]["19"]
quarter_id = row["values"]["20"]
market_id = row["values"]["21"]
state_id = row["values"]["22"]
epoch_date = row["values"]["23"]
embed_pdf = "<embed src='https://drive.google.com/viewerng/viewer?embedded=true&amp;url=https://go.manpowergroup.com/hubfs/MEOS/2019_Q1/" + str(embed) + ".pdf' width='500' height='675'>"

POST = {
"blog_author_id": blog_author_id,
"campaign": campaign_id,
"campaign_name": campaign_name,
"content_group_id": content_group_id,
"featured_image": featured_image,
"topic_ids": [year_id, quarter_id, market_id, state_id],
"meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name) + " | " + str(state) + ", " + str(country),
"name": str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name),
"post_body": embed_pdf,
"publish_date": str(epoch_date),
"publish_immediately": False,
"slug": str(year) + "_" + str(quarter) + "/" + str(embed),
"use_featured_image": True
}

xurl = "/content/api/v2/blog-posts"
url = HS_API_URL + xurl + APIKEY
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(POST))
pprint(response.status_code, response.content, response)


# RETRIEVE CONTENT FROM HubDB
def get_single_row(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_rows(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_tables():
"""Get the tables
GET /hubdb/api/v2/tables
"""
xurl = "/hubdb/api/v2/tables"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
all_tables = json.loads(response)
return all_tables


def get_table_by_id(table_id):
"""Get the tables
GET /hubdb/api/v2/tables/:tableId
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table = json.loads(response)
return table


# RETRIEVE BLOG POST ID
def list_all_posts():
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


def list_blog_posts(blog_id):
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_id)
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


# PUBLISH BLOG POSTS
def publish_blog_post_by_id(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
response = requests.post(url)
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(PUBLISH))
# pprint(response.status_code, response.content, response)
return response


def publish_post():
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
draft_id = blog_post['id']
# print(draft_id)
publish_blog_post_by_id(draft_id) # req. publish_post function


def publish_draft_posts(content_group_id, limit, draft):
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
+ '&content_group_id=' + str(content_group_id) # Blog ID
+ '&state=' + str(DRAFT) # DRAFT vs. LIVE
+ '&limit=' + str(LIMIT) # LIMIT TOTAL RESPONSES to ROW NUM
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
print(blog_post['id'])


def get_blog_post_by_id(post_id):
"""Get the blog by ID
GET /content/api/v2/blogs/:blog_id
"""
xurl = "/content/api/v2/blogs/" + str(post_id)
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_info = json.loads(response)
return blog_info

def cancel_post(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
# bin = "http://requestbin.fullcontact.com/1iiiiyo1"
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(CANCEL))
# pprint(response.status_code, response.content, response)
return response


# AUTOMATION FOR MANPOWERGROUP EMPLOYMENT OUTLOOK SURVEY (HUBSPOT)
def main():
# Create a draft version of the blog posts
create_batch_posts(1029596)
# Publish the drafts
publish_draft_posts(TEMPLATE_ID, 2, DRAFT)
print("Published")


main()


Please check out my gist for easier reading....










share|improve this question















My program automates the process of creating and publishing 152 blog posts quarterly. The blogging platform HubSpot has a series of APIs that allow developers to access account data from a CLI in Terminal. First step is creating an excel file (must save as CSV) and importing the file for use as a new HubDB table in HubSpot (basically a google sheet built into HS). The HubDB contains all of the content for a single post in a single row.



Not all of the functions defined are used, however I expect the scope to expand and to use this program to automate content creation for other blogs on HubSpot. Therefore, my goal is to make the process agnostic so that it may be applied broadly.



import requests
import json
import time
from urllib.request import urlopen
from pprint import pprint


"""
CRUD (Create, Retrieve, Update, And Delete) HTTP methods for the
ManpowerGroup Employment Outlook Survey hosted in HubSpot
"""

# Set the API endpoint

APIKEY_VALUE = "XXX-X-X-XXX"
APIKEY = "?hapikey=" + APIKEY_VALUE
HS_API_URL = "http://api.hubapi.com"
PORTAL_ID = 2942250

# Define content group IDs as global variables
TEMPLATE_ID = 5548244265 # HubSpot Templates
MANPOWERGROUP_ID = 5548244265 # ManpowerGroup
MEOS_ID = 5664168304 # ManpowerGroup Employment Outlook Survey
WEF_ID = 5505585256 # World Economic Forum

# List all HubDB table IDs as global variables
MEOS_Q1_2019 = 1029596 # table ID
MEOS_Q2_2018 = 679969
MEOS_Q3_2018 = 700276
MEOS_Q4_2018 = 850049

# Define JSON Actions
PUBLISH = {"action": "schedule-publish"}
CANCEL = {"action": "cancel-publish"}

# Define publication details
PUBLISH_NOW = str(time.time())
DRAFT = 'draft'
LIVE = 'publish'
LIMIT = 152 # Number of rows in table to publish as posts

# CREATE BLOG POSTS
def create_batch_posts(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)

for row in table_data['objects']:
name = row["values"]["1"]
embed = row["values"]["2"]
title = row["values"]["3"]
state = row["values"]["4"]
date = row["values"]["5"]
year = row["values"]["6"]
quarter = row["values"]["7"]
country = row["values"]["9"]
forecast = row["values"]["10"]
blog_author_id = row["values"]["11"]
campaign_id = row["values"]["12"]
campaign_name = row["values"]["13"]
content_group_id = row["values"]["14"]
featured_image = row["values"]["15"]
year_id = row["values"]["19"]
quarter_id = row["values"]["20"]
market_id = row["values"]["21"]
state_id = row["values"]["22"]
epoch_date = row["values"]["23"]
embed_pdf = "<embed src='https://drive.google.com/viewerng/viewer?embedded=true&amp;url=https://go.manpowergroup.com/hubfs/MEOS/2019_Q1/" + str(embed) + ".pdf' width='500' height='675'>"

POST = {
"blog_author_id": blog_author_id,
"campaign": campaign_id,
"campaign_name": campaign_name,
"content_group_id": content_group_id,
"featured_image": featured_image,
"topic_ids": [year_id, quarter_id, market_id, state_id],
"meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name) + " | " + str(state) + ", " + str(country),
"name": str(date) + " | " + str(forecast) + " " + str(title) + " " + str(name),
"post_body": embed_pdf,
"publish_date": str(epoch_date),
"publish_immediately": False,
"slug": str(year) + "_" + str(quarter) + "/" + str(embed),
"use_featured_image": True
}

xurl = "/content/api/v2/blog-posts"
url = HS_API_URL + xurl + APIKEY
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(POST))
pprint(response.status_code, response.content, response)


# RETRIEVE CONTENT FROM HubDB
def get_single_row(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_rows(table_id):
"""Get table by row
GET /hubdb/api/v2/tables/:tableId/rows
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table_data = json.loads(response)
return(table_data)


def get_all_tables():
"""Get the tables
GET /hubdb/api/v2/tables
"""
xurl = "/hubdb/api/v2/tables"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
all_tables = json.loads(response)
return all_tables


def get_table_by_id(table_id):
"""Get the tables
GET /hubdb/api/v2/tables/:tableId
"""
xurl = "/hubdb/api/v2/tables/" + str(table_id) + "?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl
response = urlopen(url).read()
table = json.loads(response)
return table


# RETRIEVE BLOG POST ID
def list_all_posts():
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


def list_blog_posts(blog_id):
"""List blog posts
Hit this URL with a HTTP method of
GET /content/api/v2/blog-posts
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_id)
url = HS_API_URL + xurl + APIKEY
blog_list = urlopen(url).read()
# print(blog_list)
return blog_list


# PUBLISH BLOG POSTS
def publish_blog_post_by_id(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
response = requests.post(url)
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(PUBLISH))
# pprint(response.status_code, response.content, response)
return response


def publish_post():
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
draft_id = blog_post['id']
# print(draft_id)
publish_blog_post_by_id(draft_id) # req. publish_post function


def publish_draft_posts(content_group_id, limit, draft):
"""Get the blog post by ID
GET /content/api/v2/blog-posts/
"""
xurl = "/content/api/v2/blog-posts/"
url = HS_API_URL + xurl + APIKEY
+ '&content_group_id=' + str(content_group_id) # Blog ID
+ '&state=' + str(DRAFT) # DRAFT vs. LIVE
+ '&limit=' + str(LIMIT) # LIMIT TOTAL RESPONSES to ROW NUM
response = urlopen(url).read()
blog_data = json.loads(response)
for blog_post in blog_data['objects']:
print(blog_post['id'])


def get_blog_post_by_id(post_id):
"""Get the blog by ID
GET /content/api/v2/blogs/:blog_id
"""
xurl = "/content/api/v2/blogs/" + str(post_id)
url = HS_API_URL + xurl + APIKEY
response = urlopen(url).read()
blog_info = json.loads(response)
return blog_info

def cancel_post(blog_post_id):
"""
Publish, schedule or unpublish a blog post
POST /content/api/v2/blog-posts/:blog_post_id/publish-action
"""
xurl = "/content/api/v2/blog-posts/" + str(blog_post_id) + "/publish-action"
url = HS_API_URL + xurl + APIKEY
# bin = "http://requestbin.fullcontact.com/1iiiiyo1"
headers = { "content-type" : "application/json" }
response = requests.post(url, headers=headers, data=json.dumps(CANCEL))
# pprint(response.status_code, response.content, response)
return response


# AUTOMATION FOR MANPOWERGROUP EMPLOYMENT OUTLOOK SURVEY (HUBSPOT)
def main():
# Create a draft version of the blog posts
create_batch_posts(1029596)
# Publish the drafts
publish_draft_posts(TEMPLATE_ID, 2, DRAFT)
print("Published")


main()


Please check out my gist for easier reading....







python python-3.x api rest






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 10 hours ago









200_success

128k15149412




128k15149412










asked 11 hours ago









FlySpaceAge

234




234












  • @200_success I have added the entire program to the post.
    – FlySpaceAge
    11 hours ago


















  • @200_success I have added the entire program to the post.
    – FlySpaceAge
    11 hours ago
















@200_success I have added the entire program to the post.
– FlySpaceAge
11 hours ago




@200_success I have added the entire program to the post.
– FlySpaceAge
11 hours ago










1 Answer
1






active

oldest

votes

















up vote
0
down vote













At the top, add a shebang:



#!/usr/bin/env python3


For this line:



APIKEY = "?hapikey=" + APIKEY_VALUE


You're doing string concatenation when the nicer thing to do is pass a dict to the params kwarg of requests. This also applies to the following lines:



xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
url = HS_API_URL + xurl


The alternative is:



url = f'{HS_API_URL}/hubdb/api/v2/tables/{table_id}/rows'
response = requests.get(url, params={'portalId': PORTAL_ID})


And for this line:



urlopen(url).read()


Why, if you have requests? Use requests instead.



table_data = json.loads(response)


For this, use requests; then you can write



table_data = response.json()


For this line:



"meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " +  str(name) + " | " + str(state) + ", " + str(country),


Stop doing so much string concatenation. Use f-string interpolation like I did above. The same applies to slug and others.



headers = { "content-type" : "application/json" }


You don't need to do that if you use requests and pass the json kwarg with your dict.



For this line:



main()


If someone else imports your file, you should give them the option of not running main. The standard way to do this is if __name__ == '__main__':






share|improve this answer





















    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209463%2fuse-python-along-with-the-hubspot-hubdb-api-and-the-blog-post-api-to-create-upd%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote













    At the top, add a shebang:



    #!/usr/bin/env python3


    For this line:



    APIKEY = "?hapikey=" + APIKEY_VALUE


    You're doing string concatenation when the nicer thing to do is pass a dict to the params kwarg of requests. This also applies to the following lines:



    xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
    url = HS_API_URL + xurl


    The alternative is:



    url = f'{HS_API_URL}/hubdb/api/v2/tables/{table_id}/rows'
    response = requests.get(url, params={'portalId': PORTAL_ID})


    And for this line:



    urlopen(url).read()


    Why, if you have requests? Use requests instead.



    table_data = json.loads(response)


    For this, use requests; then you can write



    table_data = response.json()


    For this line:



    "meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " +  str(name) + " | " + str(state) + ", " + str(country),


    Stop doing so much string concatenation. Use f-string interpolation like I did above. The same applies to slug and others.



    headers = { "content-type" : "application/json" }


    You don't need to do that if you use requests and pass the json kwarg with your dict.



    For this line:



    main()


    If someone else imports your file, you should give them the option of not running main. The standard way to do this is if __name__ == '__main__':






    share|improve this answer

























      up vote
      0
      down vote













      At the top, add a shebang:



      #!/usr/bin/env python3


      For this line:



      APIKEY = "?hapikey=" + APIKEY_VALUE


      You're doing string concatenation when the nicer thing to do is pass a dict to the params kwarg of requests. This also applies to the following lines:



      xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
      url = HS_API_URL + xurl


      The alternative is:



      url = f'{HS_API_URL}/hubdb/api/v2/tables/{table_id}/rows'
      response = requests.get(url, params={'portalId': PORTAL_ID})


      And for this line:



      urlopen(url).read()


      Why, if you have requests? Use requests instead.



      table_data = json.loads(response)


      For this, use requests; then you can write



      table_data = response.json()


      For this line:



      "meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " +  str(name) + " | " + str(state) + ", " + str(country),


      Stop doing so much string concatenation. Use f-string interpolation like I did above. The same applies to slug and others.



      headers = { "content-type" : "application/json" }


      You don't need to do that if you use requests and pass the json kwarg with your dict.



      For this line:



      main()


      If someone else imports your file, you should give them the option of not running main. The standard way to do this is if __name__ == '__main__':






      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        At the top, add a shebang:



        #!/usr/bin/env python3


        For this line:



        APIKEY = "?hapikey=" + APIKEY_VALUE


        You're doing string concatenation when the nicer thing to do is pass a dict to the params kwarg of requests. This also applies to the following lines:



        xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
        url = HS_API_URL + xurl


        The alternative is:



        url = f'{HS_API_URL}/hubdb/api/v2/tables/{table_id}/rows'
        response = requests.get(url, params={'portalId': PORTAL_ID})


        And for this line:



        urlopen(url).read()


        Why, if you have requests? Use requests instead.



        table_data = json.loads(response)


        For this, use requests; then you can write



        table_data = response.json()


        For this line:



        "meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " +  str(name) + " | " + str(state) + ", " + str(country),


        Stop doing so much string concatenation. Use f-string interpolation like I did above. The same applies to slug and others.



        headers = { "content-type" : "application/json" }


        You don't need to do that if you use requests and pass the json kwarg with your dict.



        For this line:



        main()


        If someone else imports your file, you should give them the option of not running main. The standard way to do this is if __name__ == '__main__':






        share|improve this answer












        At the top, add a shebang:



        #!/usr/bin/env python3


        For this line:



        APIKEY = "?hapikey=" + APIKEY_VALUE


        You're doing string concatenation when the nicer thing to do is pass a dict to the params kwarg of requests. This also applies to the following lines:



        xurl = "/hubdb/api/v2/tables/" + str(table_id) + "/rows?portalId=" + str(PORTAL_ID)
        url = HS_API_URL + xurl


        The alternative is:



        url = f'{HS_API_URL}/hubdb/api/v2/tables/{table_id}/rows'
        response = requests.get(url, params={'portalId': PORTAL_ID})


        And for this line:



        urlopen(url).read()


        Why, if you have requests? Use requests instead.



        table_data = json.loads(response)


        For this, use requests; then you can write



        table_data = response.json()


        For this line:



        "meta_description": str(quarter) + " ~ " + str(year) + " ~ " + str(date) + " | " + str(forecast) + " " + str(title) + " " +  str(name) + " | " + str(state) + ", " + str(country),


        Stop doing so much string concatenation. Use f-string interpolation like I did above. The same applies to slug and others.



        headers = { "content-type" : "application/json" }


        You don't need to do that if you use requests and pass the json kwarg with your dict.



        For this line:



        main()


        If someone else imports your file, you should give them the option of not running main. The standard way to do this is if __name__ == '__main__':







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 7 hours ago









        Reinderien

        1,714616




        1,714616






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209463%2fuse-python-along-with-the-hubspot-hubdb-api-and-the-blog-post-api-to-create-upd%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Morgemoulin

            Scott Moir

            Souastre