
作者 Airy
本文转自 AiryData,转载需授权
前 言
上一篇我们学习了数据采集中一个页面跳转到另一个页面的简单爬虫,虽然获取了这些链接数据,但是由于链接数目太多,不好查看,所以我们要想办法存储起来。
这里使用 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 基础教程,后面还有高级内容哦。
希望通过上面的内容能帮助大家。如果你有什么好的意见,建议,或者有不同的看法,我都希望你留言和我们进行交流、讨论。

推荐阅读
大数据舆情情感分析,如何提取情感并使用什么样的工具?(贴情感标签)
【干货】找不到适合自己的编程书?我自己动手写了一个热门编程书搜索网站(附PDF书单)



