爬虫设计之Python

爬虫 设计文档 环境与版本 python 版本:3,8,5 Django 版本:3,0,3 网站已在 Safari,Opera

本文包含相关资料包-----> 点击直达获取<-------

爬虫

设计文档

环境与版本

  1. python 版本:3.8.5
  2. Django 版本:3.0.3
  3. 网站已在 Safari、Opera、Chrome 浏览器中测试兼容

爬虫

爬虫以豆瓣电影为源网站爬取影视、演员和影评数据,共爬到 1066 部影视、5327 条影评以及 6596 位相关演员。

数据与存储

对于每部影视,从豆瓣网中爬取了影视标题、海报图片、影视简介、演员列表、5 条短评以及包括语言、发行时间等在内的其他信息。爬取下来的文字图片分别以 JSON 和 jpg 的格式保存在文件夹中。文件标题为影视的题目。以下文件为例,title、actors、brief、other、comment 分别储存了影视的标题、爬取的相关演员、影视简介、其他信息以及 5 条评论。

json { "title": "2001太空漫游 2001: A Space Odyssey", "actors": [ "凯尔·杜拉", "加里·洛克伍德", "威廉姆·西尔维斯特", "丹尼尔·里希特", "雷纳德·洛塞特", "罗伯特·比提", "肖恩·沙利文", "艾德·毕肖普", "格伦·贝克", "艾伦·吉福德" ], "brief": "\n   这部影片是库布里克花了四年时间制作的充满哲学命题的鸿篇巨制。一块大黑石树立在史前人类的面前,他们刚刚开始认识工具,进入到进化的里程碑。同样的黑石还在宇宙多处出现,它们矗立在月球上,漂浮在太空中,带着某种神秘的寓意。\n \n   现在的时间是2001年,为了寻找黑石的根源,人类开展一项木星登陆计划。飞船上有冬眠的三名宇航员,大卫船长(凯尔·杜拉 Keir Dullea饰)、富兰克飞行员(加里·洛克伍德 Gary Lockwood饰),还有一部叫“HAL9000”的高智能电脑。HAL在宇宙飞行过程中发生错乱,令到富兰克和三名冬眠人员相继丧命,剩下波曼和这台电脑作战。\n \n   从死亡线上回来的大卫一气之下关掉主脑系统,HAL彻底失效。现在,茫茫宇宙中只剩大卫一人,向木星进发。穿越瑰异壮观的星门,大卫仿佛去到一个奇特的时空,那里有人类无尽的生死轮回和宇宙的终极知识……\n ", "other": "\n导演: 斯坦利·库布里克\n编剧: 亚瑟·克拉克 / 斯坦利·库布里克\n主演: 凯尔·杜拉 / 加里·洛克伍德 / 威廉姆·西尔维斯特 / 丹尼尔·里希特 / 雷纳德·洛塞特 / 罗伯特·比提 / 肖恩·沙利文 / 艾德·毕肖普 / 格伦·贝克 / 艾伦·吉福德 / 安·吉利斯\n类型: 科幻 / 惊悚 / 冒险\n制片国家/地区: 英国 / 美国\n语言: 英语 / 俄语\n上映日期: 1968-04-02(华盛顿首映) / 1968-05-12(英国)\n片长: 149分钟\n又名: 2001:星际漫游 / 2001:太空奥德赛\nIMDb链接: tt0062622\n", "comment": [ "原作作者克拉克:“如果有人觉得完全弄懂了《太空漫游2001》在讲些什么,那一定是我和库布里克弄错了。”", "这不是照着剧本拍的,而是曲谱", "现在这个年代没人敢如此玩观众了。\r\n", "牺牲了部分叙事节奏,但构筑起来的完整世界让人目瞪口呆。我觉得我要暴走了:这怎么可能是1968年的电影!!!这怎么可能是1968年的电影!!!它反科学反伦理啊!!!", "史上最伟大的装逼片,就连作者克拉克和导演斯坦利都看不懂剧情……不过这丝毫不影响它的伟大,首先在视觉上它领先了同一时代数十年不止,很多星际旅行片都没有给我一种“星际旅行”的感觉,但这部有,关键就在于细节处理细致。还有就是,这部讲述星际旅行的片子拍摄于1968年,而美国登月则在1969" ] }

从每部电影中选取演员表的前 10 位演员进行爬取,获取演员的姓名、简介及其他信息,并下载页面中的图片,文件名均为演员的姓名。文字信息储存方式如下文件

