Advertisement

python爬取数据并存到excel,python爬取数据的意义

阅读量:

您好!今天向大家介绍一下Python数据爬取有哪些库和框架,可能很多人都不了解这一点.接下来我会详细讲解这些工具的具体使用方法和应用场景.我们现在就来学习一下吧!

文章目录

第二篇系列文章

系列文章

Python 01的基础知识:深入探索urllib库的学习
Excel存储技术:掌握xlwt与xlrd的数据管理方法
数据抓取技术:利用Flask进行动态网页开发
Flask基础知识研究:构建高效Web应用
爬虫网站项目实践

二、Python 爬 虫

1、任务介绍

采用任务驱动的方式进行爬虫的学习,并最终完成对douban电影Top250的基本信息抓取。这些信息将包含以下内容:电影名称、douban评分等基础数据以及相关的链接信息。随后将通过可视化形式展示相关数据

电影Top250网址:

2、简介

是什么

网络爬虫是一种遵循特定规则设计出来的软件程序或脚本。因为互联网数据具有多样性且资源有限,在当今社会中为了满足用户特定需求而有目的地进行信息收集与分析已成为主要采用的方式。

能做什么

我们可以获取自己感兴趣的视频与图片,并非仅限于那些可通过浏览器访问的数据也可被获取。实际上,并非只有通过购买VIP才能观看这些内容,则可被直接获取并欣赏它们的价值所在。然而这并不意味着我们只能观看那些需要付费的内容而无法欣赏其他内容而实际上我们无需付费即可直接观看并欣赏所有能够通过浏览器访问的内容

本质

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

原理:每个网站都是一个HTML文件,在里面有很多链接。我们可以通过这些链接访问下一个网站。

3、基本流程

准备工作

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

获取数据

利用HTTP库发送一个包含必要的Header字段的信息到目标站点。如果服务器正常返回,则会收到一个Response码数字,这将是我们最终获取的内容。

解析内容

获取到的内容可能为HTML格式

保存数据

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

3.1、准备工作

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

第一页:;filter=

第二页:;filter=

第三页:;filter=

3.1.1、分析页面

通过Charom...工具(按下F12键即可启动该功能,在大多数浏览器中也具有相似的操作流程)执行对网页的分析工作,在Elements选项卡中定位所需数据位置。

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

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 install 第三方模块名'以成功安装所需软件包。

PyCharm导入(常用):

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

操作需要将软件包进行安装。如果您点击左下方的install Package按钮后会立即开始执行该操作。

安装xwlt和bs4(其中re、urllib、sqlite3是预装的库,请直接导入)

复制代码
 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 : 
    
 # @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 = ""
    
     # 1. 爬取网页并解析数据
    
     dataList = getData(baseUrl)
    
     # 2. 保存数据(以Excel形式保存)
    
     savePath = ".\ 豆瓣电影"
    
     saveData(savePath)
    
  
    
  
    
 # 爬取网页,返回数据列表
    
 def getData(baseurl):
    
   	dataList = []
    
     # 爬取网页并获取需要的数据
    
     pass
    
     # 对数据逐一解析
    
     pass
    
     # 返回解析好的数据
    
     return dataList
    
  
    
  
    
 # 保存数据
    
 def saveData(savePath):
    
     pass
    
  
    
  
    
 # 程序入口
    
 if __name__ == "__main__":
    
     # 调用函数
    
     main()
3.2、获取数据

通常情况下,在Python中使用urllib库来获取网页内容。值得注意的是,在Pyth0n 2版本中,默认使用的是urllib2模块;而到了Pyth0n 3版本,则将原先的urllib和urillin整合为一个模块。对于学习urllib这一第三方库的知识,我建议参考另一篇详细的博客文章:《Python 第三方库 —— urllib 学习》。

请定义一个名为askURL$的功能模块,在接收一个 URL 参数时,则会返回对应网站的内容。
每当执行单个页面的数据抓取操作时,则会调用该功能模块来获取其内容的过程中可能会出现错误。
为了避免程序因错误而崩溃,在处理过程中必须实施错误捕获机制。

复制代码
 # 得到一个指定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 = ().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 = 
    
     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="">
    
         <img width="100" alt="肖申克的救赎"
    
              src="" class="">
    
     </a>
    
     </div>
    
     <div class="info">
    
     <div class="hd">
    
         <a href="" 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>

在本节中我们主要对解析数据部分代码进行了分析与处理

复制代码
 # 正则表达式:.表示任意字符,*表示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 = 
    
     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] = ("(/)|( )", "", titles[1])
    
             data.append("".join(titles[1].split()))
    
         else:
    
             data.append(titles[0])
    
             data.append("")
    
  
    
         other = re.findall(findOther, item)[0]  # 获取影片别称
    
         other = ("(/)|( )", "", 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 = ('\ xa0', "  ", bd)  # 去除 HTML 空格符 &nbsp;
    
         bd = ('(/\.\.\.)|(<br/>)|<br>', " ", bd)
    
         bd = ("(    )|(\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 : 
    
 # @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 = ""
    
     # 1. 爬取网页并解析数据
    
     dataList = getData(baseUrl)
    
     # 2. 保存数据(以Excel形式保存)
    
     savePath = "豆瓣电影"
    
     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 = ().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 = 
    
     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] = ("(/)|( )", "", 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 = ("(&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 = ('\ xa0', "  ", bd)  # 去除 HTML 空格符 &nbsp;
    
         bd = ('(/\.\.\.)|(<br/>)|<br>', " ", bd)
    
         bd = ("(    )|(\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])
    
  
    
     (savePath)  # 保存Excel
    
  
    
     print("保存完成!!")
    
  
    
  
    
 # 程序入口
    
 if __name__ == "__main__":
    
     # 调用函数
    
     main()

运行效果:

3.4.1、SQLite数据库保存

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

SQLite 是一个运行时内置于进程中的数据库核心组件。该组件通过实现一系列关键功能特性:支持自我管理运行(无需外部服务器支持)、无需配置即可使用(zero configuration)、具备完整的事务处理能力(transactional)。从简单易用的角度来看,在这种设计下 SQLite 将所有数据存储在一个本地文件中,并提供了一系列简便的操作方法来管理这些数据。这种设计使得它特别适合移动设备应用,在 Android 设备中广泛使用

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

复制代码
 import sqlite3

    
 # 一. 使用流程
    
 # 1.打开或创建数据库文件
    
 connect = sqlite3.connect("")
    
 # 2.获取游标
    
 c = connect.cursor()
    
 # 3.执行SQL语句
    
 sql = "...."
    
 c.execute(sql)
    
 # 4.提交(插入、删除、更新、创建表需要提交,查询不需要提交)
    
 connect.commit()
    
 # 5.关闭
    
 connect.close()
    
  
    
 # 插入、删除、更新比较简单,执行SQL语句就行。
    
 # 查询语句 会返回一个结果集,用列表进行查看就行。下面演示下查询。
    
  
    
 # 创建 user 表
    
 connect = sqlite3.connect("")
    
 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("")
    
 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 : 
    
 # @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 = ""
    
     # 1. 爬取网页并解析数据
    
     dataList = getData(baseUrl)
    
     # 2. 保存数据
    
     dbPath = ""
    
     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 = ().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 = 
    
     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] = ("(/)|( )", " ", 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 = ("(&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 = ('\ xa0', "  ", bd)  # 去除 HTML 空格符 &nbsp;
    
         bd = ('(/\.\.\.)|(<br/>)|<br>', " ", bd)
    
         bd = ("(    )|(\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中查看:

全部评论 (0)

还没有任何评论哟~