Python實現“維基百科六度分隔理論“之MySQL數據存儲

MySQL Python 維基百科 編程語言 AiryData 2017-04-05

Python實現“維基百科六度分隔理論“之MySQL數據存儲

預備閱讀:Python實現“維基百科六度分隔理論“之基礎爬蟲

前言

上一篇我們學習了數據採集中一個頁面跳轉到另一個頁面的簡單爬蟲,雖然獲取了這些鏈接數據,但是由於鏈接數目太多,不好查看,所以我們要想辦法存儲起來。

這裡使用MySQL進行數據存儲,關於MySQL的使用,以及使用Python操作MySQL,在我之前的文章中都有提到。不瞭解的同學,右上角搜索一下歷史文章即可,或文章底部的相關文章也會有。


MySQL中的“六度空間遊戲”

前面我們已經建立了網絡爬蟲來採集網頁,今天我們要把採集到的信息用數據庫存儲起來,方便後面進行數據分析。MySQL基礎知識,在我之前的文章中說的已經很多了,這裡不再贅述,默認同學已經瞭解了MySQL。

為了確定最合理的信息存儲方式,我們要先想一下我們的處理規則。一個鏈接可以輕易地把頁面A連接到頁面B,就像百度搜索,搜出來的結果就可以鏈接到我的網站。同樣也可以把頁面B連接到頁面A,我只需要把百度的網址插入到這篇文章就可以,不過這就是另一條鏈接了。所以我們可以這樣識別一個鏈接:即“頁面A存在一個鏈接,可以連接到頁面B”。也就是說,INSERT INTO links(fromPageId, toPageId) VALUES(A, B);其中A和B分別表示頁面的ID號。

這裡我們設計一個帶有兩張數據表的數據庫來分別存儲頁面和鏈接,兩張表都帶有創建時間和獨立的ID號,代碼如下:

CREATE TABLE `wiki`.`pages`(

`id` INT NOT NULL AUTO_INCREMENT COMMENT '自增id,主鍵',

`url` VARCHAR(255) NOT NULL,

`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY(`id`)

);

CREATE TABLE `wiki`.`links`(

`id` INT NOT NULL AUTO_INCREMENT COMMENT '自增id,主鍵',

`fromPageId` INT NULL,

`toPageId` INT NULL,

`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY(`id`)

);

需要注意的是,這裡我沒有創建標題字段,因為,一般情況下,只有點擊鏈接進去才能看到網頁標題,不過對於維基百科來說還好,wiki的詞條鏈接和對應的頁面標題直接轉換一下就可以,例如en.wikipedia.org/wiki/Monty_Python的後面就是頁面標題Monty Python。

下面我們來寫一下把“貝肯數”(一個頁面與凱文·貝肯詞條頁面的鏈接數)不超過6的維基百科頁面存儲起來。

from urllib.request import urlopen

from bs4 import BeautifulSoup

import re

import pymysql

#連接時,密碼要換成自己的

conn = pymysql.connect(host = '127.0.0.1', port = 3306, user = 'root', passwd = 'xxxxxxxx', db = 'wiki', charset = 'utf8mb4')

cur = conn.cursor()

#cur.execute("USE wiki")

def insertPageIfNotExists(url):

cur.execute("SELECT * FROM pages WHERE url = %s", (url))

if cur.rowcount == 0:

cur.execute("INSERT INTO pages (url) VALUES (%s)", (url))

conn.commit()

return cur.lastrowid

else:

return cur.fetchone()[0]

def insertLink(fromPageId, toPageId):

cur.execute("SELECT * FROM links WHERE fromPageId = %s AND toPageId = %s", (int(fromPageId), int(toPageId)))

if cur.rowcount == 0:

cur.execute("INSERT INTO links (fromPageId, toPageId) VALUES(%s, %s)", (int(fromPageId), int(toPageId)))

conn.commit()

pages = set()

def getLinks(pageUrl, recursionLevel):

global pages

if recursionLevel > 4:

return;

pageId = insertPageIfNotExists(pageUrl)

html = urlopen("http://en.wikipedia.org" + pageUrl)

soup = BeautifulSoup(html, "lxml")

for link in soup.findAll("a", href = re.compile("^(/wiki/)((?!:).)*$")):

insertLink(pageId, insertPageIfNotExists(link.attrs['href']))

if link.attrs['href'] not in pages:

#遇到新頁面,加入集合並搜索裡面的詞條鏈接

newPage = link.attrs['href']

pages.add(newPage)

getLinks(newPage, recursionLevel + 1)

getLinks("/wiki/Kevin_Bacon", 0)

cur.close()

conn.close()

上面的代碼就能獲取我們需要的鏈接,但是需要注意,由於維基百科裡面的鏈接很多,所以這個程序很費時間,為了節省時間,運行幾分鐘就可以中斷了,我運行了一兩分鐘,數據已經有兩千多條了,同時維基百科服務器也會拒絕程序請求。但是這些數據已經夠我們在後面進行鏈接路徑問題數據分析了。

小結

這裡我們重新複習了一下pymysql庫的用法,加深我們對之前知識的瞭解,提高問題解決能力,數據庫使我們存儲數據必不可少的工具,希望大家都能學一些基礎知識,具體內容可以看我前段時間發佈的MySQL基礎教程,後面還有高級內容哦。

希望通過上面的內容能幫助大家。如果你有什麼好的意見,建議,或者有不同的看法,我都希望你留言和我們進行交流、討論。

如果想快速聯繫我,歡迎關注微信公眾號:AiryData。

相關推薦

推薦中...