Python案例实操1-网络爬虫



案例1:使用Python爬虫、sqlite技术爬取x半电影Top250的电影数据,并保存成Excel文件和数据库文件


  1. 新建.py文件,定义程序运行的入口
if __name__ == "__main__":
	pass
  1. 分析爬取的网址信息
    x半电影TOP250,分析网址的规律,点击下一页可以发现每次点击都会在网址后面拼接上start参数,参数表示上一页结束新一页开始
  2. 开始爬取网页, 爬取网页过程就是解析数据的过程,里面会使用到urllib.request模块获取网页数据、BeautifulSoup模块解析数据、re正则表达式模块匹配查找数据等
def getData(baseurl):
    """爬取网页"""
    datalist = []
    for i in range(0, 10):  # 遍历页数
        url = baseurl + str(i * 25)  # 拼接URL,指定开始位置
        html = askUrl(url)
        # 解析网页数据
        soup = BeautifulSoup(html, "html.parser")
        for item in soup.find_all("div", class_="item"):  # 遍历指定查找结果列表
            data = []  # 保存电影信息
            item = str(item)  # 将item转成字符串
            link = re.findall(patlink, item)[0]  # 查找电影详情链接
            data.append(link)
            imgstr = re.findall(patimg, item)[0]  # 电影图片
            data.append(imgstr)
            titles = re.findall(pattitle, item)  # 电影名称,有多个名字
            if len(titles) == 2:
                data.append(titles[0])  # 中文名
                data.append(titles[1].replace("/", ""))  # 外文名, 去掉多余/
            else:
                data.append(titles[0])
                data.append("")  # 外文名留空
            score = re.findall(patscore, item)[0]  # 评分
            data.append(score)
            num = re.findall(patpeople, item)[0]  # 评价人数
            data.append(num)
            desc = re.findall(patdesc, item)  # 一句话描述
            if len(desc) != 0:
                data.append(desc[0])
            else:
                data.append("")
            bd = re.findall(patbd, item)[0]  # 背景信息
            bd = re.sub("<br(\s+)?/>(\s+)?", "", bd.strip())  # 去除<br/>标签, strip()去空格
            data.append(bd)
            datalist.append(data)
    return datalist
  1. 通过request请求数据时,经常会遇到反爬虫的网站,会报状态码418错误,需要我们手动设置headers来模拟正常用户请求,跳过反爬虫的拦截
def askUrl(baseurl):
    """获取指定URL网页数据"""
    # 设置headers来模拟正常用户请求
    header = {
        "User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 97.0.4692.99 Safari / 537.36 Edg / 97.0.1072.69"
    }
    req = urllib.request.Request(baseurl, headers=header)
    response = urllib.request.urlopen(req)
    html = response.read().decode("utf-8")
    return html
  1. 解析得到我们所需要的数据后,使用sqlite模块保存到数据库文件中,方便后续对数据的处理(如词云生成,后面会有案例)
    连接数据库,并建立movie表
def init_db(dbpath):
    """初始化数据库"""
    conn = sqlite3.connect(dbpath)
    # 获取游标
    c = conn.cursor()
    # 建表sql语句
    sql1 = "drop table if exists movie;"
    sql2 = '''
            create table movie(
                link_detail varchar not null, 
                link_img varchar, 
                c_title varchar not null, 
                o_title varchar,
                score number, 
                num int, 
                desc varchar, 
                bd text
            )
        '''
    c.execute(sql1)
    c.execute(sql2)
    conn.commit()
    conn.close()
  1. 将数据保存到数据库中
def insert(datalist, dbpath):
    """数据库新增操作"""
    conn = sqlite3.connect(dbpath)
    c = conn.cursor()
    print("%d 条数据待写入数据库" % len(datalist))
    for move in datalist:
        for index in range(0, len(move)):
            if index == 4 or index == 5:
                continue
            move[index] = '"' + move[index].strip() + '"'  # 给value加上双引号, 数字类型不用加
        sql = '''
                insert into movie(link_detail, link_img, c_title, o_title, score, num, desc, bd)
                values(%s)
        ''' % ','.join(move)  # value之间用,连接
        c.execute(sql)
        conn.commit()
    c.close()
    conn.close()
  1. 运行程序,生成movie.db数据库文件,大功告成!
  2. 附上程序完整代码 spider.py
import urllib.request
from bs4 import BeautifulSoup
import re
import xlwt
import sqlite3

