准备工作

该笔记围绕豆瓣TOP250页面进行学习,爬取豆瓣TOP250影片信息。网址为 https://movie.douban.com/top250?start=25 其中 ?start=25 表示显示第25个以后的25个影片信息,如果不加该参数,则从第一个开始显示。

我们需要安装相应的第三方模块,如下

from bs4 import BeautifulSoup   #网页解析获取数据
import re   #正则表达式进行文字匹配
import urllib.request , urllib.error , requests   #网页请求
import xlwt #进行Excel操作
import sqlite3  #进行sqlite数据库操作

项目流程

# 主函数
def main():
    baseurl = "https://movie.douban.com/top250?start="
    # 1.爬取网页
    GetData(baseurl)
    # 3.保存数据
    savepath = "./top250.xls"
    SaveData(savepath)

def GetData(baseurl):
    datalist=[]
    # 2.边爬取边解析数据
    return datalist

def SaveData(savepath):
    pass

if __name__ == "__main__":
    main()

urllib库介绍

基本的请求 是python内置的一个http请求库,不需要额外的安装。只需要关注请求的链接,参数,提供了强大的 解析。
urllb.request 请求模块
urllib.error 异常处理模块
urllib.parse 解析模块

参考: https://www.cnblogs.com/qikeyishu/p/10748497.html

# get请求
import urllib.request , urllib.error
response=urllib.request.urlopen("http://www.baidu.com")
print(response.read().decode("utf-8"))  #对读到的响应转码成utf-8
print(response.status)  # 获取状态码
print(response.getheaders())    #获取所有响应头信息
print(response.getheader("Bdqid"))    #获取某个响应头信息

# post请求
import urllib.request , urllib.error
import urllib.parse
data = bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")    #生成测试数据
res = urllib.request.urlopen("http://httpbin.org/post",data=data)
print(res.read().decode("utf-8"))

# 超时处理
import urllib.request , urllib.error
try:
    response=urllib.request.urlopen("http://www.baidu.com",timeout=0.01) # 设置超时时间,超过0.01s没返回就报错
    print(response.read().decode("utf-8"))
except urllib.error.URLError as result:
    print("Time Out!")


# 封装请求头访问
import urllib.request , urllib.error
import urllib.parse
url="http://httpbin.org/post"
data = bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")    #生成测试数据
headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
}
req = urllib.request.Request(url=url,data=data,headers=headers,method="POST")   #封装请求对象,由于urlopen无法传参数,声明一个Request对象 
res = urllib.request.urlopen(req)
print(res.read().decode("utf-8"))

数据解析

BeautifulSoup

BeautifulSoup使用详解参见:BeautifulSoup详解

正则表达式

正则表达式常用操作符

操作符说明实例
.表示任何单字符
[ ]字符集对单个字符给出取值范围[abc]表示a,b,c [a-z]表示a-z的字符
1非字符集,对单个字符给出排除范围2表示非a或b或c的单个字符
*前面一个字符0次或无限次扩展abc*表示ab,abc,abcc等
+前面一个字符1次或无限次扩展abc*表示abc,abcc等
?前面一个字符0次或1次扩展abc?表示ab,abc
左右表达式任意一个
{m}扩展前一个字符m次ab{2}c表示abbc
{m,n}扩展前一个字符m至n次(包含n)ab{1,2}c表示abc,abbc
^匹配字符串开头^abc表示abc且在一个字符串开头
$匹配字符串结尾abc$表示abc且在一个字符串结尾
( )分组标记(abc)表示abc
\d数字,邓嘉怡[0-9]
\w单词字符,等价于[a-zA-Z0-9_]

Re库主要功能函数

函数功能
re.search()在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match()在一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall()搜索字符串,以列表形式返回全部匹配到的子串
re.sub()在一个字符串中替换所有配正则表达式的子串,返回替换后的字符串
re.split()将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.finditer()搜索字符串,返回一个结果的迭代类型,每个迭代元素是个mat对象

