Python 学习 02 —— Python如何爬取数据


系列文章

Python 学习 01 —— Python基础
Python 库学习 —— urllib 学习
Python 库学习 —— BeautifulSoup4学习
Python 库学习 —— Re 正则表达式
Python 库学习 —— Excel存储(xlwt、xlrd)
Python 学习 02 —— Python如何爬取数据
Python 库学习 —— Flask 基础学习
Python 学习03 —— 爬虫网站项目


二、Python 爬 虫

1、任务介绍

爬虫的学习按照任务驱动的方式进行,最终实现douban电影Top250的基本信息抓取,包括电影的名称、douban评分、评价数、电影概括、电影链接等。后续会再以可视化的方式展现,比如统计图。

电影Top250网址:https://movie.douban.com/top250

在这里插入图片描述

2、简介

  • 是什么

    网络爬虫是一种按照特定规则自动抓取互联网信息的程序或者脚本。由于互联网数据的多样性和资源的有限性,如今根据用户需求定向抓取相关网页并分析已经成为了主流的爬取策略。

  • 能做什么

    我们可以爬取自己想看的视频、各种图片,只要是能够通过浏览器访问的数据都可以用它进行爬取。这里并不是说能爬取视频网站上的VIP才能看的视频,而是本身我们就能通过浏览器看,除非开VIP,否则还是没法访问到那些特定视频。

  • 本质

    模拟浏览器打开网页,获取网页中我们想要的特定数据。

    原理:因为每个网页其实就是一个HTML,里面有各种超链接,我们可以顺着超链接进而访问下一个网页。

3、基本流程

  • 准备工作

    通过浏览器查看分析目标网页,学习编程基础规范。

  • 获取数据

    通过HTTP库向目标站点发起请求,请求包含额外的header等信息,若服务器正常响应就会得到一个Response,这便是所要获取的页面内容。

  • 解析内容

    得到的内容可能是HTML、JSON等格式,这时就要用到页面解析库、正则表达式等进行解析。

  • 保存数据

    保存形式很多,可以保存为文本、数据库或是特定格式的文件(Excel)

3.1、准备工作

这里我们先进入doubanTop250分析下每次翻页后URL的格式。

第一页:https://movie.douban.com/top250?start=0&filter=

第二页:https://movie.douban.com/top250?start=25&filter=

第三页:https://movie.douban.com/top250?start=50&filter=

注意:初始访问第一页是没有?top250?start=0&filter=。最后的&filter=省略也能正常访问。

在这里插入图片描述

3.1.1、分析页面

借助Charome开发者工具(按F12进入,其他浏览器也类似)来分析网页,在Elments下找到需要的数据位置。

当我们点击了某个链接后,浏览器就会向服务器发出请求

3.1.2、编码规范
  • 通常Python程序第一行需要加入

    # -*- coding:utf-8 或者 # coding=utf-8
    

    这样可以在代码中包含中文,使其不乱码。

  • Python中使用#来添加注释,说明代码(段)的作用。

  • Python文件中加入main函数用于测试程序if __name__ == "__main__":,下面简单举例说明:

    """
     程序输出:
        hello 2
        hello 1
     __main__的意义:
        程序会依次调用 test(2) 和 test(1),因为python是解释型语言,会按顺序执行。
        为了使函数调用整齐有序,我们在__main__之前定义函数,在__main__中去调用。
        约定俗成我们都从main开始执行。
    """
    
    def main(a):
        print("hello", a)
    
    test(2)
    
    if __name__ == "__main__":
        main(1)
    
3.1.3、导入模块

这里要导入的第三方模块有:bs4、re、urllib、xlwt

Python导入第三方模块有两种方式,在命令行终端使用pip或者在PyCharm导入。

  • pip命令:在PyCharm底部选择Terminal,输入pip 第三方模块名来安装第三方模块。

  • PyCharm导入(常用):

    • 进入设置页面(Windows:Ctrl+Alt+S,Mac:command+,)

  • 输入要导入的模块进行安装(点击了左下角的install Package后就会自动安装了,安装完成或失败都有提示)

  • 添加xwltbs4(这里reurllibsqlite3是Python自带的,无需进行安装,直接导入)

    import re  # 正则表达式,用于文字匹配
    from bs4 import BeautifulSoup   # 用于网页解析,对HTML进行拆分,方便获取数据
    import urllib.request, urllib.error # 用于指定URL,给网址就能进行爬取
    import xlwt # 用于Excel操作
    import sqlite3  # 用于进行SQLite数据库操作
    