# 匹配规则
# 电影详情
patlink = re.compile(r'a href="(.*?)">')
# 电影图片
patimg = re.compile(r'<img.*src="(.*?)"', re.S)  # re.S:让换行符也包含在字符串中
# 电影名称
pattitle = re.compile(r'<span class="title">(.*?)</span>')
# 电影评分
patscore = re.compile(r'<span class="rating_num" property="v:average">(.*?)</span>')
# 影评人数
patpeople = re.compile(r'<span>(\d*)人评价</span>')
# 电影概况
patdesc = re.compile(r'<span class="inq">(.*?)</span>')
# 电影背景
patbd = re.compile(r'<p class="">(.*?)</p>', re.S)


def getData(baseurl):
    """爬取网页"""
    datalist = []
    for i in range(0, 10):  # 遍历页数
        url = baseurl + str(i * 25)  # 拼接URL,指定开始位置
        html = askUrl(url)
        # 解析网页数据
        soup = BeautifulSoup(html, "html.parser")
        for item in soup.find_all("div", class_="item"):  # 遍历指定查找结果列表
            data = []  # 保存电影信息
            item = str(item)  # 将item转成字符串
            link = re.findall(patlink, item)[0]  # 查找电影详情链接
            data.append(link)
            imgstr = re.findall(patimg, item)[0]  # 电影图片
            data.append(imgstr)
            titles = re.findall(pattitle, item)  # 电影名称,有多个名字
            if len(titles) == 2:
                data.append(titles[0])  # 中文名
                data.append(titles[1].replace("/", ""))  # 外文名, 去掉多余/
            else:
                data.append(titles[0])
                data.append("")  # 外文名留空
            score = re.findall(patscore, item)[0]  # 评分
            data.append(score)
            num = re.findall(patpeople, item)[0]  # 评价人数
            data.append(num)
            desc = re.findall(patdesc, item)  # 一句话描述
            if len(desc) != 0:
                data.append(desc[0])
            else:
                data.append("")
            bd = re.findall(patbd, item)[0]  # 背景信息
            bd = re.sub("<br(\s+)?/>(\s+)?", "", bd.strip())  # 去除<br/>标签, strip()去空格
            data.append(bd)
            datalist.append(data)
    return datalist


def askUrl(baseurl):
    """获取指定URL网页数据"""
    # 设置headers来模拟正常用户请求
    header = {
        "User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 97.0.4692.99 Safari / 537.36 Edg / 97.0.1072.69"
    }
    req = urllib.request.Request(baseurl, headers=header)
    response = urllib.request.urlopen(req)
    html = response.read().decode("utf-8")
    return html


def saveData(datalist, filepath):
    """保存数据到Excel文件中"""
    workbook = xlwt.Workbook(encoding="utf-8")  # 创建Workbook对象
    sheet = workbook.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):
        move = datalist[i]  # 遍历影片信息 "行"
        for j in range(0, len(col)):  # "列"
            sheet.write(i + 1, j, move[j])  # 注意:从第二行开始写入影片信息
    workbook.save(filepath)  # 保存到文件


def init_db(dbpath):
    """初始化数据库"""
    conn = sqlite3.connect(dbpath)
    # 获取游标
    c = conn.cursor()
    # 建表sql语句
    sql1 = "drop table if exists movie;"
    sql2 = '''
            create table movie(
                link_detail varchar not null, 
                link_img varchar, 
                c_title varchar not null, 
                o_title varchar,
                score number, 
                num int, 
                desc varchar, 
                bd text
            )
        '''
    c.execute(sql1)
    c.execute(sql2)
    conn.commit()
    conn.close()


def insert(datalist, dbpath):
    """数据库新增操作"""
    conn = sqlite3.connect(dbpath)
    c = conn.cursor()
    print("%d 条数据待写入数据库" % len(datalist))
    for move in datalist:
        for index in range(0, len(move)):
            if index == 4 or index == 5:
                continue
            move[index] = '"' + move[index].strip() + '"'  # 给value加上双引号, 数字类型不用加
        sql = '''
                insert into movie(link_detail, link_img, c_title, o_title, score, num, desc, bd)
                values(%s)
        ''' % ','.join(move)  # value之间用,连接
        c.execute(sql)
        conn.commit()
    c.close()
    conn.close()


def saveToSqlite(datalist, dbpath):
    """保存数据到Sqlite文件中"""
    # 初始化数据库连接
    init_db(dbpath)

    # 将数据插入表中
    insert(datalist, dbpath)


if __name__ == "__main__":
    baseurl = "https://movie.douban.com/top250?start=";
    # 1.爬取网页
    datalist = getData(baseurl)
    # 2.保存数据到Excel中
    # filepath = "豆瓣电影TOP250.xls"
    # saveData(datalist, filepath)
    # 3.保存数据到sqlite
    dbpath = "movie.db"
    saveToSqlite(datalist, dbpath)
    print("爬取成功!")