控制匹配的模式

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。 多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:

修饰符描述
re.l使匹配对大小写不敏感
re.L做本地化识别匹配
re.M多行匹配影响^和$
re.S使.匹配包括换行在内的所有字符
re.U根据Unicode字符集解析字符,影响\b,\B\w,\W
re.X该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解

Re模块下的函数

compile(pattern):创建模式对象

import re 
pat=re.compile("A") 
#m=pat.search("CBA") 

m=pat.search("ABC") 
#等价于 re.search( A , CBA ) 
print(m)
#<re.Match object; span=(2, 3), match='A'>  表示匹配到了

m=pat.search("CBD") 
print(m)        #None   表示没匹配到

search(pattern,string):在字符串中寻找模式

import re 
m = re.search("asd" , "ASDasd" ) 
print(m)
# <_sre.SRE_Match object at 0xb72cd6e8>  #匹配到了,返回MatchObject(True)

m = re.search("asd"  , "ASDASD" ) 
print(m)                                 #没有匹配到,返回None(False)

match(pattern,string):在字符串开始处匹配模式

# 等价于
pat=re.compile( "a" )
print(pat.match( "Aasd" ))
#输出None

print(pat.match("aASD" ))
#输出 <_sre.SRE_Match object at 0xb72cd6e8>

# 上面的函数返回都可以在if条件语句中进行判断:
if pat.search("asd"):
    print ("OK")   #OK        #找到返回
if re.search("a","ASD" ):
    print ("OK")            #没有找到

split(pattern,string):根据模式分割字符串,返回列表

re.split( , , a,s,d,asd )
[ a , s , d , asd ]          #返回列表

pat = re.compile( , )
pat.split( a,s,d,asd )
[ a , s , d , asd ]          #返回列表

re.split( [, ]+ , a ,  s  ,d     ,,,,,asd )   #正则匹配:[, ]+,后面说明
[ a , s , d , asd ]

re.split( [, ]+ , a ,  s  ,d     ,,,,,asd ,maxsplit=2) # maxsplit 多分割次数
[ a , s , d     ,,,,,asd ]

pat = re.compile( [, ]+ )                     #正则匹配:[, ]+,后面说明
pat.split( a ,  s  ,d     ,,,,,asd ,maxsplit=2)        # maxsplit 多分割次数
[ a , s , d     ,,,,,asd ]

findall(pattern,string):列表形式返回匹配项

import re
print(re.findall( "a" , "ASDaDFGAa" ))
#[ a , a ]                  #列表形式返回匹配到的字符串

pat = re.compile( "a" )
print(pat.findall( "ASDaDFGAa" ))
#[ a , a ]         #列表形式返回匹配到的字符串

pat = re.compile( "[A-Z]+" )    #正则匹配:[A-Z]+
print(pat.findall( "ASDcDFGAa" ))
#[ ASD , DFGA ]                 #找到匹配到的字符串

pat = re.compile( [A-Z] ) pat.findall( ASDcDFGAa ) #正则匹配:[A-Z]+
#[ A , S , D , D , F , G , A ]  #找到匹配到的字符串

pat = re.compile( [A-Za-z] )   #正则匹配:[A-Za-z]+  匹配所有单词
pat.findall( ASDcDFGAa )
[ A , S , D , c , D , F , G , A , a ]

sub(pat,repl,string) :用repl替换 pat匹配项 (留的是中间的,因为中间在中心)

re.sub( a , A , abcasd )   #找到a用A替换
AbcAsd

解析部分代码

from bs4 import BeautifulSoup   #网页解析获取数据
import re   #正则表达式进行文字匹配
import urllib.request , urllib.error , requests   #网页请求
import xlwt #进行Excel操作
import sqlite3  #进行sqlite数据库操作

