AdWords API, Reports, and Python (The Decent, the Ugly and the Good, respectively)
I’ve always been annoyed with the way the ReportService in the AdWords API works with most interpreted languages. Yes, you could say it’s a problem with SOAP (and it is), but I don’t buy that. Google engineers use Python enough that you’d think they would be more sensitive to this problem. The sample code given for reports is … disgusting. If you decide it’s too terrible to look at directly, let me fill you in. They build the XML manually in a string and then do something akin to an sprintf to fill in values. I know it’s just an example, but come on, that’s terrible.
I decided I couldn’t live like this and went about finding a better way. A few quick explanations:
- There may be a way to do this better in ZSI. I haven’t tried, I’m using SOAPpy.
- I’ll be using my AdWords client, but you can use any one you want, it’s just the conversion of the report data structure into a SOAPpy type that matters.
Alright, let’s get started, first I’ll set up the client:
import adwords.client as client
aw = client.AdWordsClient(
email='...',
password='...',
client_email='...',
developer_token='...',
application_token='...',
user_agent='...'
)
Now to build the report data structure. Of course, this is just an example so any of the data in this report could be different:
reportJob = {'selectedReportType': 'Account'}
reportJob['aggregationTypes'] = ['Daily']
reportJob['startDay'] = ‘2007-10-31′
reportJob['endDay'] = ‘2007-11-05′
reportJob['selectedColumns'] = [
'CustomerName',
'AdWordsType',
'CPC',
'CPM',
'Clicks'
]
I’ll now build a SOAPpy representation of the data. With most API calls you would be able to just plop that data structure into the call and SOAPpy would take care of it. With reports, however, Google makes a small statement at the top of the DefinedReportJob page:

To do this, you need to create a SOAPpy type and the set some attributes on that type. Here’s how I do it:
reportJob = SOAPpy.Types.structType(reportJob)
reportJob._setAttr('xmlns:impl', 'https://adwords.google.com/api/adwords/v11')
reportJob._setAttr('xsi:type', 'impl:DefinedReportJob')
As you can see, SOAPpy offers up some types. The structType is the best for dict objects, but if you run into other typing problems it supplies array types, string types, numerical types, etc. Now the only thing left to do is schedule the job:
jobId = int(aw.scheduleReportJob(reportJob))
It’s actually better practice to first validate your job with the new validateReportJob function in v11 of the API, but you get the picture.
There’s actually one additional problem I ran into when checking the status of a job. The Java service expects a long variable but if I cast it to long in Python, the API returns an error because it’s passed as a BigInt. I have no idea why it does this, but to get around it, I used some of SOAPpy’s types again:
status = aw.getReportJobStatus(SOAPpy.Types.longType(jobId))
Make sure your jobId variable is an int or SOAPpy will throw an exception.
So, I was able to get reports up and running and Python and I didn’t have to resort to archaic search and replace functionality in my code. I’ll probably be adding this to my AdWords client soon so I don’t have to think about it every time I create a report.
Leave a Reply