爬虫实战-手把手教你爬豆瓣电影 | 附详细源码和讲解

这篇具有很好参考价值的文章主要介绍了爬虫实战-手把手教你爬豆瓣电影 | 附详细源码和讲解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面的话

目前为止,你应该已经了解爬虫的三个基本小节:

来源:xiaqo.com
 

  • 正文

    明确需求

    我们今天要爬的数据是豆瓣电影Top250,是的,只有250条数据,你没猜错。
    输入网址 https://movie.douban.com/top250 我们可以看到网页长这样:
     

    如何用网络爬虫爬取电影名,爬虫

    编辑

    如何用网络爬虫爬取电影名,爬虫

    编辑

    `250条数据`清清楚楚,没有问题。

    可以看到,这个页面其实已经包含了影片的主要内容:影片名、排序、编剧、主演、年份、类型、评论人数、评分,基本上都在这个页面中。但我点开详细影片之后,发现了这个:

    如何用网络爬虫爬取电影名,爬虫

    编辑

    似乎这个页面数据更全一些,我们爬数据要的是什么,肯定是数据越多越好啊。相比这个详细内容,更是多了每个星级的影评占比,那我们肯定选择它了啊


    好,那理一下我们的思路

     

    写一下伪代码

    # 遍历10页
    data_movies # 保存所有影片数据集
    for per_page in pages:	
    	# 爬取10页的每一页数据 
    	movies = craw_page_info(per_page)
        # 遍历每一页的25个影片
    	for movie in movies:
            # 爬取每个影片的详细内容
            data_per_movie = craw_detail_info(movie)
            # 保存每个影片信息到数据集中
            data_movies.append(data_per_movie)
            
    # 保存结果到数据库中
    data_movies_to_mysql
    

    稍微解释一下:两层循环,第一层是遍历10页网页,因为其中每个网页分别有25个影片,所以,第二层循环又依次遍历25个影片获取详细信息,最后保存结果到数据库中!

    是不是,很,简,单!

    但是,实操起来你可能会遇到各种各样的问题,做好心理准备!


    #### 开始实操 **首先,确定我们要输出的影片字段** `主要数据`包括:影片排序、影片名称、影片导演、影片编剧、影片主演、影片又名、影片链接 `关键数据`包括:影片类型、制片国家、影片语言、上映日期、影片片长 `核心数据`包括:影片评分、评论人数、5/4/3/2/1各星级对应的评论占比

    字段如下

    movie_rank:影片排序
    movie_name:影片名称
    movie_director:影片导演
    movie_writer:影片编剧
    movie_starring:影片主演
    movie_type:影片类型
    movie_country:影片制片国家
    movie_language:影片语言
    movie_release_date:影片上映日期
    movie_run_time:影片片长
    movie_second_name:影片又名
    movie_imdb_href:影片IMDb 链接
    movie_rating:影片总评分
    movie_comments_user:影片评论人数
    movie_five_star_ratio:影片5星占比
    movie_four_star_ratio:影片4星占比
    movie_three_star_ratio:影片3星占比
    movie_two_star_ratio:影片2星占比
    movie_one_star_ratio:影片1星占比
    movie_note:影片备注信息,一般为空
    


    然后,开始主流程

    确认一下主要参数,起始页码(默认为0),每页影片25个,共10页,
    参数如下

    start_page:起始页码
    page_size:每一页大小
    pages:总页码
    


    定义类对象

    这里我们将每个影片封装成一个对象,传入我们的主要参数,设置爬虫头部,并建立和数据库的相关连接

    类定义对象如下

    class DouBanMovie:
        def __init__(self, url, start_page, pages, page_size):
            """
            初始化
            @param url: 爬取主网址
            @param start_page: 起始页码
            @param pages: 总页码(截止页码)
            @param page_size: 每页的大小
            """
            self.url = url
            self.start_page = start_page
            self.pages = pages
            self.page_size = page_size
            self.data_info = []
            self.pymysql_engine, self.pymysql_session = connection_to_mysql()
            self.headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
            }
    

    “小一哥,你这里的数据库连接用的是什么啊,我怎么看不太懂?” “我封装了一下,数据库的连接这里选用了 SQLAlchemy。"

    不要着急,以后会专门写一篇 SQLAlchemy 关于数据库的相关操作

    #  创建基类,
    Base = declarative_base()
    
    def connection_to_mysql():
        """
        连接数据库
        @return:
        """
        engine = create_engine('mysql+pymysql://username:passwd@localhost:3306/db_name?charset=utf8')
        Session = sessionmaker(bind=engine)
        db_session = Session()
        # 创建数据表
        Base.metadata.create_all(engine)
    
        return engine, db_session
    


    确定主框架:

    # 如果当前页码小于0,异常退出
    if self.start_page < 0:
    	return ""
    # 如果起始页面大于总页码数,退出
    if self.start_page > self.pages:
    	return ""
    
    # 若当前页其实页码小于总页数,继续爬取数据
    while self.start_page < pages:
        # 拼接当前页的网址
        # 主爬虫代码
        # 下一页
        self.start_page = self.start_page + 1
    

    拼接当前页的网址这里解释一下,当我们去访问第一页的时候发现网址如下

    https://movie.douban.com/top250
    

    去访问下一页的时候发现网址变化如下

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

    而再下一页的网址变化如下:

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

    可以发现,新的网址只是变化了后面的 start 参数,于是我们拼接出每一页的网址:

    start_number = self.start_page * self.page_size
    new_url = self.url + '?start=' + str(start_number) + '&filter='
    
     

    爬取第一个页面

    确定好主框架之后,我们需要去爬取第一个网页,也就是包含25个影片的页面
    这时候,我们前三节提到的爬虫实现方式直接拿过来:

    self.headers = {
    	'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
    }
                
    # 爬取当前页码的数据
    response = requests.get(url=new_url, headers=self.headers)
    


    成功获取到页面数据之后,我们需要对页面解析,拿到每一个影片跳转详细页面的超链接

    通过谷歌浏览器 F12 开发者工具可查看网页源码

    可以看到每个影片的详细信息在一个li 标签中,而每个 li 标签中都有一个class='pic' 的 div,在 div 里面存在这样一个 a 标签 中

    而这个 a 标签的 href 正是我们要需要的 详细页面信息的超链接

    如何用网络爬虫爬取电影名,爬虫

    编辑


    确定了超链接位置所在,打开我们上一节的 BeautifulSoup 详解,定位、解析

    soup = BeautifulSoup(response.text, 'html.parser')
    # 定位到每一个电影的 div (pic 标记的 div)
    soup_div_list = soup.find_all(class_="pic")
    # 遍历获取每一个 div 的电影详情链接
    for soup_div in soup_div_list:
        # 定位到每一个电影的 a 标签
        soup_a = soup_div.find_all('a')[0]
        movie_href = soup_a.get('href')
        print(movie_href)
    

    拿到当前页面的25 个影片的详细内容的超链接

    我们离成功又进了一步!


    爬取详细页面

    同样,一行代码拿下页面数据

    '''爬取页面,获得详细数据'''
    response = requests.get(url=movie_detail_href, headers=self.headers)
    

    创建一个有序字典,保存当前影片数据

    # 生成一个有序字典,保存影片结果
    movie_info = OrderedDict()
    

    我们再来看一下这个页面的的源码是什么样的,首先是影片排序和影片名称,我们可以从上个页面传递过来。但是,既然它这里有,我直接解析行不行?

    必须行啊!

    如何用网络爬虫爬取电影名,爬虫

    编辑

    这个更简单,影片排名直接定位一个 `class='top250-no' 的 span 标签`,影片名称定位一个 `property='v:itemreviewed' 的 span 标签`,获取标签内容即可
    # 解析电影排名和名称
    movie_info['movie_rank'] = soup.find_all('span', class_='top250-no')[0].string
    movie_info['movie_name'] = soup.find_all('span', property='v:itemreviewed')[0].string
    
     

    接下来是影片主要数据

    如何用网络爬虫爬取电影名,爬虫

    编辑




    这个时候我们需要先定位到 id='info' 的 div中,然后可以看到整个 div 的数据就是我们需要的主要数据。

    # 定位到影片数据的 div
    soup_div = soup.find(id='info')
    

    “不对啊,小一哥,我发现编剧有时候是一个,有时候是多个。多个的时候存在在多个 span 标签中,这个怎么办啊?”

    如何用网络爬虫爬取电影名,爬虫

    编辑

    “这个简单,我写一个小函数,统一处理一下。“

    def get_mul_tag_info(self, soup_span):
        """
        获取多个标签的结果合并在一个结果中返回,并用 / 分割
        """
        info = ''
        for second_span in soup_span:
            # 区分 href 和标签内容
            info = ('' if (info == '') else '/').join((info, second_span.string))
    
        return info
    

    “对了,你记得把最外层的 span 标签给我就行。像这种:”

    # 解析电影发布信息
    movie_info['movie_director'] = self.get_mul_tag_info(soup_div.find_all('span')[0].find_all('a'))
    movie_info['movie_writer'] = self.get_mul_tag_info(soup_div.find_all('span')[3].find_all('a'))
    movie_info['movie_starring'] = self.get_mul_tag_info(soup_div.find_all('span')[6].find_all('a'))
    movie_info['movie_type'] = self.get_mul_tag_info(soup_div.find_all('span', property='v:genre'))
    movie_info['movie_country'] = soup_div.find(text='制片国家/地区:').next_element.lstrip().rstrip()
    movie_info['movie_language'] = soup_div.find(text='语言:').next_element.lstrip().rstrip()
    movie_info['movie_release_date'] = self.get_mul_tag_info(soup_div.find_all('span', property='v:initialReleaseDate'))
    movie_info['movie_run_time'] = self.get_mul_tag_info(soup_div.find_all('span', property='v:runtime'))
    movie_info['movie_imdb_href'] = soup_div.find('a', target='_blank')['href']
    

    “小一哥,又出问题了,有的影片没有又名标签,这个怎么处理呢?”
    “这个我们做个异常检测,没有的手动赋空值就行了。”

    movie_second_name = ''
    try:
    	movie_second_name = soup_div.find(text='又名:').next_element.lstrip().rstrip()
    except AttributeError:
        print('{0} 没有又名'.format(movie_info['movie_name']))
        movie_info['movie_second_name'] = movie_second_name
    
     

    最后还剩下评分数据

    评分数据不但有总评分,还有每个星级的评分。

    “小一哥,你说我们取哪个数据啊?”
    “小孩才做选择,我当然是全部都要!”

    如何用网络爬虫爬取电影名,爬虫

    编辑

    可以看到,总评分和总评论人数分别有一个`唯一的 property`,分别是` property='v:average' 的 strong 标签`和 `property='v:votes' 的 span 标签`

    ok,接下来直接拿数据:

    # 获取总评分和总评价人数
    movie_info['movie_rating'] = soup.find_all('strong', property='v:average')[0].string
    movie_info['movie_comments_user'] = soup.find_all('span', property='v:votes')[0].string
    

    最后就剩下每个星级的评分占比,可以看到 5星/4星/3星/2星/1星 分别对应 力荐/推荐/还行/较差/很差,可以看到他们都存在在一个class='ratings-on-weight' 的 div

    所以,先定位 div :

    # 定位到影片星级评分占比的 div
    soup_div = soup.find('div', class_="ratings-on-weight")
    

    然后获取每个星级评分占比数据:

    # 获取每个星级的评分
    movie_info['movie_five_star_ratio'] = soup_div.find_all('div')[0].find(class_='rating_per').string
    movie_info['movie_four_star_ratio'] = soup_div.find_all('div')[2].find(class_='rating_per').string
    movie_info['movie_three_star_ratio'] = soup_div.find_all('div')[4].find(class_='rating_per').string
    movie_info['movie_two_star_ratio'] = soup_div.find_all('div')[6].find(class_='rating_per').string
    movie_info['movie_one_star_ratio'] = soup_div.find_all('div')[8].find(class_='rating_per').string
    

    打印一下看一下我们当前的影片数据:

    对 movie_starring 字段只输出部分显示

    OrderedDict(
    	[
    		('movie_rank', 'No.1'), 
    		('movie_name', '肖申克的救赎 The Shawshank Redemption'), 
    		('movie_director', '弗兰克·德拉邦特'), 
    		('movie_writer', '弗兰克·德拉邦特/斯蒂芬·金'), 
    		('movie_starring', '蒂姆·罗宾斯/摩根·弗里曼/鲍勃·冈顿/威廉姆·赛德勒/), 
    		('movie_type', '剧情/犯罪'), 
    		('movie_country', '美国'), 
    		('movie_language', '英语'), 
    		('movie_release_date', '1994-09-10(多伦多电影节)/1994-10-14(美国)'), 
    		('movie_run_time', '142分钟'), 
    		('movie_imdb_href', 'https://www.imdb.com/title/tt0111161'), 
    		('movie_rating', '9.7'), 
    		('movie_comments_user', '1720706'), 
    		('movie_five_star_ratio', '84.8%'), 
    		('movie_four_star_ratio', '13.6%'), 
    		('movie_three_star_ratio', '1.4%'), 
    		('movie_two_star_ratio', '0.1%'), 
    		('movie_one_star_ratio', '0.1%'), 
    		('movie_note', '')
    	]
    )
    

    搞定,成功拿到了想要的数据,最后一步:保存数据库

    # 保存当前影片信息
    self.data_info.append(movie_info)
    
    # 获取数据并保存成 DataFrame
    df_data = pd.DataFrame(self.data_info)
    # 导入数据到 mysql 中
    df_data.to_sql('t_douban_movie_top_250', self.pymysql_engine, index=False, if_exists='append')
    

    看一眼我们的数据库,该有的数据都存进去了

    如何用网络爬虫爬取电影名,爬虫

    编辑

    到这里,爬虫就算是结束了。


     

    总结一下:

    准备工作:

     

    开始爬虫:

     

    思考:

    以上就是我们今天爬虫实战的主要内容,相对来说比较简单。
    第一个项目,旨在让大家了解爬虫流程,同时,也可以思考一下以下几点:

    以上数据的获取是否可以用今天的获取方法?如果不行,那应该通过什么方式获取这些数据?

     

    写在后面的话

    今天的实战项目就结束了,需要源代码的同学可以在公众号后台回复 豆瓣电影 获取,如果觉得小一哥讲的还不错的话,不妨点个赞

    开篇已经提到,我们的目的不是爬数据。所以,我会利用这些数据做一个简单数据分析,目的很简单:了解数据分析的流程。下期见。文章来源地址https://www.toymoban.com/news/detail-844208.html

    • 首先,进入豆瓣电影Top250,一共10页,每页25个影片。
    • 然后,针对每一页的25个影片,进入其详细内容页面
    • 最后,解析每个影片的详细内容,保存内容到数据库中
    • 首先我们定义了一个影片对象,传入了网址的参数信息,设置了爬虫头部,并建立了数据库连接
    • 我们通过下一页分析出每个影片页的超链接,发现只是改变了参数
    • 建立了主流程,并写出了主流程的伪代码
    • 爬取第一页的网页内容
    • 解析第一页的内容,获取每页中25个影片的详细超链接
    • 爬取详细影片的网页内容
    • 解析第二页的内容,保存到每个影片对象中
    • 保存数据到数据库中
    • 影片详细页面的短评论数据
    • 影片详细页面的获奖情况数据
    • 影片详细页面的讨论区数

到了这里,关于爬虫实战-手把手教你爬豆瓣电影 | 附详细源码和讲解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 小白必看、手把手教你利用爬虫爬网页

    接下来从网络爬虫的概念、用处与价值和结构等三个方面,让大家对网络爬虫有一个基本的了解。 网络爬虫及其应用 随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战,网络爬虫应运而生。网络爬虫(又被称为网页蜘蛛

    2024年02月07日
    浏览(28)
  • 用Python手把手教你实现一个爬虫(含前端界面)

    前言 爬虫基本原理 使用Python的requests库发送HTTP请求 使用BeautifulSoup库解析HTML页面 使用PyQt5构建前端界面 实现一个完整的爬虫程序 结语 随着互联网的飞速发展,再加上科技圈的技术翻天覆地的革新,互联网上每天都会产生海量的数据,这些数据对于企业和个人都具有重要的

    2024年04月28日
    浏览(32)
  • 手把手教你实战TDD

    领域驱动设计,测试驱动开发。 我们在《手把手教你落地DDD》一文中介绍了领域驱动设计(DDD)的落地实战,本文将对测试驱动开发(TDD)进行探讨,主要内容有:TDD基本理解、TDD常见误区、TDD技术选型,以及案例实战。希望通过本文,读者能够理解掌握TDD并将其应用于实际

    2024年02月08日
    浏览(31)
  • 『爬虫四步走』手把手教你使用Python抓取并存储网页数据!

    爬虫是Python的一个重要的应用,使用Python爬虫我们可以轻松的从互联网中抓取我们想要的数据,**本文将基于爬取B站视频热搜榜单数据并存储为例,详细介绍Python爬虫的基本流程。**如果你还在入门爬虫阶段或者不清楚爬虫的具体工作流程,那么应该仔细阅读本文! 第一步:

    2024年02月04日
    浏览(47)
  • 【实战】手把手教你在 vscode 中写 markdown

    markdown 语法、markdown 插件咱先放放,先说最头疼的,图片问题 相对于 HBuilder 自带 markdown 图片粘贴功能来说,vscode显得不那么友好,若是不装插件粘贴截图就只能手动进行如下操作: 截取图片 将图片存在特定位置 在markdown文件中通过路径引入图片 预览 最终我找到了 Paste I

    2024年02月13日
    浏览(55)
  • 手把手教你针对层级时间轮(TimingWheel)延时队列的实战落地

    承接上文 承接上文,让我们基本上已经知道了「时间轮算法」原理和核心算法机制,接下来我们需要面向于实战开发以及落地角度进行分析如何实现时间轮的算法机制体系。 前言回顾 什么是时间轮 调度模型:时间轮是为解决高效调度任务而产生的调度模型/算法思想。 数据

    2023年04月20日
    浏览(35)
  • pytorch实战7:手把手教你基于pytorch实现VGG16

    前言 ​ 最近在看经典的卷积网络架构,打算自己尝试复现一下,在此系列文章中,会参考很多文章,有些已经忘记了出处,所以就不贴链接了,希望大家理解。 ​ 完整的代码在最后。 本系列必须的基础 ​ python基础知识、CNN原理知识、pytorch基础知识 本系列的目的 ​ 一是

    2023年04月19日
    浏览(40)
  • Autosar诊断实战系列01-手把手教你增加一路31Routine服务

    在本系列笔者将结合工作中对诊断实战部分的应用经验进一步介绍常用UDS服务的进一步探讨及开发中注意事项, Dem/Dcm/CanTp/Fim模块配置开发及注意事项,诊断与BswM/NvM关联模块的应用开发及诊断capl测试脚本开发等诊断相关实战内容。 Autosar诊断实战导读快速链接:Autosar诊断实

    2024年02月08日
    浏览(30)
  • 【图解数据结构】顺序表实战指南:手把手教你详细实现(超详细解析)

    🌈个人主页: 聆风吟 🔥系列专栏: 图解数据结构、算法模板 🔖少年有梦不应止于心动,更要付诸行动。 线性表(linear list):线性表是一种数据结构,由n个具有相同数据类型的元素构成一个有限序列。 线性表可以用数组、链表、栈等方式实现,常见的线性表有数组、链

    2024年01月22日
    浏览(41)
  • 【Golang项目实战】手把手教你写一个备忘录程序|附源码——建议收藏

    博主简介: 努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:数据结构、Go,Java等相关知识。 博主主页: @是瑶瑶子啦 所属专栏: Go语言核心编程 近期目标: 写好专栏的每一篇文章 前几天瑶瑶子学习了Go语言的基础语法知识,那么今天我们就写个

    2024年02月06日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包