# 主函数
def main():
    baseurl = "https://movie.douban.com/top250?start="
    # 1.爬取网页
    GetData(baseurl)
    # 3.保存数据
    savepath = "./豆瓣TOP250.xls"
    SaveData(savepath)

#详情链接
findlink=re.compile(r'<a href="(.*?)">')    #创建正则表达式对象,表示规则
#影片图片
findsrc=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)

def GetData(baseurl):
    datalist=[]
    for i in range(0,10):
        url = baseurl + str(i*25)   # 调用获取页面信息函数10次
        html =AskURL(url)
        # 2.边爬取边解析数据
        soup = BeautifulSoup(html,"html.parser")
        for item in soup.find_all('div',class_="item"): #查找符合要求的字符串形成列表,
            data = []   #保存一部影片所有信息
            item=str(item)
          
            #影片详情页链接
            link=re.findall(findlink,item)[0]   #使用re库查找指定字符串
            data.append(link)                   #添加链接

            #影片图片
            imgsrc=re.findall(findsrc,item)[0]
            data.append(imgsrc)                 #添加图片

            #影片名字
            titles=re.findall(findtitle,item)   #片名可能只有中文名没有外文名
            if (len(titles)==2):
                data.append(titles[0])  #添加中文名
                data.append(titles[1].replace("/",""))  #添加外文名
            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)
            bd=re.sub("/","",bd)    #去掉 /
            data.append(bd.strip()) #去掉空格,并添加进data

            datalist.append(data)
  
    print(datalist)

    return datalist

#保存数据
def SaveData(savepath):
    pass

#得到一个指定url的内容
def AskURL(url):
    headers={   #模拟浏览器头部信息,向豆瓣发送请求
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
    }
    request = urllib.request.Request(url=url,headers=headers)
    try:
        response =urllib.request.urlopen(request)
        html = response.read().decode("utf-8")
        # print(html)
    except urllib.error.URLError as e:
        if hasattr(e,"code"):
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)
    return html


if __name__ == "__main__":
    main()

数据保存

保存数据到Excel

参考: https://www.cnblogs.com/caesar-id/p/11802440.html

使用xlwt保存数据到Excel的小demo:

import xlwt

workbook=xlwt.Workbook(encoding="utf-8")    #创建workbook对象
worksheet=workbook.add_sheet("sheet1")      #创建工作表取名sheet1
worksheet.write(0,0,"hello")                #在sheet1中的第一行第一列写入hello
workbook.save("student.xls")                #保存数据表取名为student.xls

保存数据到Excel代码

from bs4 import BeautifulSoup   #网页解析获取数据
import re   #正则表达式进行文字匹配
import urllib.request , urllib.error , requests   #网页请求
import xlwt #进行Excel操作
import sqlite3  #进行sqlite数据库操作

# 主函数
def main():
    baseurl = "https://movie.douban.com/top250?start="
    # 1.爬取网页
    datalist=GetData(baseurl)
    # 3.保存数据
    savepath = "./豆瓣TOP250.xls"
    SaveData(datalist,savepath)

#详情链接
findlink=re.compile(r'<a href="(.*?)">')    #创建正则表达式对象,表示规则
#影片图片
findsrc=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)

def GetData(baseurl):
    datalist=[]
    for i in range(0,10):
        url = baseurl + str(i*25)   # 调用获取页面信息函数10次
        html =AskURL(url)
        # 2.边爬取边解析数据
        soup = BeautifulSoup(html,"html.parser")
        for item in soup.find_all('div',class_="item"): #查找符合要求的字符串形成列表,
            data = []   #保存一部影片所有信息
            item=str(item)
          
            #影片详情页链接
            link=re.findall(findlink,item)[0]   #使用re库查找指定字符串
            data.append(link)                   #添加链接

            #影片图片
            imgsrc=re.findall(findsrc,item)[0]
            data.append(imgsrc)                 #添加图片

            #影片名字
            titles=re.findall(findtitle,item)   #片名可能只有中文名没有外文名
            if (len(titles)==2):
                data.append(titles[0])  #添加中文名
                data.append(titles[1].replace("/",""))  #添加外文名
            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)
            bd=re.sub("/","",bd)    #去掉 /
            data.append(bd.strip()) #去掉空格,并添加进data

            datalist.append(data)
  
    # print(datalist)

    return datalist