3.1.4、程序流程

这里先是大致思路,后面逐一对每个步骤进行实现。

# -*- coding = utf-8 -*-
# @Time : 2021/7/3 6:33 下午
# @Author : 张城阳
# @File : main.py
# @Software : PyCharm

import re  # 正则表达式,用于文字匹配
from bs4 import BeautifulSoup  # 用于网页解析,对HTML进行拆分,方便获取数据
import urllib.request, urllib.error  # 用于指定URL,给网址就能进行爬取
import xlwt  # 用于Excel操作
import sqlite3  # 用于进行SQLite数据库操作


def main():
    # 豆瓣Top250网址(末尾的参数 ?start= 加不加都可以访问到第一页)
    baseUrl = "https://movie.douban.com/top250?start="
    # 1. 爬取网页并解析数据
    dataList = getData(baseUrl)
    # 2. 保存数据(以Excel形式保存)
    savePath = ".\\豆瓣电影Top250.xls"
    saveData(savePath)


# 爬取网页,返回数据列表
def getData(baseurl):
  	dataList = []
    # 爬取网页并获取需要的数据
    pass
    # 对数据逐一解析
    pass
    # 返回解析好的数据
    return dataList


# 保存数据
def saveData(savePath):
    pass


# 程序入口
if __name__ == "__main__":
    # 调用函数
    main()

3.2、获取数据

Python一般使用urllib库获取页面(Python2是urllib2,Python3将urllib和urllib2整合了),关于urllib可以我看另一篇博客Python 第三方库 —— urllib 学习

  • 定义一个用于获取网页的函数askURL,给函数传入url就会返回该网址对于的网页内容。
  • 对于每一个页面都调用askURL去获取页面内容
  • 在访问页面时可能出现错误,为了保证程序正常运行,需要进行异常捕获try……except……
# 得到一个指定URL的网页内容
def askURL(url):
    # 模拟头部信息,像douban服务器发送消息
    # User-Agent 表明这是一个浏览器(这个来自谷歌浏览器F12里 Network中 Request headers的User-Agent)
    # 每个人的用户代理可能不相同,用自己的就好。不要复制错了,否则会报418状态码。
    head = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"
    }
    # 封装头部信息
    request = urllib.request.Request(url, headers=head)
    html = ""
    try:
        # 发起请求并获取响应
        response = urllib.request.urlopen(request)
        # 读取整个HTML源码,并解码为UTF-8
        html = response.read().decode("utf-8")
    except urllib.error.URLError as e:
        # 异常捕获
        if hasattr(e, "code"):
            print("状态码:", e.code)
        if hasattr(e, "reason"):
            print("原因:", e.reason)
    return html


# 爬取网页,返回数据列表
def getData(baseurl):
    dataList = []
    # 爬取所有网页并获取需要的HTML源码
    for i in range(0, 10):      # doubanTop250 共有10页,每页25条。 range(0,10)的范围是[0,10)。
        url = baseurl + str(i*25)  # 最终 url = https://movie.douban.com/top250?start=225
        html = askURL(url)      # 将每个页面HTML源码获取出来   
        # 对页面源码逐一解析
        pass
    # 返回解析好的数据
    return dataList

3.3、解析数据

现在开始解析获取到的HTML源码。根据观察发现,每一部电影信息都由<div class="item">包裹,其中包括电影名称、详情链接、图片链接等,这就需要用到正则表达式re库。关于re库,可以看我另一篇博客Python 库学习 —— Re 正则表达式

下面是电影肖生克的救赎部分的HTML:

<div class="item">
    <div class="pic">
        <em class="">1</em>
        <a href="https://movie.douban.com/subject/1292052/">
            <img width="100" alt="肖申克的救赎"
                 src="https://img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
        </a>
    </div>
    <div class="info">
        <div class="hd">
            <a href="https://movie.douban.com/subject/1292052/" class="">
                <span class="title">肖申克的救赎</span>
                <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                <span class="other">&nbsp;/&nbsp;月黑高飞()  /  刺激1995()</span>
            </a>


            <span class="playable">[可播放]</span>
        </div>
        <div class="bd">
            <p class="">
                导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
                1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
            </p>

            <div class="star">
                <span class="rating5-t"></span>
                <span class="rating_num" property="v:average">9.7</span>
                <span property="v:best" content="10.0"></span>
                <span>2385802人评价</span>
            </div>
            <p class="quote">
                <span class="inq">希望让人自由。</span>
            </p>
        </div>
    </div>
</div>

下面是解析数据部分代码:(为了方便观察,这里只对第一页进行了解析,把range(0, 1)改为range(0, 10)就是10页了。

# 正则表达式:.表示任意字符,*表示0次或任意次,?表示0次或1次。(.*?)惰性匹配。
findLink = re.compile(r'<a href="(.*?)">')  # 获取电影详情链接。
findImg = re.compile(r'<img.*src="(.*?)"', re.S)  # 获取影片图片。re.S 让换行符包含在字符串中
findTitle = re.compile(r'<span class="title">(.*)</span>')  # 获取影片名称(可能有两个)
findOther = re.compile(r'<span class="other">(.*)</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)  # 获取影片相关内容

# 爬取网页,返回数据列表
def getData(baseurl):
    dataList = []
    # 爬取所有网页并获取需要的HTML源码
    for i in range(0, 1):  # 豆瓣Top250 共有10页,每页25条。 range(0,10)的范围是[0,10)。
        url = baseurl + str(i * 25)  # 最终 url = https://movie.douban.com/top250?start=225
        html = askURL(url)  # 将每个页面HTML源码获取出来
        # 对页面源码逐一解析
        soup = BeautifulSoup(html, "html.parser")  # 设置解析器
        for item in soup.find_all("div", class_="item"):  # 查找 class为item的div标签
            data = []  # 保存一部电影数据(每部电影由<div class="item">划分)
            item = str(item)  # 把item转为字符串类型(原本是Tag类型对象)

            # findall返回匹配成功的列表。
            link = re.findall(findLink, item)[0]  # 获取影片详情页链接,只需要一个就行。这里会返回两个。
            data.append(link)  # 把link追加到data里

            img = re.findall(findImg, item)[0]  # 获取影片图片链接
            data.append(img)

            titles = re.findall(findTitle, item)  # 获取影片名称
            # 有的影片title是两个,有的是一个。如果只有一个,则第二个保存空。
            if (len(titles) == 2):
                data.append(titles[0])
                titles[1] = re.sub("(/)|( )", "", titles[1])
                data.append("".join(titles[1].split()))
            else:
                data.append(titles[0])
                data.append("")

            other = re.findall(findOther, item)[0]  # 获取影片别称
            other = re.sub("(/)|( )", "", other)
            data.append("".join(other.split()))

            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('\\xa0', "  ", bd)  # 去除 HTML 空格符 &nbsp;
            bd = re.sub('(/\.\.\.)|(<br/>)|<br>', " ", bd)
            bd = re.sub("(    )|(\n)", "", bd)
            data.append(bd.strip())  # strip 去掉前后空格

            dataList.append(data)
    # 返回解析好的数据
    print(dataList)
    return dataList

3.4、保存数据

3.4.1、Excel表存储

利用Python库xlwt将获取到的数据dataList写入到Excel表(读取是xlrd模块)。可以看我另一篇博客Python 库学习 —— Excel存储(xlwt、xlrd)

下面是将爬取到的电影保存至Excel中的代码:

# -*- coding = utf-8 -*-
# @Time : 2021/7/3 6:33 下午
# @Author : 张城阳
# @File : main.py
# @Software : PyCharm

import re  # 正则表达式,用于文字匹配
from bs4 import BeautifulSoup  # 用于网页解析,对HTML进行拆分,方便获取数据
import urllib.request, urllib.error, urllib.parse  # 用于指定URL,给网址就能进行爬取
import xlwt  # 用于Excel操作
import sqlite3  # 用于进行SQLite数据库操作
import ssl

# 正则表达式:.表示任意字符,*表示0次或任意次,?表示0次或1次。(.*?)惰性匹配。
findLink = re.compile(r'<a href="(.*?)">')  # 获取电影详情链接。
findImg = re.compile(r'<img.*src="(.*?)"', re.S)  # 获取影片图片。re.S 让换行符包含在字符串中
findTitle = re.compile(r'<span class="title">(.*)</span>')  # 获取影片名称(可能有两个)
findOther = re.compile(r'<span class="other">(.*)</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)  # 获取影片相关内容


def main():
    # 处理SSL
    ssl._create_default_https_context = ssl._create_unverified_context

    # 豆瓣Top250网址(末尾的参数 ?start= 加不加都可以访问到第一页)
    baseUrl = "https://movie.douban.com/top250?start="
    # 1. 爬取网页并解析数据
    dataList = getData(baseUrl)
    # 2. 保存数据(以Excel形式保存)
    savePath = "豆瓣电影Top250.xlsx"
    saveData(dataList, savePath)


# 得到一个指定URL的网页内容
def askURL(url):
    # 模拟头部信息,像豆瓣服务器发送消息
    # User-Agent 表明这是一个浏览器(这个来自F12里Network中 Request headers的User-Agent)
    head = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"
    }
    # 封装头部信息
    request = urllib.request.Request(url, headers=head)
    html = ""
    try:
        # 发起请求并获取响应
        response = urllib.request.urlopen(request)
        # 读取整个HTML源码,并解码为UTF-8
        html = response.read().decode("utf-8")
    except urllib.error.URLError as e:
        # 异常捕获
        if hasattr(e, "code"):
            print("状态码:", e.code)
        if hasattr(e, "reason"):
            print("原因:", e.reason)
    return html


# 爬取网页,返回数据列表
def getData(baseurl):
    dataList = []
    # 爬取所有网页并获取需要的HTML源码
    for i in range(0, 10):  # 豆瓣Top250 共有10页,每页25条。 range(0,10)的范围是[0,10)。
        url = baseurl + str(i * 25)  # 最终 url = https://movie.douban.com/top250?start=225
        html = askURL(url)  # 将每个页面HTML源码获取出来
        # 对页面源码逐一解析
        soup = BeautifulSoup(html, "html.parser")  # 设置解析器
        for item in soup.find_all("div", class_="item"):  # 查找 class为item的div标签
            data = []  # 保存一部电影数据(每部电影由<div class="item">划分)
            item = str(item)  # 把item转为字符串类型(原本是Tag类型对象)

            # findall返回匹配成功的列表。
            link = re.findall(findLink, item)[0]  # 获取影片详情页链接,只需要一个就行。这里会返回两个。
            data.append(link)  # 把link追加到data里

            img = re.findall(findImg, item)[0]  # 获取影片图片链接
            data.append(img)

            titles = re.findall(findTitle, item)  # 获取影片名称
            # 有的影片title是两个,有的是一个。如果只有一个,则第二个保存空。
            if (len(titles) == 2):
                data.append(titles[0])  # 中文名称
                titles[1] = re.sub("(/)|( )", "", titles[1])
                data.append("".join(titles[1].split()))  # 英文名称
            else:
                data.append(titles[0])  # 中文名称
                data.append("")  # 没有英文名称,添加空

            other = re.findall(findOther, item)[0]  # 获取影片别称
            other = other.replace("/", "", 1)
            other = re.sub("(&nbsp;)|(NBSP)|(\\xa0)|( )", "", other) # 去除空格
            data.append(other)

            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('\\xa0', "  ", bd)  # 去除 HTML 空格符 &nbsp;
            bd = re.sub('(/\.\.\.)|(<br/>)|<br>', " ", bd)
            bd = re.sub("(    )|(\n)", "", bd)
            data.append(bd.strip())  # strip 去掉前后空格

            dataList.append(data)
    # 返回解析好的数据
    return dataList


# 保存数据
def saveData(dataList, savePath):
    print("正在保存...")

    book = xlwt.Workbook(encoding="utf-8")
    sheet = book.add_sheet("豆瓣电影Top250", cell_overwrite_ok=True)  # 第二个参数表示 可以对单元格进行覆盖

    # 写入列名(第一行存储列名)
    col = ("影片详情链接", "图片链接", "影片中文名", "影片外国名", "影片别称", "评分", "评论人数", "影片概括", "影片相关信息")
    for i in range(0, len(col)):
        sheet.write(0, i, col[i])

    # 写入电影信息(从第二行开始)
    for i in range(0, 250):
        print("正在保存->第%d部电影" % (i + 1))
        data = dataList[i]  # 取出某部电影数据
        for j in range(0, len(col)):
            sheet.write(i + 1, j, data[j])

    book.save(savePath)  # 保存Excel

    print("保存完成!!")


# 程序入口
if __name__ == "__main__":
    # 调用函数
    main()

运行效果:

3.4.1、SQLite数据库保存

使用这种方式至少得对数据库要有所了解,要明白SQL语句的基本使用。

SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。简单来说,SQLite 是把存储内容作为一个文件保存在本地的,它和MySQL不一样,MySQL是保存数据到服务器里。(Android中也常常用到SQLite)

下面用Python简单描述下如何使用SQLite:

import sqlite3
# 一. 使用流程
# 1.打开或创建数据库文件
connect = sqlite3.connect("test.db")
# 2.获取游标
c = connect.cursor()
# 3.执行SQL语句
sql = "...."
c.execute(sql)
# 4.提交(插入、删除、更新、创建表需要提交,查询不需要提交)
connect.commit()
# 5.关闭
connect.close()

# 插入、删除、更新比较简单,执行SQL语句就行。
# 查询语句 会返回一个结果集,用列表进行查看就行。下面演示下查询。

# 创建 user 表
connect = sqlite3.connect("test.db")
c = connect.cursor()
sql1 = "create table `user`(id int primary key not null, name varchar(10) not null)"
c.execute(sql1)
connect.commit()

# 插入两条数据并立马查询
connect = sqlite3.connect("test.db")
c = connect.cursor()
sql2 = "insert into user(id, name) values(1, '小白'), (2, '小红');"
c.execute(sql2)
connect.commit()

sql3 = "select * from user"
cursor = c.execute(sql3)
for row in cursor:
    print("id = ", row[0], "name = ", row[1])
connect.commit()

connect.close()

下面是完整的SQLite代码:

# -*- coding = utf-8 -*-
# @Time : 2021/7/3 6:33 下午
# @Author : 张城阳
# @File : main.py
# @Software : PyCharm

import re  # 正则表达式,用于文字匹配
from bs4 import BeautifulSoup  # 用于网页解析,对HTML进行拆分,方便获取数据
import urllib.request, urllib.error, urllib.parse  # 用于指定URL,给网址就能进行爬取
import xlwt  # 用于Excel操作
import sqlite3  # 用于进行SQLite数据库操作
import ssl

# 正则表达式:.表示任意字符,*表示0次或任意次,?表示0次或1次。(.*?)惰性匹配。
findLink = re.compile(r'<a href="(.*?)">')  # 获取电影详情链接。
findImg = re.compile(r'<img.*src="(.*?)"', re.S)  # 获取影片图片。re.S 让换行符包含在字符串中
findTitle = re.compile(r'<span class="title">(.*)</span>')  # 获取影片名称(可能有两个)
findOther = re.compile(r'<span class="other">(.*)</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)  # 获取影片相关内容


def main():
    # 处理SSL
    ssl._create_default_https_context = ssl._create_unverified_context

    # 豆瓣Top250网址(末尾的参数 ?start= 加不加都可以访问到第一页)
    baseUrl = "https://movie.douban.com/top250?start="
    # 1. 爬取网页并解析数据
    dataList = getData(baseUrl)
    # 2. 保存数据
    dbPath = "movie.db"
    saveDataToDB(dataList, dbPath)  # SQLite


# 得到一个指定URL的网页内容
def askURL(url):
    # 模拟头部信息,像豆瓣服务器发送消息
    # User-Agent 表明这是一个浏览器(这个来自F12里Network中 Request headers的User-Agent)
    head = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"
    }
    # 封装头部信息
    request = urllib.request.Request(url, headers=head)
    html = ""
    try:
        # 发起请求并获取响应
        response = urllib.request.urlopen(request)
        # 读取整个HTML源码,并解码为UTF-8
        html = response.read().decode("utf-8")
    except urllib.error.URLError as e:
        # 异常捕获
        if hasattr(e, "code"):
            print("状态码:", e.code)
        if hasattr(e, "reason"):
            print("原因:", e.reason)
    return html


# 爬取网页,返回数据列表
def getData(baseurl):
    dataList = []
    # 爬取所有网页并获取需要的HTML源码
    for i in range(0, 10):  # 豆瓣Top250 共有10页,每页25条。 range(0,10)的范围是[0,10)。
        url = baseurl + str(i * 25)  # 最终 url = https://movie.douban.com/top250?start=225
        html = askURL(url)  # 将每个页面HTML源码获取出来
        # 对页面源码逐一解析
        soup = BeautifulSoup(html, "html.parser")  # 设置解析器
        for item in soup.find_all("div", class_="item"):  # 查找 class为item的div标签
            data = []  # 保存一部电影数据(每部电影由<div class="item">划分)
            item = str(item)  # 把item转为字符串类型(原本是Tag类型对象)

            # findall返回匹配成功的列表。
            link = re.findall(findLink, item)[0]  # 获取影片详情页链接,只需要一个就行。这里会返回两个。
            data.append(link)  # 把link追加到data里

            img = re.findall(findImg, item)[0]  # 获取影片图片链接
            data.append(img)

            titles = re.findall(findTitle, item)  # 获取影片名称
            # 有的影片title是两个,有的是一个。如果只有一个,则第二个保存空。
            if (len(titles) == 2):
                data.append(titles[0])  # 中文名称
                titles[1] = re.sub("(/)|( )", " ", titles[1])
                data.append("".join(titles[1].split()))  # 英文名称
            else:
                data.append(titles[0])  # 中文名称
                data.append("")  # 没有英文名称,添加空

            other = re.findall(findOther, item)[0]  # 获取影片别称
            other = other.replace("/", "", 1)
            other = re.sub("(&nbsp;)|(NBSP)|(\\xa0)|( )", "", other)
            data.append(other)

            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('\\xa0', "  ", bd)  # 去除 HTML 空格符 &nbsp;
            bd = re.sub('(/\.\.\.)|(<br/>)|<br>', " ", bd)
            bd = re.sub("(    )|(\n)", "", bd)
            data.append(bd.strip())  # strip 去掉前后空格

            dataList.append(data)
    # 返回解析好的数据
    return dataList

# 初始化数据库
def iniDB(dbPath):
    print("正在初始化...")
    # 创建表
    sql = '''
        create table if not exists movie250(
            id integer primary key autoincrement,
            info_link text,
            pic_link text,
            c_name varchar,
            e_name varchar,
            other_name varchar,
            score numeric,
            rated numeric,
            introduction text,
            info text
        );
    '''
    connect = sqlite3.connect(dbPath)
    cursor = connect.cursor()
    cursor.execute(sql)
    connect.commit()
    cursor.close()
    connect.close()
    print("初始化完成!!")


# 保存数据(SQLite)
def saveDataToDB(dataList, dbPath):
    iniDB(dbPath)  # 初始化数据库
    connect = sqlite3.connect(dbPath)
    cursor = connect.cursor()

    print("正在入库...")
    # dataList存储了250部电影的信息,data一部电影的信息列表,它包含了9个元素。
    for data in dataList:
        # 这个for循环是为了将列表字符串元素都加上双引号,因为后面拼接sql时 每个元素需要双引号括起来。
        for index in range(len(data)):
            # 下标6和7的元素是score和rated,是数字类型,不需要引号。
            if index == 5 or index == 6:
                continue
            data[index] = '"' + data[index] + '"'
        # 下面是用 %s 作为占位符,填充的是 ",".join(data)。
        # ",".join(data)表明 把列表data转为字符串且每个元素用逗号隔开。
        sql = '''
            insert into movie250(
            info_link, pic_link, c_name, e_name, other_name, score, rated, introduction, info)
            values(%s)''' % ",".join(data)
        cursor.execute(sql)
        connect.commit()
    cursor.close()
    connect.close()
    print("入库完毕!!")


# 程序入口
if __name__ == "__main__":
    main()

运行结果这里在PyCharm中查看:

运行结果

  • 30
    点赞
  • 282
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老板来碗小面加蛋~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值