四、保存数据(SQLite数据库)

1. 调用库函数

库函数的下载请见 爬虫入门记(1)

from builtins import len, hasattr, range  # 提供对Python的“内置”标识符的直接访问
from bs4 import BeautifulSoup  # 解析网页数据
import re  # 正则表达式
import urllib.request, urllib.error  # 提供了一系列用于操作URL的功能
import sqlite3  # 与SQLite相关的库函数

2. 定义主函数

def main():
	baseurl = "https://movie.douban.com/top250?start="  # 以豆瓣电影Top250为例
    datalist = getData(baseurl)  # getData 函数用来爬取数据,并且返回一个列表,下面会介绍
    # 保存到SQlite数据库
    dbpath = "movie.db"  # db文件一般是软件用于存放数据的一个文件,相当于数据库
    saveData2DB(datalist, dbpath)
    
if __name__ == "__main__":
    # 调用函数
    main()
    print("爬取完毕")

3. getData 函数

用来爬取网页,并且返回一个存放数据的列表。
【下面是re匹配规则,用到了正则表达式,位置在主函数main之后。】

findLink = re.compile(r'<a href="(.*?)">')  # 创建正则表达式对象的规则和模式
findImgSrc = re.compile(r'<img.*src="(.*?)"', re.S)  # re.S让换行符包含在其中
findTiTle = re.compile(r'<span class="title">(.*)</span>')
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
findJudge = re.compile(r'<span>(\d*)人评价</span>')
findInq = re.compile(r'<span class="inq">(.*)</span>')
findBD = re.compile(r'<p class="">(.*?)</p>', re.S)

getData 代码:

def getData(baseurl):
    datalist = []
    for i in range(0, 10):  # 调用获取页面信息的函数,一共爬取10页的信息
        url = baseurl + str(i * 25)  # 观察网页每一页的网址变化
        html = askURL(url)  # 保存获取到的当前页网页源码
        # 逐一解析数据
        soup = BeautifulSoup(html, "html.parser")  #  调用BeautifulSoup库函数解析数据
        for item in soup.find_all('div', class_="item"):  # 查找符合要求的字符串,形成列表
            # print(item)测试:查看电影全部信息
            data = []  # 保存一部电影的全部信息,以列表形式存储
            item = str(item)  # 转化为字符串

            link = re.findall(findLink, item)[0]  # 调用re库函数,给一个findlink规则,根据该规则找到相应内容
            data.append(link)  # 向data列表添加该电影信息

            imgSrc = re.findall(findImgSrc, item)[0]
            data.append(imgSrc)

            titles = re.findall(findTiTle, item)
            # 一个电影可能有很多名字
            if len(titles) == 2:
                ctitle = titles[0]  # 中文名字
                data.append(ctitle)
                otitle = titles[1]  # 外国名字
                otitle = re.sub('/', "", otitle)  #名字中可能有/符号,将/符号替换为没有
                data.append(otitle)
            else:
                data.append(titles[0])
                data.append(" ")  # (外国名)留空

            rating = re.findall(findRating, item)[0]
            data.append(rating)

            judgeNum = re.findall(findJudge, item)[0]
            data.append(judgeNum)

            inq = re.findall(findInq, item)
            if len(inq) != 0:
                inq = inq[0].replace("。", "")  # 去掉句号
                data.append(inq)
            else:
                data.append(" ")  # 留空

            bd = re.findall(findBD, item)[0]
            bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd)  # 去掉br
            bd = re.sub('/', "", bd)
            data.append(bd.strip())  # strip去掉空格
            datalist.append(data)  # 把处理好的data放入datalist总列表

    return datalist

4. 新建数据库

def init_db(dbpath):
    sql = '''
        create table movie250
        (
        id integer primary key autoincrement,
        info_link text,
        pic_link text,
        cname varchar ,
        oname varchar ,
        score numeric ,
        rate numeric ,
        instroduction text,
        info text
        )
    '''  # 数据库的sql语言
    conn = sqlite3.connect(dbpath)  # 链接数据库
    cursor = conn.cursor()  # 对数据的操作需要通过cursor来实现,即游标
    cursor.execute(sql)  # 执行sql语句
    conn.commit()  # 提交事务,不然不能做到真正插入数据
    conn.close()  # 用于关闭连接,以防止下面紧接着有另外的 查询会产生冲突。

5. saveData2DB 函数

# 保存数据-SQlite
def saveData2DB(datalist, dbpath):
    init_db(dbpath)  # 新建数据库
    conn = sqlite3.connect(dbpath)  # 链接数据库
    cur = conn.cursor()  # 对数据的操作需要通过cursor来实现,即游标

    for data in datalist:
        for index in range(len(data)):
            if index == 4 or index == 5:
                continue
            data[index] = '"' + data[index] + '"'   # 将数据转化成字符串
        sql = '''
                insert into movie250(
                info_link, pic_link, cname, oname, score, rate, instroduction, info)
                values (%s)''' % ",".join(data)  # 把data这个链表每一个中间用,链接起来,填补前面%s的位置
        cur.execute(sql)
        conn.commit()
    cur.close()
    conn.close()