从IMDB上爬取MovieLens数据集中的详细电影信息

article/2025/10/12 16:08:22

文章目录

    • 基于协同过滤的电影推荐系统
    • 数据集
    • HTML页面分析
    • 爬虫代码
    • 运行时间
    • 百度网盘链接

基于协同过滤的电影推荐系统

用这个数据集实现了一个小型的电影推荐网站,GitHub代码

数据集

数据集是MovieLens提供的ml-latest-small

https://grouplens.org/datasets/movielens/

试了几个数据集,这个数据集效果比较好

10万条评分记录,3600个用户对电影打的标签,9000部电影,600个用户

数据集的格式是这样的

link.csv :存放电影的imdb id和tmdb id

movies.csv :存放电影的id 名称 类型

ratings.csv :用户对电影的评分,范围是0.5~5

tags.csv :用户对电影打的标签

link.csv文件是这样的格式:

在这里插入图片描述

HTML页面分析

我刚看的时候不明白imdbID是什么意思,后面访问IMBD网站发现,这里的imdbID就是URL里面的标识符在这里插入图片描述
有了link.csv文件里面的imdbID,我们就可以访问到这部电影在IMDB上面的详情页面了(这个数据集也太爽了😄👍)
仔细看这个页面,红框里面是我们需要爬取的信息

这里就不分析了,不然篇幅有点长了,具体看代码就行。自己可以f12看一下页面的组织结构

爬虫代码

爬虫我用的库是requests和BeautifulSoup,其它库没有用的原因是不会,BS4用起来挺顺手的

需要注意的是,我们爬到的是海报的URL,所以在爬信息的过程中还需要再爬一次,发起请求把海报下载下来。下图中,src存储的就是海报的链接
src就是海报的链接
上述分析过程中可以知道,构造请求应该独立成一个函数,因为第一次爬电影信息要用,第二次爬电影海报要用
下面贴一下代码:
我都是把爬虫包装在一个类里面,这个类的函数结构:

在这里插入图片描述
解释一下为什么有white_lst和black_lst这两个奇怪的东西:
下面的爬虫代码我改了很多遍,它的异常处理结构是最后才改好的,也就是说中途会有报错,我需要把bug改好然后继续运行爬虫爬取剩下的电影信息。但是呢,没报错之前已经爬取了一些电影了,我就不需要重头爬了,因此我用一个white_lst来存放已经爬取完成的电影信息。
black_lst是用来存放爬取过程中出错的电影,例如ImdbID失效啊(很少),没有海报信息啊(有几部是这样的),整个数据集爬取完后,再处理这个black_lst里面的电影(最后我发现大概就十部不到的电影出错,于是我就手动处理了)
下图是运行日志中记录的爬取出错的电影
在这里插入图片描述