json { "name": "新垣结衣 Yui Aragaki", "info": "\n\n\n性别: \n 女\n \n\n星座: \n 双子座\n \n\n出生日期: \n 1988-06-11\n \n\n出生地: \n 日本,冲绳县,那霸市\n \n\n职业: \n 演员 / 配音\n \n\n更多外文名: \n 新垣結衣 / あらがき ゆい / ガッキー / Aragaki-Yui (本名) / Yuibo (昵称) / Yui (昵称) / Gakki(昵称) / Gakky (昵称)\n \n\nimdb编号: \n nm2201753\n\n\n官方网站: \n https://www.lespros.co.jp/artists/yui-aragaki/\n\n\n", "brief": "  新垣结衣(1988年6月11日-)是出身于日本冲绳县那霸市的演员、歌手及模特儿,官方身高168厘米,现为日本LesPros Entertainment旗下的艺人。2001年代替姊姊参加当时《Nicola》举办的模特儿比赛,获得最优秀奖。作为杂志模特儿,主要为少年杂志拍摄平面照片。2005年因在电视剧《龙樱》中的演出开始受到关注。2006年出版第一本写真集《水漾青春》。2007年毕业于日出高等学校后专注于演艺圈发展。同年出演电视剧《父女七日变》,发表个人首张音乐专辑《天空》,并参与专辑封面设计与作词。2008年因主演电影《恋空》接连获得电影新人奖。新垣结衣是家中三姊妹中最小的一个,小时候是个很害羞的女孩,到现在还很怕生。中学时参加了一个月的羽毛球俱乐部。虽然是冲绳人,但还是很怕热,腿长80cm。她对自己的称呼一直换,最常用“WATASHI”,但是日记里她喜欢用“BOKU”、“YUIBO”、“YUI”、“ARAGAKI”、“GAKKI”等等(在冲绳和她同龄的人很少用“WATASHI”)。她的昵称“GAKKI”成为“nicomo”后榎本亜弥子给她取的,中学同学叫她 “YUIBO”。很敬佩身边沉着冷静的人,还说自己2006年的目标就是“在心理上长大5岁”。兴趣是卡拉OK,是DA PUMP的FAN。很喜欢漫画,也擅长画画,最擅长的料理是冲绳特色料理“苦瓜炒什锦”,在和小出的约会中就做了这道菜。很喜欢吃冰淇淋,甚至冬天也吃。酷爱牛奶,以至于在吃披萨和拉面的时候都要喝。很讨厌打针,有惧高症,不喜欢灵异鬼怪类的故事。演了很多辣妹角色。在她还是nicomo的时候就有很多FANS喜欢她了,早安少女的新垣里沙和她同年生,但是名字的读法不一样。石田未来和她也是同年生,两人同一个事务所,搬到东京后还一起住。和佐津川爱美,就是辣妹里演SHIZUKA的女生,读同一所学校。在初中的时候,参加了羽毛球队。运动细胞不好,朋友形容她“没办法把手抬到肩膀以上”。" }

爬虫性能

爬虫主要使用 requests 与 BeautifulSoup 来发送请求并解析网页。在获得网页后,通过 BeautifulSoup 定位至需要的信息并记录,最终生成.json 文件;

同时,为了解决网站反爬问题,爬虫中采用了设置 Headers、采用 API 调用 IP 代理池、设置 cookie 等多种方法来绕过反爬机制;

爬虫选取了豆瓣中 https://movie.douban.com/j/search_subjects?type=movie&amp;tag=欧美&amp;sort=recommend&amp;page_limit=500&amp;page_start=0 网页中的电影,并同时对包括华语、豆瓣高分、日本等不同 tag 下的电影进行了爬取;

由于不同电影的所需的爬取量、网速快慢等等因素,爬虫的运行速率(部/秒)无法准确确定,最终估算在 350-400 分钟左右可以爬取完所有的数据

网站

网站采用 Django 架构

数据库模型

网站为演员、影视以及影评分别建立了模型:

```python class Actor(models.Model): name = models.CharField(max_length=20) brief = models.CharField(max_length=150) info = models.CharField(max_length=150) collaborate = models.ManyToManyField(to='self')

def __str__(self):
    return self.name

```

在演员类中,定义了名字、简介、其他信息三个字符串类,和到自身的多对多关系,用以储存不同演员间的合作。

```python class Movie(models.Model): title = models.CharField(max_length=20) brief = models.CharField(max_length=150) other_info = models.CharField(max_length=100) actors = models.ManyToManyField(Actor)

def __str__(self):
    return self.title

```

在电影类中,同样定义了名字、简介、其他信息,并同时定义了电影到演员的多对多关系,来代表这个电影在系统中收录的演员表;同时通过反向查询 actor.moive_set 也可以获得代表演员参演的电影。

```python class Comment(models.Model): content = models.CharField(max_length=100) movie = models.ForeignKey(Movie, on_delete=models.CASCADE)

def __str__(self):
    return self.content

```

