Now that you know how to make requests to the Google Search Console API using Python, you’re probably well on your way to automating a lot of tasks and analyzing a lot of SEO data at scale!
If you’re anything like me, you’ve been copying and pasting the same codes from the API Connection and the API Requests into all of the scripts you’ve been writing. That’s a perfectly fine way to do it, but there’s a simpler way! I’m going to teach you how to write the scripts we’ve learned in previous articles and set them up in your directories in a way that will allow us to import the file and use the functions (we’ll be defining them here) to execute your requests.
What I won’t be showing you here is how to create a package that you can install via pip. Although we will be creating a large portion of what we need to in order to make a pip-installable package, that is a more advanced method and is beyond the scope of this article.
Creating Importable Python Script
I won’t spend much time on the individual components of this since I’ve covered them in previous articles, but I will be including every piece of the puzzle here.
The first step is that we are going to import our modules and define the function to authorize our API just like we did in the Connecting to the Google Search Console API with Python article.
# Import Modules
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
# Define function to get authorization
def gsc_auth(scopes):
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', scopes)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', scopes)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
service = build('searchconsole', 'v1', credentials=creds)
return service
That should look very familiar to you if you’ve been following the previous articles.
The next thing we’re going to do is turn each of the four reports we went over in the Google Search Console Python API Requests article into functions that we can call. I personally find it difficult to remember exactly which functions to chain together for each one without a reference, so I like to turn them into functions with arguments for everything we’ll need to make the requests.
# Define List of Sites Function
def get_sites(service):
return service.sites().list().execute()
# Define List of Sitemaps Function
def get_sitemaps(service, property_uri):
return service.sitemaps().list(siteUrl=property_uri).execute()
# Define Query Execution Function
def query_gsc(service, property_uri, request):
return service.searchanalytics().query(siteUrl=property_uri, body=request).execute()
# Define Inspect URL Function
def inspect_url(service, request):
return service.urlInspection().index().inspect(body=request).execute()
This is the general gist of the script. However, as someone likely starting out in Python, you might run this code and say, “This script doesn’t actually do anything.” And you’re kinda right. We’ll want to test to make sure these functions are working.
scopes = ['https://www.googleapis.com/auth/webmasters']
service = gsc_auth(scopes)
gsc_sites = get_sites(service)
gsc_sitemaps = get_sitemaps(service, 'sc-domain:shortautomaton.com')
sa_request = {
"startDate": "2022-03-01",
"endDate": "2022-03-15",
"dimensions": [
"QUERY",
"PAGE"
],
"rowLimit": 10
}
gsc_search_analytics = query_gsc(service, 'sc-domain:shortautomaton.com', sa_request)
inspect_request = {
"siteUrl": "sc-domain:shortautomaton.com",
"inspectionUrl": "https://www.shortautomaton.com/",
}
gsc_inspect = inspect_url(service, inspect_request)
I’m not going to bother showing you the output of these since we covered them in the other article. You can trust that these are working properly.
But we’re not finished. If we were to leave this as it is and import the script into another script, it will run the whole thing and we don’t want that because we don’t need to re-run our test every time. We could just delete it out, I suppose, but the best way to handle this is using an IF statement. You might have seen one like it before. Check it out.
if __name__ == '__main__':
scopes = ['https://www.googleapis.com/auth/webmasters']
service = gsc_auth(scopes)
gsc_sites = get_sites(service)
gsc_sitemaps = get_sitemaps(service, 'sc-domain:shortautomaton.com')
sa_request = {
"startDate": "2022-03-01",
"endDate": "2022-03-15",
"dimensions": [
"QUERY",
"PAGE"
],
"rowLimit": 10
}
gsc_search_analytics = query_gsc(service, 'sc-domain:shortautomaton.com', sa_request)
inspect_request = {
"siteUrl": "sc-domain:shortautomaton.com",
"inspectionUrl": "https://www.shortautomaton.com/",
}
gsc_inspect = inspect_url(service, inspect_request)
I’ll try to keep this simple. Under the hood, every script gets assigned a __name__
attribute at the time it is called upon. The script file you are running is assigned the __name__
“__main__”. Any imported scripts will be named differently.
As a result, when we are checking if the __name__
is equal to "__main__"
, we are basically asking if the script we are calling is the “home” script as opposed to an imported script. If it is, we run everything indented under it, just like a regular IF statement. This allows us to run our tests on the script without running the tests when it is imported. Cool stuff, right?
A quick note, I’m calling them tests, but as you become a more advanced developer, testing can mean something pretty different. That’s well beyond the scope of this article, so don’t sweat it for now.
Go ahead and save this file as gsc_api.py
in a folder of your choice. In the same folder, add your credentials.json
file.
Full Code for gsc_api.py
# Import Modules
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
# Define function to get authorization
def gsc_auth(scopes):
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', scopes)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', scopes)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
service = build('searchconsole', 'v1', credentials=creds)
return service
# Define List of Sites Function
def get_sites(service):
return service.sites().list().execute()
# Define List of Sitemaps Function
def get_sitemaps(service, property_uri):
return service.sitemaps().list(siteUrl=property_uri).execute()
# Define Query Execution Function
def query_gsc(service, property_uri, request):
return service.searchanalytics().query(siteUrl=property_uri, body=request).execute()
# Define Inspect URL Function
def inspect_url(service, request):
return service.urlInspection().index().inspect(body=request).execute()
if __name__ == '__main__':
scopes = ['https://www.googleapis.com/auth/webmasters']
service = gsc_auth(scopes)
gsc_sites = get_sites(service)
gsc_sitemaps = get_sitemaps(service, 'sc-domain:shortautomaton.com')
sa_request = {
"startDate": "2022-03-01",
"endDate": "2022-03-15",
"dimensions": [
"QUERY",
"PAGE"
],
"rowLimit": 10
}
gsc_search_analytics = query_gsc(service, 'sc-domain:shortautomaton.com', sa_request)
inspect_request = {
"siteUrl": "sc-domain:shortautomaton.com",
"inspectionUrl": "https://www.shortautomaton.com/",
}
gsc_inspect = inspect_url(service, inspect_request)
Importing gsc_api.py Into Another Script
Within the Same Folder
In the same folder, create a new script. I called it proof_of_importability.py
. Very original.
Now your folder might look something like this:
- folder
- credentials.json
- gsc_api.py
- proof_of_importability.py
You might also have a token.json
in there, if you’ve tested gsc_api.py
.
Depending on your IDE, this might become super obvious immediately that it works. Just for fun, let’s write some code.
import gsc_api
scopes = ['https://www.googleapis.com/auth/webmasters']
service = gsc_api.gsc_auth(scopes)
sites = gsc_api.get_sites(service)
verified_sites = [site['siteUrl'] for site in sites['siteEntry']
if site['permissionLevel'] != 'siteUnverifiedUser']
print('\n'.join(verified_sites))
And let’s run it. Provided you followed along with this correctly, you should get something like this:
"https://www.shortautomaton.com/"
"http://www.shortautomaton.com/"
"https://shortautomaton.com/"
"http://shortautomaton.com/"
"sc-domain:shortautomaton.com"
Within a Child/Descendant Folder
This also works if you create a gsc_api_module
folder with gsc_api.py
in it.
So now your directory structure might look like this:
- folder
- gsc_api_module
- gsc_api.py
- credentials.json
- proof_of_importability.py
- gsc_api_module
We’re going to slightly change proof_of_importability.py
with the code below.
from gsc_api_module import gsc_api
scopes = ['https://www.googleapis.com/auth/webmasters']
service = gsc_api.gsc_auth(scopes)
sites = gsc_api.get_sites(service)
verified_sites = [site['siteUrl'] for site in sites['siteEntry']
if site['permissionLevel'] != 'siteUnverifiedUser']
print('\n'.join(verified_sites))
Go ahead and run it. You should see the same output as before.
Other Importing Methods
There are ways to import from a parent or ancestor folder tree, but it is nowhere near as straightforward. To keep this guide as useful as possible for beginners, I’m not going to cover those. They involved importing other modules to set directories to the PATH programmatically with built-in modules. It’s a headache. At that point, you’re better off creating a Python package to install via pip, which, as I mentioned at the beginning, I also won’t be covering.
As a final tip, I prefer using the second method. With the second method, I can just copy and paste the entire folder to the various folders I do my work. This keeps my credentials and token files with them as well while also reducing the clutter for the code I’m working in.
Eric is a Python SEO with a passion for data. He uses Python to automate tasks and analyze large data sets. He is often the go-to for spreadsheet challenges, too. He sees every challenge as an opportunity to learn.