Github API: 用python爬取相關(guān)數(shù)據(jù)

這學(xué)期選修《社會網(wǎng)絡(luò)分析》需要爬取些數(shù)據(jù)懦鼠,剛接觸python對爬蟲還不是很熟悉,過程中遇到一些問題,把心得分享給同樣學(xué)習(xí)python爬蟲的同學(xué)。

  • 教科書般的API接口信息
    Github作為一個出色的代碼托管平臺劫侧,也為開發(fā)者們提供了結(jié)構(gòu)非常清晰的API接口信息,瀏覽器安裝json插件后閱讀更佳哨啃。
  • 詳細的開發(fā)者文檔
    想了解相關(guān)參數(shù)設(shè)置和可爬取的數(shù)據(jù)烧栋,可閱讀Github Developer Guide
  • 爬取目標(biāo):
    "digital,library"主題下的開源項目合作情況,包含加權(quán)貢獻值commit,additions,deletions.

  • 注意事項:
    Github的關(guān)鍵詞檢索功能比較有限棘催,用雙引號和逗號相結(jié)合表示AND檢索.

  • 邏輯思路:

    • 先通過repository_search_url 獲取檢索結(jié)果下的項目信息
      https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}
  • 再根據(jù)項目信息中的{owner}{name}信息傳遞到stats/contributors頁面獲取相關(guān)和做貢獻信息
    https://api.github.com/repos/{owner}/{name}/stats/contributors

  • 問題思考:

  1. 使用urlopen()需要導(dǎo)入劲弦、安裝什么包耳标?如何導(dǎo)入urllib包醇坝?
    python3.x已經(jīng)包含urlllib包,無需再安裝,且不同于以往的urllib2呼猪,urllib分為urllib.requesturllib.error画畅,導(dǎo)入urlopen的方法
from urllib.request import urlopen
  1. 如何解決API Rate Limiting限制?
    初次爬取到的數(shù)據(jù)只有200多條記錄宋距,與事先的搜索結(jié)果不符轴踱,而且返回http error 403 forbidden,訪問請求被禁止谚赎,閱讀Github Developer Guide后才發(fā)現(xiàn)未經(jīng)過認證的請求上限是60次/hour淫僻,打開api url也會發(fā)現(xiàn)該頁只有30條記錄,為了爬取到較為完整的數(shù)據(jù)壶唤,需要添加Authentication認證Pagination分頁
  2. 如何實現(xiàn)Authentication認證
    Github提供了三種認證方式雳灵,考慮到源碼分享后的賬戶安全問題,用戶+密碼認證方式不太建議使用闸盔,另外就是令牌訪問方式悯辙。
    首先是如何生成令牌,在你的個人主頁setting/personal access token/ generate new token迎吵,把生成的token復(fù)制保存下來躲撰,后面即將用到
  • 方法一:sent in a header
    一開始我是這么請求的
headers = {'Authorization':'ef802a122df2e4d29d9b1b868a6fefb14f22b272'}

然后得到了http error 401 unauthorizated,以為是令牌的問題regenerate了幾次击费,后來才發(fā)現(xiàn)是要加上token前綴拢蛋,網(wǎng)上很多教程都提到要如何生成tokentoken要加在headers里蔫巩,但真的很少提到這點瓤狐,敲這篇文章的時候發(fā)現(xiàn)Github Developer Guide已經(jīng)寫得很清楚了(閱讀說明文檔很重要-攤手.jpg)

headers = {'User-Agent':'Mozilla/5.0',
               'Authorization': 'token ef802a122df2e4d29d9b1b868a6fefb14f22b272',
               'Content-Type':'application/json',
               'Accept':'application/json'
               }
  • 方法二:sent as a parameter
 https://api.github.com/?access_token=OAUTH-TOKEN
  1. 如何實現(xiàn)對結(jié)果分頁?
    Github一頁的上限是100,在后面加上page=1&per_page=100即可批幌,建議加上升序或降序排列础锐,后續(xù)處理數(shù)據(jù)將更加方便,根據(jù)star值降序排列采用的是e.g.
https://api.github.com/search/repositories?q={search}&page=4&per_page=100&sort=stars&order=desc
  1. json解析器錯誤
    raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    網(wǎng)上很多人都遇到了該問題荧缘,起初我也以為我也是皆警,有點奇怪的是我在爬取第一頁時沒有該報錯,是后面才有的......
    JSON(JavaScript Object Notation)是一種輕量級的數(shù)據(jù)交換格式截粗,可以簡單把它理解為list數(shù)組字符串信姓,我們的目的是要將已編碼的 JSON 字符串解碼為 Python 對象來處理
response = urlopen(req).read()
result = json.loads(response.decode())

注意必須要加上decode(),如果涉及到中文還要加上具體的編碼方式如decode('utf-8')绸罗,因為在這里response返回的頁面信息是bytes意推,我們要把他轉(zhuǎn)為string
顯然我并不是這類解碼問題,我也嘗試把json的單引號替換成雙引號珊蟀,然而并沒有什么用菊值,這個問題真的弄得我寢食難安了一兩天。直到我看到某個論壇里有人說可能你要解析的object就是空list,這我需要驗證一下了腻窒,于是我在代碼中加上了print(item['name'])昵宇,果然在打印了十幾條后中止了又跳出該報錯,我拿出事先爬取的RepoList比對(這個時候你會發(fā)現(xiàn)當(dāng)初的降序排列是個多么明智的選擇)
到該停止結(jié)點的頁面去看發(fā)現(xiàn)果然是空的(由于時間和權(quán)限關(guān)系儿子,某些repositories已經(jīng)失效或者沒有contributors信息)瓦哎,只有{},所以需要在代碼中加上判斷條件柔逼,但并不是頁面為空蒋譬,而是列表為空,前面提到可以簡單把json理解成list數(shù)組愉适,所以判斷條件是len(JSON)是否為0

