小工具知识网

当前位置: 首页 > 行业知识 > 爬虫实战-手把手教你爬豆瓣电影 | 附详细源码和讲解

行业知识

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

2026-10-31 00:44:31 来源:互联网转载
写在前面的话

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

来源: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:影片备注信息,一般为空

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

    # 定位到影片数据的 psoup_p = 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_p.find_all('span')[0].find_all('a'))movie_info['movie_writer'] = self.get_mul_tag_info(soup_p.find_all('span')[3].find_all('a'))movie_info['movie_starring'] = self.get_mul_tag_info(soup_p.find_all('span')[6].find_all('a'))movie_info['movie_type'] = self.get_mul_tag_info(soup_p.find_all('span', property='v:genre'))movie_info['movie_country'] = soup_p.find(text='制片国家/地区:').next_element.lstrip().rstrip()movie_info['movie_language'] = soup_p.find(text='语言:').next_element.lstrip().rstrip()movie_info['movie_release_date'] = self.get_mul_tag_info(soup_p.find_all('span', property='v:initialReleaseDate'))movie_info['movie_run_time'] = self.get_mul_tag_info(soup_p.find_all('span', property='v:runtime'))movie_info['movie_imdb_href'] = soup_p.find('a', target='_blank')['href']

    “小一哥,又出问题了,有的影片没有又名标签,这个怎么处理呢?”

    “这个我们做个异常检测,没有的手动赋空值就行了。”

    movie_second_name = ''try:movie_second_name = soup_p.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].stringmovie_info['movie_comments_user'] = soup.find_all('span', property='v:votes')[0].string

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

    所以,先定位 p :

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

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

    # 获取每个星级的评分movie_info['movie_five_star_ratio'] = soup_p.find_all('p')[0].find(class_='rating_per').stringmovie_info['movie_four_star_ratio'] = soup_p.find_all('p')[2].find(class_='rating_per').stringmovie_info['movie_three_star_ratio'] = soup_p.find_all('p')[4].find(class_='rating_per').stringmovie_info['movie_two_star_ratio'] = soup_p.find_all('p')[6].find(class_='rating_per').stringmovie_info['movie_one_star_ratio'] = soup_p.find_all('p')[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)# 获取数据并保存成 DataFramedf_data = pd.DataFrame(self.data_info)# 导入数据到 mysql 中df_data.to_sql('t_douban_movie_top_250', self.pymysql_engine, index=False, if_exists='append')

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

    ​

    编辑

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

     

    总结一下:

    准备工作:

     

    开始爬虫:

     

    思考:

    第一个项目,旨在让大家了解爬虫流程,同时,也可以思考一下以下几点:

     

    写在后面的话

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

    开篇已经提到,我们的目的不是爬数据。所以,我会利用这些数据做一个简单数据分析,目的很简单:了解数据分析的流程。下期见。

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

上一篇:掌上飞车怎么选择服务器?

下一篇:【Nginx笔记02】通过Nginx服务器转发客户端的WebSocket接口到后端服务