在评论类中,定义了内容的字符串类和到电影的多对一关系,用以代表此评论是哪一个电影的;同时反向查询可以获得某个电影的所有影评

搜索与导航栏

网站的搜索功能通过在每个界面导航栏中的搜索框、搜索按钮和选择框实现。当搜索框中填写了字符后,将在选择的对应领域中进行搜索;如果是空的话,将跳转到对应的列表页面(影评的话将在结果页)。

在导航栏的最左边有一个图标,也可以点击,将会转到主页(影视列表页)

列表页面

列表页面包括影视列表以及演员列表,其中影视列表是主页。

网页展示

两种列表以卡片形式展现了所有的影视和演员,并以每页 20 页实现了分页。同时在导航栏最右侧增加按钮,支持影视列表和演员列表之间的切换。

分页的实现利用了 django.core 中的 paginator 以及前端的链接等方法实现。卡片的外观通过 CSS 中的 card 类实现。

python movieList = list(Movie.objects.all()) # 进行分页 pages = Paginator(movieList, 20) current_page = int(request.GET.get('page', default=1)) display_list = pages.get_page(current_page) if current_page > pages.num_pages: current_page = pages.num_pages # get page range,获得分页栏中展示的数字,其他的用省略号省略 page_range = range(max(1, current_page - 2), min(pages.num_pages, current_page + 2) + 1) path_dict = dict() base = '../static/pic/' return render(request, 'main.html', { 'display_list': display_list, 'current_page': current_page, 'total': pages.num_pages, 'movie_total': len(movieList), 'end': pages.num_pages - 3, 'page_range': page_range, })

两个界面的 view 函数分别为 views.py 中的 main_view 和 actor_lists,对应的 HTML 文件分别为 main.html 和 actorlist.html;影视列表的网址为主网站,演员列表的网址为 /actors

影视信息

每个影片都具有自己的详情页,详情页展示了影视的信息,包括海报、基本信息、简介、演员表以及影评等。演员表以卡片的形式展示,可以通过点击名字/图片跳转到该演员的详情页;影评以单独设计的形式展示。

影视页对应的网址为 movie/<int:movie_id> ,影视对应的 id 为其在数据库中的序号。网站通过序号获得对应的数据,传递到前端文件进行展示。对应的 views 函数为 movie_detail ,HTML 文件为 moviewdetail.html

网页展示

海报、标题、其他信息与简介

演员表与影评,可以通过点击演员进入演员详情页

演员信息

每位演员都具有自己的详情页,详情页展示了演员的海报、基本信息、简介、参演电影以及合作演员等。参演电影、合作演员均以卡片的形式展示,可以通过点击名字/图片跳转到该电影/演员的详情页。合作演员选取了 10 个与当前演员合作次数最多的演员,并标注了合作的次数。

影视页对应的网址为 movie/<int:actor_id> ,对应的 id 为其在数据库中的序号。网站通过序号获得对应的数据,传递到前端文件进行展示。对应的 views 函数为 actor_detail ,HTML 源文件为 actordetail.html。

网页展示

照片、姓名、简介

参演电影与合作演员

合作演员的计算方法:首先通过演员反向查询到演员参与的影视列表,再从参演的影视列表中获得所有与该演员合作过的演员;再通过求两个演员参演电影交集的个数来判断他们合作的次数,从而得到与该演员合作次数最多的十个演员。

源代码:

python def getActorsCollaboration(actor): movie_set = set(actor.movie_set.all()) actor_all = set() for movie in movie_set: actors = set(movie.actors.all()) for actor in actors: actor_all.add(actor) dic = dict() for other_actor in actor_all: if other_actor != actor: dic[other_actor] = getCommon(actor, other_actor) dic = sorted(dic.items(), key=lambda d: d[1], reverse=True) return dic[0:10]

搜索结果页面

搜索功能可根据单选框,分别在影视、演员、影评中搜索相关的信息;同时在搜索结果页面支持记录上次的搜索关键字和搜索类型。

搜索结果页面对应的 views 函数为 search ,对应 HTML 文件为 results.html,对应的 url 为 /search

网页展示

通过查询影片名字可以查询到泰坦尼克号

通过查询演员名字也可以查询到泰坦尼克号;电影搜索支持影片名搜索和演员搜索;

演员搜索与影视搜索类似。

影评搜索结果页,可以点击影视下方的来源跳转到相应电影的详情页。

搜索功能的实现

搜索的参数传递和类型选择通过 GET 类型向 search 发送请求,包括三个参数:keyword 关键词、type 查询类型和 pages 页数,默认为 1。

在通过 request.GET 获得参数后,搜索功能实现的主要方法是数据库中的 filter 方法,从数据库中获得包含关键词的演员、影视或影评,再通过 HTML 展示。

搜索部分源码