#保存数据
def SaveData(datalist,savepath):

    workbook=xlwt.Workbook(encoding="utf-8")    #创建workbook对象
    worksheet=workbook.add_sheet("豆瓣TOP250")      #创建工作表取名sheet1
  
    col=("电影详情链接","图片链接","影片中文名","影片外文名","评分","评价数","概况","相关信息")
    for i in range(0,8):
        worksheet.write(0,i,col[i])     #添加表头
    for i in range(0,250):
        print("第%d条"%i)
        data=datalist[i]
        for j in range(0,8):
            worksheet.write(i+1,j,data[j])
    workbook.save(savepath)                #保存数据表取名为student.xls

#得到一个指定url的内容
def AskURL(url):
    headers={   #模拟浏览器头部信息,向豆瓣发送请求
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
    }
    request = urllib.request.Request(url=url,headers=headers)
    try:
        response =urllib.request.urlopen(request)
        html = response.read().decode("utf-8")
        # print(html)
    except urllib.error.URLError as e:
        if hasattr(e,"code"):
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)
    return html


if __name__ == "__main__":
    main()

保存数据到数据库

sqlite基本使用方法

  1. 建立数据库表
import sqlite3
# 建表
conn=sqlite3.connect("test.db") # 打开或创建数据库
c=conn.cursor() #获取游标
sql ='''
create table commpany
(id int primary key not null,
name text not null,
age int not null,
address char(50),
salary real)
'''
c.execute(sql)  #执行sql语句
conn.commit()   #提交数据库操作
c.close()       #关闭游标
conn.close()    #关闭数据库
  1. 插入数据
import sqlite3
# 插入数据
conn=sqlite3.connect("test.db") # 打开或创建数据库
c=conn.cursor() #获取游标
sql1 ='''
insert into commpany (id,name,age,address,salary)
values (1,'张三',32,'成都',8000);
'''
sql2 ='''
insert into commpany (id,name,age,address,salary)
values (2,'李四',30,'重庆',10000);
'''
c.execute(sql1)  #执行sql语句
c.execute(sql2)  #执行sql语句
conn.commit()   #提交数据库操作
c.close()       #关闭游标
conn.close()    #关闭数据库
  1. 查询数据库
import sqlite3
# 查询数据库
conn=sqlite3.connect("test.db") # 打开或创建数据库
c=conn.cursor() #获取游标
sql ='''
select id,name,age,address,salary from commpany
'''
cur=c.execute(sql)  #执行sql语句

for row in cur:
    print("id = ",row[0])
    print("name = ",row[1])
    print("address = ",row[2])
    print("salary = ",row[3],"\n")

c.close()       #关闭游标
conn.close()    #关闭数据库

保存数据到数据库代码

from bs4 import BeautifulSoup   #网页解析获取数据
import re   #正则表达式进行文字匹配
import urllib.request , urllib.error , requests   #网页请求
import xlwt #进行Excel操作
import sqlite3  #进行sqlite数据库操作

# 主函数
def main():
    baseurl = "https://movie.douban.com/top250?start="
    # 1.爬取网页
    datalist=GetData(baseurl)
    # 3.保存数据到Excel
    # savepath = "./豆瓣TOP250.xls"
    # SaveData(datalist,savepath)

    # 4. 保存数据到数据库
    dbpath="./movies.db"
    SaveData2DB(datalist,dbpath)

#详情链接
findlink=re.compile(r'<a href="(.*?)">')    #创建正则表达式对象,表示规则
#影片图片
findsrc=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)

