[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

Eastmount發表於2019-01-31

前面作者講解了很多知識圖譜相關的原理知識,包括知識圖譜相關技術、Neo4j繪製關係圖譜等,但還是缺少一個系統全面的例項。為了加深自己對知識圖譜構建的認識,為後續建立貴州旅遊知識圖譜打下基礎,作者學習了張巨集倫老師的網易雲課程(星球系列電影),強烈推薦大家去學習,並結合自己的理解和技術分享了該系列專欄,從資料採集、資料分析到知識圖譜構建,文章後續會講解中文資料的實體識別、關係抽取、知識展示等。

這是一篇基礎性文章,希望對您有所幫助 ,尤其是剛入門的同學。同時也是因為最近準備博士考試,做題做吐了,寫點新東西調節下心情,與君共勉,一起加油。

下載地址:https://download.csdn.net/download/eastmount/10947419


[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

推薦作者的知識圖譜前文:
知識圖譜相關會議之觀後感分享與學習總結
中文知識圖譜研討會的學習總結 (上) 圖譜引入、百度知心、搜狗知立方
搜尋引擎和知識圖譜那些事 (上).基礎篇
基於VSM的命名實體識別、歧義消解和指代消解

CSDN下載-第一屆全國中文知識圖譜研討會演講PPT 清華大學
CSDN下載-知識圖譜PDF資料 清華大學知識圖譜研討會彙報PPT

[知識圖譜構建] 一.Neo4j圖資料庫安裝初識及藥材供應圖譜例項
[知識圖譜構建] 二.《Neo4j基礎入門》基礎學習之建立圖資料庫節點及關係
[關係圖譜] 一.Gephi通過共線矩陣構建知網作者關係圖譜
[關係圖譜] 二.Gephi匯入共線矩陣構建作者關係圖譜

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

再次強烈推薦大家閱讀張巨集倫老師的網易雲課程及Github原始碼,受益匪淺。
https://github.com/Honlan/starwar-visualization/tree/master/star_war
https://study.163.com/course/courseLearn.htm?courseId=1003528010

張老師最終成果如下所示:http://zhanghonglun.cn/starwars/

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

一.目標網站

我們的目標是構建一個《星球大戰》7部電影的知識圖譜,首先需要獲取電影資料資訊,常規的方法是通過豆瓣進行抓取,但是豆瓣收錄的資訊不完整,這裡爬取 SWAPI 這個網站。
網址:https://swapi.co/documentation

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

這是全球首個量化的、可供程式設計使用的星球大戰資料集,開發者彙總了星戰系列電影中涉及的多個種類實體資料。它同時提供了Python程式語言包,swapi-python is built by the author of swapi, Paul Hallett。六個API對應六類實體:

如下圖表示Films提供的JSON格式資料。

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

通過http訪問網址 https://swapi.co/api/films/1/ 即可獲取如下所示的資料,包括電影標題《A New Hope》,這是第4部,人物實體characters對應的連結。

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

二.抓取電影films頁面

接著寫爬蟲獲取基本電影的資料,迴圈遍歷 https://swapi.co/api/films/7 七部電影的資訊。

Python3 完整程式碼如下:
get_files.py

# coding: utf-8
import urllib.request as urllib2

#定義陣列存所有電影
films = []

#迴圈寫入七部電影的連結《星球大戰》
for x in range(1,8):
    films.append('https://swapi.co/api/films/'+str(x)+'/')
    
#定義headers 防止網站反扒 Window系統
headers = {}
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36"

#寫入檔案
with open('films.csv','w') as file:
    for item in films:
        print(item)
        #請求訪問網站
        request = urllib2.Request(url=item, headers=headers)
        #url開啟
        response = urllib2.urlopen(request)
        result = response.read().decode('utf-8')
        print(result)
        file.write(result+"\n")

該程式獲取了7部電影的JSON資訊,並儲存至films.csv檔案中,如下圖所示:

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

其中一部電影的完整資訊如下:

HTTP 200 OK
Content-Type: application/json
Vary: Accept
Allow: GET, HEAD, OPTIONS

{
    "title": "A New Hope", 
    "episode_id": 4, 
    "opening_crawl": "It is a period of civil war.\r\nRebel spaceships, striking\r\nfrom a hidden base....", 
    "director": "George Lucas", 
    "producer": "Gary Kurtz, Rick McCallum", 
    "release_date": "1977-05-25", 
    "characters": [
        "https://swapi.co/api/people/1/", 
        "https://swapi.co/api/people/2/", 
        "https://swapi.co/api/people/3/", 
        "https://swapi.co/api/people/4/", 
        "https://swapi.co/api/people/5/", 
        "https://swapi.co/api/people/6/", 
        "https://swapi.co/api/people/7/", 
        "https://swapi.co/api/people/8/", 
        "https://swapi.co/api/people/9/", 
        "https://swapi.co/api/people/10/", 
        "https://swapi.co/api/people/12/", 
        "https://swapi.co/api/people/13/", 
        "https://swapi.co/api/people/14/", 
        "https://swapi.co/api/people/15/", 
        "https://swapi.co/api/people/16/", 
        "https://swapi.co/api/people/18/", 
        "https://swapi.co/api/people/19/", 
        "https://swapi.co/api/people/81/"
    ], 
    "planets": [
        "https://swapi.co/api/planets/2/", 
        "https://swapi.co/api/planets/3/", 
        "https://swapi.co/api/planets/1/"
    ], 
    "starships": [
        "https://swapi.co/api/starships/2/", 
        "https://swapi.co/api/starships/3/", 
        "https://swapi.co/api/starships/5/", 
        "https://swapi.co/api/starships/9/", 
        "https://swapi.co/api/starships/10/", 
        "https://swapi.co/api/starships/11/", 
        "https://swapi.co/api/starships/12/", 
        "https://swapi.co/api/starships/13/"
    ], 
    "vehicles": [
        "https://swapi.co/api/vehicles/4/", 
        "https://swapi.co/api/vehicles/6/", 
        "https://swapi.co/api/vehicles/7/", 
        "https://swapi.co/api/vehicles/8/"
    ], 
    "species": [
        "https://swapi.co/api/species/5/", 
        "https://swapi.co/api/species/3/", 
        "https://swapi.co/api/species/2/", 
        "https://swapi.co/api/species/1/", 
        "https://swapi.co/api/species/4/"
    ], 
    "created": "2014-12-10T14:23:31.880000Z", 
    "edited": "2015-04-11T09:46:52.774897Z", 
    "url": "https://swapi.co/api/films/1/"
}

下面補充下如何獲取headers值,瀏覽器審查元素檢視Network中的Headers實現。

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

三.抓取所有實體頁面

最後需要獲取每一部電影中所有實體資訊,包括以下五種實體,然後構建這些實體之間的關係。

  • ‘characters’ 人物
  • ‘planets’ 星球
  • ‘starships’ 飛船
  • ‘vehicles’ 裝備
  • ‘species’ 種族

這些實體可以通過遍歷電影films實體中的元素,如charaters屬性如下,表示一個個連結。再通過Request獲取每一個實體的詳細資訊。

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

這裡補充一個知識點,從檔案讀取的資料是字串格式,需要轉換為字典格式,才能供JSON查詢,程式碼如下:

import json

#json.loads函式:將字串轉化為字典
json_info = '{"age": "12"}'
dict1 = json.loads(json_info)
print(str(type(json_info)), json_info)
print(str(type(dict1)), dict1)
print(dict1['age'])

輸出結果如下:

<class 'str'> {"age": "12"}
<class 'dict'> {'age': '12'}
12

完整程式碼如下所示:
get_details.py

# coding: utf-8
import urllib.request as urllib2
import json

#設定headers
headers = {}
headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36"

#讀取檔案-讀取json資訊並將json格式資料轉換為字典
f = open('films.csv', 'r', encoding='utf-8')
films = []
for line in f.readlines():
    #print(line)
    print(line.strip('\n'))
    line = json.loads(line.strip('\n'))
    films.append(line)
f.close()

#遍歷每部電影films的實體並獲取其他實體
#獲取 characters人物, planets星球, starships飛船, vehicles裝備, species種族
targets = ['characters', 'planets', 'starships', 'vehicles', 'species']

for target in targets:
    print(target)
    #迴圈獲取五類資料並儲存至檔案
    fw = open('film_' + target + '.csv', 'w')
    data = []
    #獲取7部電影資訊的實體名稱
    for item in films:  
        tmp = item[target]  #實體對應的連結
        print(tmp)
        for t in tmp:
            if t in data: #如果實體已經存在則跳過 比如某部電影人物另一部也出現了
                continue
            else:
                data.append(t)
            
            #迴圈請求直到成功 防止網路延遲
            while 1:
                try:
                    print(t)
                    request = urllib2.Request(url=t, headers=headers)
                    response = urllib2.urlopen(request)
                    result = response.read().decode('utf-8')
                except Exception as e:
                    continue #請求失敗迴圈繼續
                else:
                    fw.write(result+"\n")
                    break #請求成功跳出迴圈
                finally:
                    pass
                
    #檢視七部電影含這種實體多少個
    print(str(len(data)), target)
    fw.close()

print("success")

該程式共抓取87名角色、21顆星球、37艘飛船、39架戰車、37個種族,以及這228個實體之間的1112次聯絡。

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

獲取的檔案資料如下所示:

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體
[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

講到這裡第一篇文章敘述完畢,快去嘗試吧!後續將開展分析及實體、關係、屬性的提取。


PS:最近參加CSDN2018年部落格評選,希望您能投出寶貴的一票。我是59號,Eastmount,楊秀璋。投票地址:https://bss.csdn.net/m/topic/blog_star2018/index

[知識圖譜實戰篇] 一.資料抓取之Python3抓取JSON格式的電影實體

五年來寫了320篇部落格,12個專欄,是真的熱愛分享,熱愛CSDN這個平臺,也想幫助更多的人,專欄包括Python、資料探勘、網路爬蟲、影象處理、C#、Android等。現在也當了兩年老師,更是覺得有義務教好每一個學生,讓貴州學子好好寫點程式碼,學點技術,“師者,傳到授業解惑也”,提前祝大家新年快樂。2019我們攜手共進,為愛而生。

(By:Eastmount 2019-01-31 下午2點 http://blog.csdn.net/eastmount/)

相關文章