用Python的Django框架编写从Google Adsense中获得报表的应用
我完成了更新我们在Neutron的实时收入统计。在我花了一周的时间完成并且更新了我们的PHP脚本之后,我最终认决定开始使用Python进行抓取,这是值得我去花费我的时间和精力的事情。我建立了一个Django程序,它可以从不同的来源存储收入统计,我可以用这些去简历视图和用于统计工具的API。
所以在过去的几天里,我写了一个脚本,它可以登入到其他的网页并抓取数据,或者,如果这些网页有API,可以直接访问API。我发现了一些事情。
1.requests>httplib2(requests多于httplib2);
2.SOAP很糟糕,但它至少是一个API,Suds使SOAP好一点。我了解到SOAP是我说知道的API中,唯一一个完全基于.net开发的。
3.BeautifulSoup是一个很好的求助对象;
4.我确实十分惊讶,这么多企业能在如此蹩脚的技术中生存下来。
我拯救了GoogleAdsense,他们将会拥有最好的API,并且因此成为最简单的实现。他有着比我预想的要多的挑战。显然你无法仅仅插入用户名/密码或是APIkey去获取获得进入API的入口,你必须完成整个Oauth2的握手流程。
不幸的是,我发现文档不如我希望过得那样容易查询。我发现了很多死链接。我认为,在这方面Google的人应该做的更好。例如,在他们的uptodatedeveloperdocs文档中,我发现他们指出了brokenlinktoreadmoreaboutauthenticationandauthorization。(好的,多么奇怪,我尽快提交了这个问题,这个链接终于开始工作了,我猜你会感谢我。)
所以,这篇博客将尝试记录从Adsense获取报表到我的Django应用的过程。
为了使用Google的API来访问Adsense报表,你需要使用AdsenseManagementAPI.这个API只提供OAuth,所以你需要在浏览器中至少完成一次认证过程,来获取你的证书,然后你可以保存这些证书来进行下一步操作。说实话,我已经听说过OAuth很多次了,但是直到现在,我在实践中仍没有需要来使用它。所以我是边做边学,并欢迎大家留言指出我说的不对的地方。
就我所知,Google对于它的各种产品都拥有一个庞大的API。在研究Adsense之前,你需要在GoogleAPI控制台注册你的应用。我已经成功注册了我的应用。因为我还没有一个可用的URL地址,我现在暂时使用我的开发URL(localhost:8000)。它运作起来似乎正常。并使用提供的这个链接下载JSON文件。
还有,当你管理你的APIs的时候,你需要打开服务选项卡,打开AdSenseManagementAPI选项。否则,当你尝试发送请求的时候,你会得到一个错误消息“AccessNotConfigured”。
Google已经创建了一个Python客户端库,你可以轻易的通过pip来安装这个库。它还包含一个Django样例项目,这个项目使用这个库实现OAuth2的握手过程。我想,它是使用Django1.1编写的(因为在写这个项目的时候,Django1.5才刚刚发布),所以它可能有点过时,但是它可是一个好的开始点。
我的应用很简单。我只需要读取指定日期的收益金额,并保存到我的本地数据库。
我在djaongo项目中创建了一个新的应用,叫做“adsense”。并创建了一个models.py文件来存储认证证书。
fromdjango.contrib.auth.modelsimportUser
fromdjango.dbimportmodels
fromoauth2client.django_ormimportCredentialsField
classCredential(models.Model):
id=models.ForeignKey(User,primary_key=True)
credential=CredentialsField()
classRevenue(models.Model):
date=models.DateField(unique=True)
revenue=models.DecimalField(max_digits=7,decimal_places=2)
def__unicode__(self):
return'{0}${1}'.format(self.date,self.revenue)
我把从API控制台下载的JSON文件放到我的应用的文件夹下面,并创建了一个views.py文件
importos
fromdjango.confimportsettings
fromdjango.contrib.auth.decoratorsimportlogin_required
fromdjango.contrib.sites.modelsimportSite
fromdjango.httpimportHttpResponseBadRequest,HttpResponse
fromdjango.httpimportHttpResponseRedirect
fromoauth2clientimportxsrfutil
fromoauth2client.clientimportflow_from_clientsecrets
fromoauth2client.django_ormimportStorage
from.modelsimportCredential
CLIENT_SECRETS=os.path.join(os.path.dirname(__file__),'client_secrets.json')
FLOW=flow_from_clientsecrets(
CLIENT_SECRETS,
scope='https://www.googleapis.com/auth/adsense.readonly',
redirect_uri='http://{0}/adsense/oauth2callback/'.format(
Site.objects.get_current().domain))
@login_required
defindex(request):
storage=Storage(Credential,'id',request.user,'credential')
credential=storage.get()
ifcredentialisNoneorcredential.invalidisTrue:
FLOW.params['state']=xsrfutil.generate_token(settings.SECRET_KEY,
request.user)
authorize_url=FLOW.step1_get_authorize_url()
returnHttpResponseRedirect(authorize_url)
else:
returnHttpResponse('Alreadyvalidated.')
@login_required
defauth_return(request):
ifnotxsrfutil.validate_token(settings.SECRET_KEY,
request.REQUEST['state'],request.user):
returnHttpResponseBadRequest()
credential=FLOW.step2_exchange(request.REQUEST)
storage=Storage(Credential,'id',request.user,'credential')
storage.put(credential)
returnHttpResponseRedirect("/")
在urls.py文件中我包含了一个链接指向我的应用的url文件
mainurls.py:
fromdjango.conf.urlsimportpatterns,include,url
fromdjango.contribimportadmin
admin.autodiscover()
urlpatterns=patterns(
'',
url(r'^adsense/',include('adsense.urls',namespace='adsense')),
url(r'^admin/doc/',include('django.contrib.admindocs.urls')),
url(r'^admin/',include(admin.site.urls)),
)
adsense/urls.py:
fromdjango.conf.urlsimportpatterns,url
urlpatterns=patterns(
'adsense.views',
url(r'^$','index',name='index'),
url(r'^oauth2callback/$','auth_return',name='auth_return'),
)
最后,创建了一个通过给定日期调用API并获取收益的类。它放在adsense/tasks.py,因为我准备把它当作任务,钩在Celery/RabbitMQ之上。
importdatetime
importhttplib2
fromapiclient.discoveryimportbuild
fromdjango.contrib.auth.modelsimportUser
fromoauth2client.django_ormimportStorage
from.modelsimportCredential,Revenue
TODAY=datetime.date.today()
YESTERDAY=TODAY-datetime.timedelta(days=1)
classScraper(object):
defget_report(self,start_date=YESTERDAY,end_date=TODAY):
user=User.objects.get(pk=1)
storage=Storage(Credential,'id',user,'credential')
credential=storage.get()
ifnotcredentialisNoneorcredential.invalidisFalse:
http=httplib2.Http()
http=credential.authorize(http)
service=build('adsense','v1.2',http=http)
reports=service.reports()
report=reports.generate(
startDate=start_date.strftime('%Y-%m-%d'),
endDate=end_date.strftime('%Y-%m-%d'),
dimension='DATE',
metric='EARNINGS',
)
data=report.execute()
forrowindata['rows']:
date=row[0]
revenue=row[1]
record=Revenue()
try:
r=Revenue.objects.get(date=date)
pk=r.id
exceptRevenue.DoesNotExist:
pk=None
record.id=pk
record.date=date
record.revenue=revenue
record.save()
为了让它能工作起来,我在浏览器打开http://localhost:8000/adsense/。这时候会要求我登录Google帐号。我为我的应用授权来访问Adsense。然后,认证证书就会保存在我的本地数据库,然后我可以调用Scraperget_report()方法。祝贺我吧!。它能顺利工作了。