def GetData(baseurl):
    datalist=[]
    for i in range(0,10):
        url = baseurl + str(i*25)   # 调用获取页面信息函数10次
        html =AskURL(url)
        # 2.边爬取边解析数据
        soup = BeautifulSoup(html,"html.parser")
        for item in soup.find_all('div',class_="item"): #查找符合要求的字符串形成列表,
            data = []   #保存一部影片所有信息
            item=str(item)
          
            #影片详情页链接
            link=re.findall(findlink,item)[0]   #使用re库查找指定字符串
            data.append(link)                   #添加链接

            #影片图片
            imgsrc=re.findall(findsrc,item)[0]
            data.append(imgsrc)                 #添加图片

            #影片名字
            titles=re.findall(findtitle,item)   #片名可能只有中文名没有外文名
            if (len(titles)==2):
                data.append(titles[0])  #添加中文名
                data.append(titles[1].replace("/",""))  #添加外文名
            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)
            bd=re.sub("/","",bd)    #去掉 /
            data.append(bd.strip()) #去掉空格,并添加进data

            datalist.append(data)
  
    # print(datalist)

    return datalist

#保存数据
def SaveData(datalist,savepath):

    workbook=xlwt.Workbook(encoding="utf-8")    #创建workbook对象
    worksheet=workbook.add_sheet("豆瓣TOP250")      #创建工作表取名sheet1
  
    col=("电影详情链接","图片链接","影片中文名","影片外文名","评分","评价数","概况","相关信息")
    for i in range(0,8):
        worksheet.write(0,i,col[i])     #添加表头
    for i in range(0,250):
        # print("第%d条"%i)
        data=datalist[i]
        for j in range(0,8):
            worksheet.write(i+1,j,data[j])
    workbook.save(savepath)                #保存数据表取名为student.xls

#得到一个指定url的内容
def AskURL(url):
    headers={   #模拟浏览器头部信息,向豆瓣发送请求
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
    }
    request = urllib.request.Request(url=url,headers=headers)
    try:
        response =urllib.request.urlopen(request)
        html = response.read().decode("utf-8")
        # print(html)
    except urllib.error.URLError as e:
        if hasattr(e,"code"):
            print(e.code)
        if hasattr(e,"reason"):
            print(e.reason)
    return html

def init_db(dbpath):
    sql='''
        create table movies250
        (id integer primary key autoincrement,
        info_link text,
        pic_link text,
        cname varchar,
        ename varchar,
        score numeric,
        rated numeric,
        instroduction text,
        info text)
    '''
    conn=sqlite3.connect(dbpath)
    cursor=conn.cursor()    #获取游标
    cursor.execute(sql)     #执行SQL语句:创建数据表
    conn.commit()           #事务提交:让操作生效
    cursor.close()          #关闭游标
    conn.close()            #关闭连接 

def SaveData2DB(datalist,dbpath):
    init_db(dbpath)
    conn=sqlite3.connect(dbpath)
    cursor=conn.cursor()    #获取游标

    for data in datalist:
        for index in range(len(data)):
            if index ==4 or index==5:
                continue
            data[index]='"'+data[index]+'"'         # sql语句中的字符串添加 " " 
        sql = '''
        insert into movies250(info_link,pic_link,cname,ename,score,rated,instroduction,info)
        values (%s)
        '''%",".join(data)
        # print(data)
        # print("%s"%",".join(data))
        # print(sql)
        cursor.execute(sql)     #执行SQL语句:创建数据表
        conn.commit()           #事务提交:让操作生效

    cursor.close()          #关闭游标
    conn.close()            #关闭连接 

if __name__ == "__main__":
    main()

豆瓣Top250项目可视化代码以及资料

Github仓库:https://github.com/imgyh/DouBan_Top250


  1. abc
最后修改:2022 年 12 月 20 日
如果觉得我的文章对你有用,请随意赞赏