import requests
from bs4 import BeautifulSoup
import unicodedata
import logging
import csv
import timeclass Model():def __init__(self):# 请求头self.headers = {'User-Agent': 'Mozilla/5.o (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36'}# 存放每一步电影的id和imdb的idself.movie_dct = {}# 存放已经处理完的movie idself.white_lst = []# 电影详情的初始urlself.url = 'https://www.imdb.com/title/'self.movie_csv_path = '../ml-latest-small/links.csv'# 海报的保存路径self.poster_save_path = './poster'# 电影信息的保存文件self.info_save_path = './info/info.csv'# logging的配置,记录运行日志logging.basicConfig(filename="run.log", filemode="a+", format="%(asctime)s %(name)s:%(levelname)s:%(message)s",datefmt="%Y-%m-%d %H:%M:%S", level=logging.INFO)# 表示当前处理的电影self.cur_movie_id = Noneself.cur_imdb_id = Nonedef get_white_lst(self):'''获取处理完的白名单'''with open('white_list') as fb:for line in fb:line = line.strip()self.white_lst.append(line)def get_movie_id(self):'''获取电影的id和imdb的id'''with open(self.movie_csv_path) as fb:fb.readline()for line in fb:line = line.strip()line = line.split(',')# 电影id 对应 imdbidself.movie_dct[line[0]] = line[1]def update_white_lst(self, movie_id):'''更新白名单'''with open('white_list', 'a+') as fb:fb.write(movie_id + '\n')def update_black_lst(self, movie_id, msg=''):with open('black_list.txt', 'a+') as fb:# 写入movie id 和imdb id,并且加上错误原因# msg=1是URL失效,msg=2是电影没有海报fb.write(movie_id + ' ' + self.movie_dct[movie_id] + ' ' + msg + '\n')def get_url_response(self, url):'''访问网页请求,返回response'''logging.info(f'get {url}')i = 0# 超时重传,最多5次while i < 5:try:response = requests.get(url, timeout=6)if response.status_code == 200:logging.info(f'get {url} sucess')# 正常获取,直接返回return response# 如果状态码不对,获取失败,返回None,不再尝试logging.error(f'get {url} status_code error: {response.status_code} movie_id is {self.cur_movie_id}')return Noneexcept requests.RequestException:# 如果超时logging.error(f'get {url} error, try to restart {i + 1}')i += 1# 重试5次都失败,返回Nonereturn Nonedef process_html(self, html):'''解析html,获取海报,电影信息'''soup = BeautifulSoup(html, 'lxml')# 名字和发布日期 如:Toy Story (1995)name = soup.find(class_='title_wrapper').h1.get_text()# 去掉html的一些/x20等空白符name = unicodedata.normalize('NFKC', name)# print(name)poster_url = ''try:# 海报的URLposter_url = soup.find(class_='poster').a.img['src']poster_re = self.get_url_response(poster_url)# 保存图片self.save_poster(self.cur_movie_id, poster_re.content)except AttributeError as e:# 如果没有海报链接,那么在黑名单中更新它# msg=2表示没有海报链接self.update_black_lst(self.cur_movie_id, '2')# 电影的基本信息   1h 21min | Animation, Adventure, Comedy | 21 March 1996 (Germany)info = []try:# 时长时间info.append(soup.find(class_='subtext').time.get_text().strip())except AttributeError as e:# 没有则添加空字符串info.append('')# 基本信息和详细发布时间 Animation, Adventure, Comedy | 21 March 1996 (Germany)for tag in soup.find(class_='subtext').find_all('a'):info.append(tag.get_text().strip())# 简介intro = soup.find(class_='summary_text').get_text().strip()intro = unicodedata.normalize('NFKC', intro)# 卡司。D W S C,分别表示 导演,编剧,明星,导演case_dict = {'D': [], 'W': [], 'S': [], 'C': []}for i, tags in enumerate(soup.find_all(class_='credit_summary_item')):for h4 in tags.find_all('h4'):title = h4.get_text()ch = title[0]for _, a in enumerate(h4.next_siblings):if a.name == 'a':case_dict[ch].append(a.get_text())for k, v in case_dict.items():# 去掉多余的信息,只保留关键人名。# 例如Pete Docter (original story by) | 6 more credits »。我们不需要|后面的字符if v and (v[-1].find('credit') != -1 or v[-1].find('full cast') != -1):case_dict[k] = case_dict[k][:-1]# 有时候导演名会用Creator代替if 'C' in case_dict.keys():case_dict['D'].extend(case_dict['C'])# id,电影名称,海报链接,时长,类型,发行时间,简介,导演,编剧,演员detail = [self.cur_movie_id, name, poster_url, info[0], '|'.join(info[1:-1]),info[-1], intro,'|'.join(case_dict['D']), '|'.join(case_dict['W']), '|'.join(case_dict['S'])]self.save_info(detail)def save_poster(self, movie_id, content):with open(f'{self.poster_save_path}/{movie_id}.jpg', 'wb') as fb:fb.write(content)def save_info(self, detail):# 存储到CSV文件中with open(f'{self.info_save_path}', 'a+', encoding='utf-8', newline='') as fb:writer = csv.writer(fb)writer.writerow(detail)def run(self):# 开始爬取信息# 先读入文件self.get_white_lst()self.get_movie_id()for movie_id, imdb_id in self.movie_dct.items():if movie_id in self.white_lst:continueself.cur_movie_id = movie_idself.cur_imdb_id = imdb_id# 休眠,防止被封IP,大概3秒处理完一部电影的信息,如果注释掉,会减少大约2.5小时的运行时间# IMDB好像没有反爬机制,可以放心的注释掉time.sleep(1)response = self.get_url_response(self.url + 'tt' + self.cur_imdb_id)# 找不到电影详情页的url,或者超时,则仅仅保留id,之后再用另一个脚本处理if response == None:self.save_info([self.cur_movie_id, '' * 9])# 仍然更新白名单,避免重复爬取这些失败的电影self.update_white_lst(self.cur_movie_id)# 更新黑名单,爬完之后用另一个脚本再处理self.update_black_lst(self.cur_movie_id, '1')continue# 处理电影详情信息self.process_html(response.content)# 处理完成,增加movie id到白名单中self.update_white_lst(self.cur_movie_id)logging.info(f'process movie {self.cur_movie_id} success')if __name__ == '__main__':s = Model()s.run()

运行时间