完善后成功爬取數(shù)據(jù)的代碼如下:

from urllib.request import urlopen
from urllib.request import Request
import datetime
import json

def get_statistics(owner,name,headers):
    url = 'https://api.github.com/repos/{owner}/{name}/stats/contributors?page=2&per_page=100'.format(owner=owner, name=name)
    req = Request(url,headers=headers)
    response = urlopen(req).read()
    if len(response)==0:
        return response
    else:
        result = json.loads(response.decode())
        return result

def get_results(search,headers):
    url = 'https://api.github.com/search/repositories?q={search}&page=4&per_page=100&sort=stars&order=desc'.format(search=search)
    req = Request(url,headers=headers)
    response = urlopen(req).read()
    result = json.loads(response.decode())
    return result
    

if __name__ == '__main__':
    # 這里用不用轉(zhuǎn)義符沒差別
    search = '\"digital,library\"'
    
    headers = {'User-Agent':'Mozilla/5.0',
               'Authorization': 'token ef802a122df2e4d29d9b1b868a6fefb14f22b272',
               'Content-Type':'application/json',
               'Accept':'application/json'
               }

    results = get_results(search,headers)

    f = open('ContributorsInfo4.txt', 'w')
    for item in results['items']:
        name = item['name']
        star = item['stargazers_count']
        owner = item['owner']['login']
        language = str('0') 
        user = str('0')
        commits = 0
        language = item['language']
        stats = get_statistics(owner,name,headers)
        contributor_list = []
        count = len(stats)
        for i in range(0,count):
            user = stats[i]['author']['login']
            commits = stats[i]['total']
            deletions = 0
            additions = 0
            first_commit = None
            last_commit = None
            for week in stats[i]['weeks']:
                deletions += week['d']
                additions += week['a']
                # assume that weeks are ordered
                if first_commit is None and week['c'] > 0:
                    first_commit = week['w']
                if week['c'] > 0:
                    last_commit = week['w']
            contributor_list.append([name,
                                     owner,
                                     star,
                                     language,
                                     count,
                                     user,
                                     commits,
                                     additions,
                                     deletions,
                                     datetime.datetime.fromtimestamp(first_commit).strftime('%Y-%m-%d'),
                                     datetime.datetime.fromtimestamp(last_commit).strftime('%Y-%m-%d')
                                    ])
        for contributor in contributor_list:
            print(contributor,file = f)

參考項目 Github
詳細接口信息 API接口
請詳細閱讀 Github Developer Guide

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末羡铲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子儡毕,更是在濱河造成了極大的恐慌也切,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腰湾,死亡現(xiàn)場離奇詭異雷恃,居然都是意外死亡,警方通過查閱死者的電腦和手機费坊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門倒槐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人附井,你說我怎么就攤上這事讨越。” “怎么了永毅?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵把跨,是天一觀的道長。 經(jīng)常有香客問我沼死,道長着逐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任意蛀,我火速辦了婚禮耸别,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘县钥。我一直安慰自己秀姐,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布若贮。 她就那樣靜靜地躺著省有,像睡著了一般痒留。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锥咸,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音细移,去河邊找鬼搏予。 笑死,一個胖子當(dāng)著我的面吹牛弧轧,可吹牛的內(nèi)容都是我干的雪侥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼精绎,長吁一口氣:“原來是場噩夢啊……” “哼速缨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起代乃,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤旬牲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后搁吓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體原茅,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年堕仔,在試婚紗的時候發(fā)現(xiàn)自己被綠了擂橘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡摩骨,死狀恐怖通贞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恼五,我是刑警寧澤昌罩,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站灾馒,受9級特大地震影響峡迷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜你虹,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一绘搞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧傅物,春花似錦夯辖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圆米。三九已至,卻和暖如春啄栓,著一層夾襖步出監(jiān)牢的瞬間娄帖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工昙楚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留近速,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓堪旧,卻偏偏與公主長得像削葱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淳梦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1 前言 作為一名合格的數(shù)據(jù)分析師析砸,其完整的技術(shù)知識體系必須貫穿數(shù)據(jù)獲取、數(shù)據(jù)存儲爆袍、數(shù)據(jù)提取首繁、數(shù)據(jù)分析、數(shù)據(jù)挖掘陨囊、...
    whenif閱讀 18,061評論 45 523
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蛮瞄,服務(wù)發(fā)現(xiàn),斷路器谆扎,智...
    卡卡羅2017閱讀 134,629評論 18 139
  • # Python 資源大全中文版 我想很多程序員應(yīng)該記得 GitHub 上有一個 Awesome - XXX 系列...
    aimaile閱讀 26,448評論 6 428
  • 譯自 《You Can Ignore Your Competitors, But Don’t Ignore The...
    hfcorriez閱讀 556評論 2 4
  • 我本就不是一個善解人意溫暖體貼的人 你也不必傷心失望我沒能給點安慰和擁抱 你在回憶過往 覺得我狠心絕情冷漠 卻不曾...
    Heidi610閱讀 223評論 3 1