Min.教你远离剧荒(2)

上次我们已经获得了tag标签,现在我打算对标签进行排列组合。
这里仅计算组合结果,不进行排列,计算公式为:

计算出所有tag在不同n情况下的组合,再用这些组合进行反向筛选电影,n越大权重越高,所以对n降序排列。
有些电影的tag数过多,所以决定只取5个tag。

先上代码:

1
2
3
4
5
6
7
8
''' Mingo's movie_recommend script '''
import itertools
def arrange(tag):
for num in range(len(tag), 0, -1):
s = (list(itertools.combinations(tag, num)))
print(s)

这里我用到了itertools模块进行组合运算,itertools.combinations(tag, num)即从tag中取出num个元素进行组合,各组合return一个元组,list返回一个列表。这里range是反向排列的,因为num越大权重越大。输出如下:

得到了标签的组合,现在再观察豆瓣电影标签查找电影的页面:

发现url的规律即:

https://movie.douban.com/tag/

加上:
东野圭吾%20推理%20日本%20福山雅治%20悬疑
其中的%20为空格,再对中文进行编码即可,于是修改代码:

1
2
3
4
5
6
7
8
def arrange(tag):
url_tag = "https://movie.douban.com/tag/"
for num in range(len(tag), 0, -1):
s = (list(itertools.combinations(tag, num)))
#print(s)
for each in s:
url = url_tag + urllib.parse.quote(' '.join(each))
print (url)

输出了通过所有的tag组合查找的网址。

查看输出url的网页源代码,很容易找到了电影名所在位置。

但也有的tag组合可能查找不到电影,则查找不到a class:

查找不到的即跳过,选出查找到的前十部即可。

直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
''' Mingo's movie_recommend script '''
def arrange(tag,url_pre):
url_tag = "https://movie.douban.com/tag/"
all = []
for num in range(len(tag), 0, -1):
s = (list(itertools.combinations(tag, num)))
#print(s)
for each in s:
url = url_tag + urllib.parse.quote(' '.join(each))
html = get_html(url)
end = 0
#print (url)
for i in range(len(re.findall('a class="nbg" href="', html))):
start = html.find('a class="nbg" href="', end) + len('a class="nbg" href="')
end = html.find('" title=', start)
name_start = end + len('" title="')
name_end = html.find('">', name_start)
if html[start:end] != url_pre and not re.findall(html[start:end], ''.join(all)):
all.append(html[name_start:name_end] + "\t" + html[start:end] + "\n")
if len(all) == 10:
return ''.join(all)
#print (html[name_start:name_end] + "\n" + html[start:end])
#print (start,end,name_start,name_end)

这里写的有些繁琐,首先arrange函数传入2个参数,tag为之前的标签,url_pre 为输入电影的地址。创建了一个all的list用于储存数据,url获得了标签组合的网址,利用之前的get_html()函数进行解析。之后在网页中查找地址,这里并没有用到BeautifulSoup,只用了普通的find查找。

1
re.findall('a class="nbg" href="', html)

利用正则表达式查找出html电影的个数,进行循环。
start, end, name_start, name_end为4个数值,代表电影名起止位置及电影url起止位置。

1
2
3
4
if html[start:end] != url_pre and not re.findall(html[start:end], ''.join(all)):
all.append(html[name_start:name_end] + "\t" + html[start:end] + "\n")
if len(all) == 10:
return ''.join(all)

这里进行条件判断,两个条件:(1)要求此刻查找出的电影url与输入的电影url不同,这里就用到了arrange函数中传入的url_pre;(2)要求此刻查找出的电影url与all列表中已添加的电影url不同,以免最终结果中出现相同的电影。满足这两个条件即可将此电影url及名称添加进list。
添加完后再进行条件判断,如果添加个数达到10个则停止循环,直接返回all。

大致如此,让我们测试一下:



噢。。似乎还可以的样子。对输入单部影片来说,似乎就到这里可以了。。

但做单部影片也太没挑战性了,于是我决定在修改一下,在输入多部影片时,依旧能够找出最相近的影片。
首先多部影片就会有多个tag标签,不同影片可能会有相同的标签或不同的标签,所以需要搜集标签进行排序。
所以:

1
2
3
4
5
6
7
8
9
tag_all = {}
def tag_sort(tag,tag_all):
for each in tag:
if each not in tag_all.keys():
tag_all[each] = 1
else:
tag_all[each]+=1
return tag_all

tag_sort()函数传入2个参数,tag为之前得到的标签,tag_all即为我们新创建的dict字典,用来储存tag并进行计数;tag为一个list,for each 遍历tag,进行条件判断:如果这个标签不存在于tag_all的key中,则将此标签添加进去;如果,存在,则将tag_all中此标签的values 加一。遍历完后此函数return一个tag_all字典。

为了配合,我们将主函数也修改了一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if __name__ == "__main__":
name = input("movie name:")
name_list = name.split(',')
tag_all = {}
for name in name_list:
#print (name)
url_pre = "https://movie.douban.com/subject_search?search_text=" + urllib.parse.quote(name)
html = get_html(url_pre)
movie_url = analyse(html)
html_movie = get_html(movie_url)
movie_tag = tag(html_movie)
tag_all = tag_sort(movie_tag,tag_all)
print (tag_all)
#print (arrange(movie_tag, movie_url))

电影名之间以”,”分隔,输出:

看到输出的字典中喜剧,美国,动画的values最大,所以我们对字典进行排列:

1
2
3
4
5
tag_dict = sorted(tag_all.items(), key=lambda x:x[1], reverse=True)
movie_tag = []
for ta in tag_dict[:5]:
movie_tag.append(ta[0])
print (movie_tag)

这里tag_all.items()得到(键,值)的列表,sorted方法,通过key这个参数,reverse=TRUE表示降序。

最后输出:

看来没问题,排列输出正确。
将输出的list再拼接回去,再输出:



okay,就这样完成了!效果似乎还不错。
于是你可以输入各种你喜欢的剧,看看这个小脚本到底给不给力吧!

最后把源代码上传到了github上。
Mingo’s Github

Yumin Huang wechat
快来订阅我的公众号吧-,-
坚持原创分享,来支持一下作者吧~