python if typeSelected == 'movies': if keyword == '': return HttpResponseRedirect(reverse('home')) query = Q(title__contains=keyword) | Q(actors__name__contains=keyword) movie_list = Movie.objects.filter(query).all().distinct() result = list(movie_list) elif typeSelected == 'actors': if keyword == '': return HttpResponseRedirect(reverse('actors')) query = Q(name__contains=keyword) | Q(movie__title__contains=keyword) actor_list = Actor.objects.filter(query).all().distinct() result = list(actor_list) else: comments = list(Comment.objects.filter(content__contains=keyword).all()) result = comments

查询的时间大约在 20ms 左右,主要为将惰性的查询集 QuerySet 转化为 list 所需的时间。

数据导入

在通过爬虫获取数据后,需要将数据导入 Django 的数据库中。为实现这一功能,编写了 initialize.py 文件,用以读取全部 JSON 数据。首先读取 actor 的 JSON 并保存;然后再读取所有的 movie 及其评论,并根据其演员表将影视与演员关联。在导入所有影视后,在开始统计不同演员之间的合作关系,并建立演员到演员自己的 ManyToManyField ,实现合作关系的统计

```python import json, os, sys from engine.models import Actor, Movie, Comment

dirMovies = 'src/movies/json' dirActor = 'src/actors/json' dirTry = 'src/trial/json'

def main(): actors() movie() finishActors() pass

读入演员并保存

def actors(): files = os.listdir(dirActor) for file in files: path = os.path.join(dirActor, file) f = open(path).read() dic = json.loads(f) a = Actor(name=dic['name'], brief=dic['brief'], info=dic['info']) a.save()

读入电影并保存

def movie(): files = os.listdir(dirMovies) for file in files: path = os.path.join(dirMovies, file) f = open(path).read() dic = json.loads(f) q = Movie(title=dic['title'], brief=dic['brief'], other_info=dic['other']) q.save() for actor_name in dic['actors']:#根据演员表建立电影到演员的关系 actor = Actor.objects.filter(name__contains=actor_name) if list(actor). len (): q.actors.add(list(actor)[0]) for comment in dic['comment']:#读取每个电影的评论 c = Comment(content=str(comment), movie=q) c.save()

获取一个演员的合作对象

def getActorsCollaboration(actor): movie_set = set(actor.movie_set.all()) actor_all = set() for movie in movie_set: actors = set(movie.actors.all()) for actor in actors: actor_all.add(actor) dic = dict() for other_actor in actor_all: if other_actor != actor: dic[other_actor] = getCommon(actor, other_actor) dic = sorted(dic.items(), key=lambda d: d[1], reverse=True) return dic[0:10]

根据演员的合作对象建立Actor之间的关系

def finishActors(): for actor in Actor.objects.all(): tmp = getActorsCollaboration(actor) count = 0 for other_actor in tmp: if count == 10: continue if other_actor[0].name != actor.name: count += 1 actor.collaborate.add(other_actor[0])

统计两个演员合作的次数

def getCommon(actor1, actor2): mov_set1 = set(actor1.movie_set.all()) mov_set2 = set(actor2.movie_set.all()) return len(mov_set1 & mov_set2)

```

参考文献

  • 恶意URL检测项目中基于PageRank算法的网络爬虫的设计和实现(北京邮电大学·王晓梅)
  • 主题搜索引擎搜索策略的研究及算法设计(兰州大学·高庆芳)
  • 基于增量反馈和自适应机制的主题爬虫系统的设计与实现(南京理工大学·王斐)
  • 搜索引擎中通用爬虫系统的研究与设计(吉林大学·高龙)
  • 基于Hadoop的分布式网络爬虫的设计与研究(成都理工大学·程泽)
  • 基于Scrapy技术的数据采集系统的设计与实现(南京邮电大学·杨君)
  • 网络爬虫技术在云平台上的研究与实现(电子科技大学·刘小云)
  • 支持AJAX的定址网络爬虫系统的研究与实现(北京邮电大学·刘凡凡)
  • 搜索引擎中网络爬虫技术研究(西安电子科技大学·郭海燕)
  • 主题微博爬虫的设计与实现(中原工学院·王艳阁)
  • 基于标记模板的分布式网络爬虫系统的设计与实现(华中科技大学·杨林)
  • 面向主题的爬行搜索策略研究与实现(陕西师范大学·王敏翔)
  • 主题网络爬虫关键技术研究(哈尔滨工业大学·王桂梅)
  • 主题网络爬虫关键技术研究(哈尔滨工业大学·王桂梅)
  • 基于Hadoop的分布式网络爬虫的设计与研究(成都理工大学·程泽)

本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:源码驿站 ,原文地址:https://bishedaima.com/yuanma/35984.html

相关推荐

发表回复

登录后才能评论