用Python的Django框架編寫從Google Adsense中獲得報(bào)表的應(yīng)用
我完成了更新我們?cè)?Neutron的實(shí)時(shí)收入統(tǒng)計(jì)。在我花了一周的時(shí)間完成并且更新了我們的PHP腳本之后,我最終認(rèn)決定開始使用Python進(jìn)行抓取,這是值得我去花費(fèi)我的時(shí)間和精力的事情。我建立了一個(gè) Django程序,它可以從不同的來(lái)源存儲(chǔ)收入統(tǒng)計(jì),我可以用這些去簡(jiǎn)歷視圖和用于統(tǒng)計(jì)工具的API。
所以在過去的幾天里,我寫了一個(gè)腳本,它可以登入到其他的網(wǎng)頁(yè)并抓取數(shù)據(jù),或者,如果這些網(wǎng)頁(yè)有 API,可以直接訪問 API。我發(fā)現(xiàn)了一些事情。
1.requests >httplib2(requests多于httplib2);
2.SOAP很糟糕,但它至少是一個(gè)API,Suds使SOAP好一點(diǎn)。我了解到SOAP是我說知道的API中,唯一一個(gè)完全基于.net開發(fā)的。
3.Beautiful Soup是一個(gè)很好的求助對(duì)象;
4.我確實(shí)十分驚訝,這么多企業(yè)能在如此蹩腳的技術(shù)中生存下來(lái)。
我拯救了 Google Adsense,他們將會(huì)擁有最好的API,并且因此成為最簡(jiǎn)單的實(shí)現(xiàn)。他有著比我預(yù)想的要多的挑戰(zhàn)。顯然你無(wú)法僅僅插入用戶名/密碼或是APIkey去獲取獲得進(jìn)入API的入口,你必須完成整個(gè)Oauth2的握手流程。
不幸的是,我發(fā)現(xiàn)文檔不如我希望過得那樣容易查詢。我發(fā)現(xiàn)了很多死鏈接。我認(rèn)為,在這方面Google的人應(yīng)該做的更好。例如,在他們的up to date developer docs文檔中,我發(fā)現(xiàn)他們指出了broken link to read more about authentication and authorization。(好的,多么奇怪,我盡快提交了這個(gè)問題,這個(gè)鏈接終于開始工作了,我猜你會(huì)感謝我。)
所以,這篇博客將嘗試記錄從Adsense獲取報(bào)表到我的Django應(yīng)用的過程。
為了使用Google的API來(lái)訪問Adsense報(bào)表,你需要使用Adsense Management API. 這個(gè)API只提供OAuth,所以你需要在瀏覽器中至少完成一次認(rèn)證過程,來(lái)獲取你的證書,然后你可以保存這些證書來(lái)進(jìn)行下一步操作。說實(shí)話,我已經(jīng)聽說過OAuth很多次了,但是直到現(xiàn)在,我在實(shí)踐中仍沒有需要來(lái)使用它。所以我是邊做邊學(xué),并歡迎大家留言指出我說的不對(duì)的地方。
就我所知,Google對(duì)于它的各種產(chǎn)品都擁有一個(gè)龐大的API。在研究Adsense之前,你需要在Google API 控制臺(tái)注冊(cè)你的應(yīng)用。我已經(jīng)成功注冊(cè)了我的應(yīng)用。因?yàn)槲疫€沒有一個(gè)可用的URL地址,我現(xiàn)在暫時(shí)使用我的開發(fā)URL(localhost:8000)。它運(yùn)作起來(lái)似乎正常。并使用提供的這個(gè)鏈接下載JSON文件。
還有,當(dāng)你管理你的APIs的時(shí)候,你需要打開服務(wù)選項(xiàng)卡,打開AdSense Management API選項(xiàng)。否則,當(dāng)你嘗試發(fā)送請(qǐng)求的時(shí)候,你會(huì)得到一個(gè)錯(cuò)誤消息“Access Not Configured”。
Google已經(jīng)創(chuàng)建了一個(gè)Python 客戶端庫(kù),你可以輕易的通過pip來(lái)安裝這個(gè)庫(kù)。它還包含一個(gè)Django樣例項(xiàng)目,這個(gè)項(xiàng)目使用這個(gè)庫(kù)實(shí)現(xiàn)OAuth2的握手過程。我想,它是使用Django 1.1編寫的(因?yàn)樵趯戇@個(gè)項(xiàng)目的時(shí)候,Django 1.5才剛剛發(fā)布),所以它可能有點(diǎn)過時(shí),但是它可是一個(gè)好的開始點(diǎn)。
我的應(yīng)用很簡(jiǎn)單。我只需要讀取指定日期的收益金額,并保存到我的本地?cái)?shù)據(jù)庫(kù)。
我在djaongo項(xiàng)目中創(chuàng)建了一個(gè)新的應(yīng)用,叫做“adsense”。并創(chuàng)建了一個(gè)models.py文件來(lái)存儲(chǔ)認(rèn)證證書。
from django.contrib.auth.models import User from django.db import models from oauth2client.django_orm import CredentialsField class Credential(models.Model): id = models.ForeignKey(User, primary_key=True) credential = CredentialsField() class Revenue(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控制臺(tái)下載的JSON文件放到我的應(yīng)用的文件夾下面,并創(chuàng)建了一個(gè)views.py文件
import os from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.sites.models import Site from django.http import HttpResponseBadRequest, HttpResponse from django.http import HttpResponseRedirect from oauth2client import xsrfutil from oauth2client.client import flow_from_clientsecrets from oauth2client.django_orm import Storage from .models import Credential 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 def index(request): storage = Storage(Credential, 'id', request.user, 'credential') credential = storage.get() if credential is None or credential.invalid is True: FLOW.params['state'] = xsrfutil.generate_token(settings.SECRET_KEY, request.user) authorize_url = FLOW.step1_get_authorize_url() return HttpResponseRedirect(authorize_url) else: return HttpResponse('Already validated.') @login_required def auth_return(request): if not xsrfutil.validate_token(settings.SECRET_KEY, request.REQUEST['state'], request.user): return HttpResponseBadRequest() credential = FLOW.step2_exchange(request.REQUEST) storage = Storage(Credential, 'id', request.user, 'credential') storage.put(credential) return HttpResponseRedirect("/")
在 urls.py 文件中我包含了一個(gè)鏈接指向我的應(yīng)用的url文件
main urls.py: from django.conf.urls import patterns, include, url from django.contrib import admin 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: from django.conf.urls import patterns, url urlpatterns = patterns( 'adsense.views', url(r'^$', 'index', name='index'), url(r'^oauth2callback/$', 'auth_return', name='auth_return'), )
最后,創(chuàng)建了一個(gè)通過給定日期調(diào)用API并獲取收益的類。它放在adsense/tasks.py,因?yàn)槲覝?zhǔn)備把它當(dāng)作任務(wù),鉤在 Celery/ RabbitMQ之上。
import datetime import httplib2 from apiclient.discovery import build from django.contrib.auth.models import User from oauth2client.django_orm import Storage from .models import Credential, Revenue TODAY = datetime.date.today() YESTERDAY = TODAY - datetime.timedelta(days=1) class Scraper(object): def get_report(self, start_date=YESTERDAY, end_date=TODAY): user = User.objects.get(pk=1) storage = Storage(Credential, 'id', user, 'credential') credential = storage.get() if not credential is None or credential.invalid is False: 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() for row in data['rows']: date = row[0] revenue = row[1] record = Revenue() try: r = Revenue.objects.get(date=date) pk = r.id except Revenue.DoesNotExist: pk = None record.id = pk record.date = date record.revenue = revenue record.save()
為了讓它能工作起來(lái),我在瀏覽器打開http://localhost:8000/adsense/。這時(shí)候會(huì)要求我登錄Google帳號(hào)。我為我的應(yīng)用授權(quán)來(lái)訪問Adsense。然后,認(rèn)證證書就會(huì)保存在我的本地?cái)?shù)據(jù)庫(kù),然后我可以調(diào)用Scraper get_report() 方法。祝賀我吧!。它能順利工作了。
- python實(shí)現(xiàn)自動(dòng)化報(bào)表功能(Oracle/plsql/Excel/多線程)
- ZABBIX3.2使用python腳本實(shí)現(xiàn)監(jiān)控報(bào)表的方法
- Python數(shù)據(jù)報(bào)表之Excel操作模塊用法分析
- Python實(shí)現(xiàn)定制自動(dòng)化業(yè)務(wù)流量報(bào)表周報(bào)功能【XlsxWriter模塊】
- 對(duì)python生成業(yè)務(wù)報(bào)表的實(shí)例詳解
- 使用Python快速制作可視化報(bào)表的方法
- python生成每日?qǐng)?bào)表數(shù)據(jù)(Excel)并郵件發(fā)送的實(shí)例
- python實(shí)現(xiàn)報(bào)表自動(dòng)化詳解
- Python實(shí)現(xiàn)導(dǎo)出數(shù)據(jù)生成excel報(bào)表的方法示例
- 如何使用Python自動(dòng)生成報(bào)表并以郵件發(fā)送
相關(guān)文章
TensorFlow2.X結(jié)合OpenCV 實(shí)現(xiàn)手勢(shì)識(shí)別功能
這篇文章主要介紹了TensorFlow2.X結(jié)合OpenCV 實(shí)現(xiàn)手勢(shì)識(shí)別功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04python找出列表中大于某個(gè)閾值的數(shù)據(jù)段示例
今天小編就為大家分享一篇python找出列表中大于某個(gè)閾值的數(shù)據(jù)段示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2019-11-11手把手教你實(shí)現(xiàn)PyTorch的MNIST數(shù)據(jù)集
本文主要介紹了PyTorch的MNIST數(shù)據(jù)集,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06Python多進(jìn)程共享numpy 數(shù)組的方法
這篇文章主要介紹了Python多進(jìn)程共享numpy 數(shù)組的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07python使用fork實(shí)現(xiàn)守護(hù)進(jìn)程的方法
守護(hù)進(jìn)程(Daemon)也稱為精靈進(jìn)程是一種生存期較長(zhǎng)的一種進(jìn)程。它們獨(dú)立于控制終端并且周期性的執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。他們常常在系統(tǒng)引導(dǎo)裝入時(shí)啟動(dòng),在系統(tǒng)關(guān)閉時(shí)終止。2017-11-11關(guān)于adfuller函數(shù)返回值的參數(shù)說明與記錄
這篇文章主要介紹了關(guān)于adfuller函數(shù)返回值的參數(shù)說明與記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11