一部电影爬取大概要3~5秒的时间,因为中间额外的保存海报,所以会花1到2s的时间,写日志、写文件也需要一些时间。
最快时间: 9700 ∗ 3 / 3600 ≈ 8 h 9700*3/3600 \approx 8h 97003/36008h 所以最好放到云服务器上面跑。如果你会多进程加速的话也可以试着改进一下(顺便贴在评论教我一下😄)

百度网盘链接

ok看到这里,如果你不想花那么多时间自己跑,我提供我运行后的文件和代码,你可以直接使用
下图中的info.csv和poster,分别是电影的详细信息和电影的海报
在这里插入图片描述
海报的命名都是用imdbID来标识的
在这里插入图片描述
链接:https://pan.baidu.com/s/1qByOgO0sisL-lkn1hzsM-g
提取码:nd8b
复制这段内容后打开百度网盘手机App,操作更方便哦


http://chatgpt.dhexx.cn/article/PegMjxg0.shtml

相关文章

数据分析实例:MovieLens电影数据分析

数据分析实例&#xff1a;MovieLens电影数据分析 数据准备 数据集来源&#xff1a;grouplens.org/datasets/movielens/ 下载 ml-1m.zip&#xff0c;read me 中有电影评分介绍 MovieLens 1M电影分级。 稳定的基准数据集。 6000个用户观看4000部电影时获得100万个评分。 发布2…

Spark Hive实现基于协同过滤的电影推荐(MovieLens数据集)

这篇文章记录一下我之前做过的通过Spark与Hive实现的基于协调过滤的电影推荐。这篇文章只能提供算法、思路和过程记录&#xff0c;并没有完整的代码&#xff0c;仅尽量全面地记录过程细节方便参考。 一、数据获取 数据集是从下面这个地址下载的&#xff0c;数据集主要内容是关…

基于用户的协同过滤Movielens电影推荐系统简单实例

基于用户的协同过滤Movielens电影推荐系统简单实例 一、Movielens数据集 1. MovieLens数据集的下载&#xff08;Download&#xff09; 1&#xff09; 从网站下载数据 链接: https://grouplens.org/datasets/movielens/. 有好几种版本&#xff0c;对应不同数据量&#xff0c;…

ML之GB:基于MovieLens电影评分数据集利用基于图的推荐算法(Neo4j图数据库+Cypher查询语言)实现对用户进行Top5电影推荐案例

ML之GB&#xff1a;基于MovieLens电影评分数据集利用基于图的推荐算法(Neo4j图数据库Cypher查询语言)实现对用户进行Top5电影推荐案例 目录 基于MovieLens电影评分数据集利用基于图的推荐算法(Neo4j图数据库Cypher查询语言)实现对用户进行Top5电影推荐案例 1、定义数据集 1.…

从IMDB上爬取MovieLens-1m的补充数据(电影海报和简介)

文章主要内容 本人是想做推荐算法相关的一名在校生&#xff0c;目前想做多模态融合&#xff0c;而MovieLens-1m数据集只有电影信息和用户信息&#xff0c;于是有想法能否在原有的电影推荐公开数据集中而外获取电影海报&#xff08;图片信息&#xff09;和电影简介&#xff08;…

对Movielens数据集进行评分预测

对Movielens数据集进行评分预测 实验源码&#xff1a;lab3代码.ipynb 实验环境&#xff1a;vscode colab 数据解释&#xff1a; movies.dat的数据如下 1::Toy Story (1995)::Animation|Childrens|Comedy 2::Jumanji (1995)::Adventure|Childrens|Fantasy 3::Grumpier Old…

ML之KG:基于MovieLens电影评分数据集利用基于知识图谱的推荐算法(networkx+基于路径相似度的方法)实现对用户进行Top电影推荐案例

ML之KG&#xff1a;基于MovieLens电影评分数据集利用基于知识图谱的推荐算法(networkx基于路径相似度的方法)实现对用户进行Top电影推荐案例 目录 基于MovieLens电影评分数据集利用基于知识图谱的推荐算法(networkx基于路径相似度的方法)实现对用户进行Top电影推荐案例 # 1、定…

利用pandas对MovieLens电影数据分析

掌握pandas基本语法操作「pandas基础入门中有详细语法格式」后&#xff0c;就可以利用pandas做一些简单实例的数据处理。 Movie电影数据分析 首先需要下载电影数据集MovieLens&#xff0c;这个数据集中包含用户数据&#xff1b;电影数据&#xff1b;电影评分表。电影数据中包…

MovieLens数据集处理

有一个定律&#xff0c;对于内容的访问遵循80/20原则&#xff0c;也就是20%的内容&#xff0c;会占有80%的访问量。就是zipf分布[1]。  根据MovieLens的数据集中的ratings.dat&#xff0c;我做了数据处理&#xff0c;获取得分最高的2000个条目。 ml-pro.py import os import …

推荐系统笔记(二):常用数据集Movielens学习

介绍 movielens数据集是电影推荐数据集&#xff0c;数据集有多种大小和目的使用的数据集。按照使用目的可以分为两类&#xff0c;一类数据集适用于推进最新研究的数据&#xff0c;一类数据集是用于高校研究和教育科研使用的数据集。本次介绍三个数据集的使用和处理。 数据集下…

java读取movielens数据txt

各位好&#xff0c;我是菜鸟小明哥&#xff0c;movielens数据是常见的推荐方面的开源数据集&#xff0c;另一个推荐方面的数据集是新闻MIND&#xff0c;本文将从movielens再次出发&#xff0c;做基础的推荐方法&#xff0c;比如基本的基于标题的相似性&#xff0c;word2vector&…

推荐系统数据集之MovieLens

1.概述 MovieLens其实是一个推荐系统和虚拟社区网站&#xff0c;它由美国 Minnesota 大学计算机科学与工程学院的GroupLens项目组创办&#xff0c;是一个非商业性质的、以研究为目的的实验性站点。GroupLens研究组根据MovieLens网站提供的数据制作了MovieLens数据集合&#xff…

【工具】Movielens数据集详细介绍

MovieLens数据集 MovieLens数据集包含多个用户对多部电影的评级数据&#xff0c;也包括电影元数据信息和用户属性信息。 下载地址 http://files.grouplens.org/datasets/movielens/ 介绍 下面以ml-100k数据集为例进行介绍&#xff1a; 最主要用的是u.data(评分) | u.item…

movielens数据集简述

一、movielens数据集 ratings数据: 文件里面的内容包含了每一个用户对于每一部电影的评分。数据格式如下: userId, movieId, rating, timestamp userId: 每个用户的id movieId: 每部电影的id rating: 用户评分,是5星制,按半颗星的规模递增(0.5 stars - 5 stars) timestam…

Movielens数据集详细介绍

MovieLens数据集包含多个用户对多部电影的评级数据&#xff0c;也包括电影元数据信息和用户属性信息。下载地址为&#xff1a;http://files.grouplens.org/datasets/movielens/ 下面以ml-100k数据集为例进行介绍&#xff1a; 最主要用的是u.data(评分) | u.item(电影信息) …

movielens数据集介绍及使用python简单处理

0 前言 个性化推荐中&#xff0c;电影推荐研究时常使用movielens上的数据集。该网站的数据集主要分两部分&#xff0c; 一是用于推进最新研究进展的数据集。当前最新的是发布于2019年12月份的25M数据集。 二是用于高校、组织科研的数据集。该类数据集按其是否带有标签、时间…

mui用ajax上拉加载更多,mui上拉加载更多下拉刷新数据的封装过程

辗转用mui做了两个项目&#xff0c;空下来把mui上拉加载更多&#xff0c;下拉刷新数据做了一个简单的封装&#xff0c;希望可以帮助到需要的朋友 demo项目的结构 直接贴代码了 index.html mui上拉刷新下拉加载都这里了&#xff0c;两个方法搞定mui上拉刷新下拉加载demo--封装 l…

如何实现上拉加载和下拉刷新

下拉刷新和上拉加载这两种交互⽅式通常出现在移动端中 本质上等同于PC⽹⻚中的分⻚&#xff0c;只是交互形式不同 开源社区也有很多优秀的解决⽅案&#xff0c;如 iscroll 、 better-scroll 、 pulltorefresh.js 库等等 这些第三⽅库使⽤起来⾮常便捷 我们通过原⽣的⽅式实现…

ComposeUI——下拉刷新+上拉加载(一、简单封装)

前言&#xff1a;ComposeUI是将来开发的趋势&#xff0c;本人也在对它进行学习&#xff0c;会把踩过的坑一一记录下来&#xff0c;希望能对大家有帮助。话不多说&#xff0c;直接开干。 目录 下拉刷新 1、引入依赖库 2、使用方法 上拉加载 1、先看用法&#xff08;结合下…

Flutter 下拉刷新、上拉加载

Flutter 下拉刷新、上拉加载有很多第三方插件&#xff0c;本文使用插件为&#xff1a;pull_to_refresh 目前pull_to_refresh在pub.dev上的使用情况&#xff1a; 刷新header的类型: ClassicHeader const ClassicHeader({Key? key,RefreshStyle refreshStyle: RefreshStyle.…