当前位置:   article > 正文

基于协同过滤算法的电影资源个性化推荐系统设计与实现_基于协同过滤推荐算法的电影推荐系统的设计与实践论文

基于协同过滤推荐算法的电影推荐系统的设计与实践论文

目录

摘要 I
Abstract II
1.绪论 4
1.1课题背景及意义 4
1.2国内外研究现状 5
1.3论文内容结构 5
2.协同过滤与相关技术 6
2.1推荐算法介绍 6
2.1.1基于内容的推荐算法 6
2.1.2协同过滤算法 7
2.1.3协同过滤算法分类 7
2.1.4协同过滤优化 8
2.1.5协同过滤推荐的优缺点 9
2.1.6应用场景 10
2.2相关技术介绍 11
3.系统分析与设计 13
3.1需求分析 13
3.2系统设计 14
3.2.1微信公众号 15
3.2.2接口定义 16
3.2.3前后端交互接口 18
3.2.4文本请求 19
3.2.5事件处理 19
3.2.6web 服务器 20
3.3数据库设计 22
3.3.1电影信息表 22
3.3.2其他表结构 22
3.4推荐算法设计 24
4.系统实现 26
4.1数据采集 26
4.1.1爬虫概要 26
4.1.2数据库结构 29
4.1.3爬虫主要逻辑 30
4.1.4页面分析 31
4.1.5数据处理 32
4.2基础功能实现 33
4.2.1后端主要逻辑 33
4.2.2搜索功能 38
4.2.3评价功能 41
4.3协同过滤推荐实现 43
4.3.1读取用户曲线 43
4.3.2用户相似程度 44
4.3.3获得最终结果 45
4.4解决冷启动问题 47
4.4.1解决方案 47
4.4.2代码实现 47
4.4.3其他完善方案 48
5.实验结果分析 49
5.1推荐功能测试 49
5.1.1协同过滤推荐 49
5.1.2基于内容推荐 50
5.2推荐功能优化 52
5.2.1重复推荐 52
5.2.2响应时间 52
5.2.3避免冷启动 52
5.3评价功能优化 53
5.3.1影片名纠纷 53
5.3.2鼓励评分 53
5.4其他辅助功能 54
5.4.1功能说明书 54
5.4.2收藏夹 54
结论 55
参考文献 56
致谢 57

3.系统分析与设计
3.1需求分析
本文将利用上一章中介绍的技术搭建一个电影资源个性化推荐系统。本系统对用户提供一个微信公众号,微信用户对公众号添加关注后就能享受到电影个性化推荐服务。
在用户使用推荐系统时,会用到几个功能:
(1)个性化推荐功能:这是用户所需要的服务,也是推荐系统的必要功能。
(2)评价功能:用户可以对看过的电影进行一个评价,这份数据将作为推荐算法做抉择的依据。
(3)搜索功能:一个基本的功能,能让用户准确搜索出电影的详细信息。除了上述的必要功能,用户可能还会用到一些其他的扩展功能:
(1)说明书:怎么与公众号进行交互,让系统进行相关的操作,把这个写成说明书给用户看。
(2)收藏夹:用户对于喜欢的电影可以添加到收藏夹,以免忘记。
在使用该系统时,用户可以主动向公众号发出一些命令,然后公众号完成相应的功能,可能还需要返回结果内容。
推荐功能可以将内容主动推荐给用户,也可以在用户使用系统时显示出推荐结果, 也可以让用户主动寻求推荐。由于本系统使用微信公众号,功能有限,所以使用的方法是用户主动寻求推荐,当用户发送“推荐”二字给系统时,系统做出推荐结果返回给用户。
评价功能可以在用户购买商品后进行评价,或者在观看电影后对电影进行评价,但
是由于本系统没有购物系统,只是简单的推荐系统,所以这个功能也是用户主动评价, 用户可以对电影进行一个 0-10 分的评价。系统将记录这个评分,用来作为个性推荐的依据。
搜索功能则比较简单,用户直接发送电影名,系统将电影详细信息返回给用户。其他功能对推荐系统的作用不是很大,本文没有做出具体实现。

3.2系统设计
首先需要准备工作环境,工作环境非常简单,一台电脑作为后台,一个微信公众号作为前端。电脑需要拥有公网 IP,这样微信公众号才能接入到自己编写的后台程序, 最好的选择就是购买一个云服务器,配置不需要高。在本系统中使用安装了 CentOS 操作系统的云服务器,微信公众号使用微信申请个人微信公众号。

2.2 相关技术介绍
在本文的推荐系统搭建在安装 linux 操作系统的云服务器(Elastic Compute Service
简称 ECS)上。除了核心的推荐算法,还需要以下技术支持:
(1)python:一门被广泛应用的编程语言,有很多不同功能的第三方库可以使用。调用这些第三方库,简单的 python 代码可以实现强大的功能:网页爬虫、神经网络、、图像识别、文章分词及关键字提取、网站后台等等。本系统中使用 python 作为主要开发语言,使用python 爬取源数据,并使用python 编写后台逻辑、与数据库交互等。
(2)MySQL:一个免费的关系数据库软件,当拥有大量记录,并且记录与记录之间有复杂的联系时,把这些信息直接存到文件系统是不适合的,存到非关系数据库又体现不出记录之间的复杂关系,本文转载自http://www.biyezuopin.vip/onews.asp?id=14846比较好的选择就是使用 MySQL,
MySQL 是关系数据库中比较流行的一个。在本系统中使用 MySQL 数据库存储电影资源的信息、用户的信息、用户的行为信息。
(3)微信公众号:作为一个 C/S 架构的服务,开发一个客户端软件所需要的时间太长,使用 HTML 开发一个网站前端也需要写大量代码,由于本系统对前端界面需求不大,为了节省时间,本文使用腾讯公司的微信公众号作为后台接入点,将微信聊天界面当成用户界面使用,这样避免了编写前端代码,用户也可以使用微信轻松的访问系统。
(4)Web.py:一个使用 python 语言的轻量级网站后台框架,使用这个框架可以简单的实现网站后台,与微信公众号对接,作为公众号的后台,提供用户数据采集功能和推荐计算服务。
除了上述的主要技术,在系统实现阶段还会用到一些其他技术,例如:使用 pythond 的第三方库requests 下载 HTML 页面内容、使用Xpath 语法解析 HTML 页面内容、使用 pymysql 库操作 MySQL 等等。

#!/bin/python
#-*- coding: utf-8 -*-
import web
import hashlib
import lxml
import time
import os
import random
import pymysql

import reply
import receive

urls = (
	'/', 'Main',
)
class Main(object):
	def GET(self):
		try:
			data = web.input()
			if len(data) == 0:
				return "hello, this is handle view"
			signature = data.signature
			timestamp = data.timestamp
			nonce = data.nonce
			echostr = data.echostr
			token = "HelloChj" #按照公众平台官网\基本配置中信息填写

			list = [token, timestamp, nonce]
			list.sort()
			sha1 = hashlib.sha1()
			map(sha1.update, list)
			hashcode = sha1.hexdigest()
			print "handle/GET func: hashcode, signature: ", hashcode, signature
			if hashcode == signature:
				return echostr
			else:
				return ""
		except Exception, Argument:
			return Argument
	def update_user_info(self, user_name):
		self.db = pymysql.connect(host='localhost', port=3306, user='root', password='186386', db='douban', charset='utf8')
		self.cursor = self.db.cursor()
		cmd = 'select * from user_info where wx_id = "{}";'.format(user_name)
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		if len(results) == 0:
			cmd = 'insert into user_info(wx_id, start_time) values("{}", "{}");'.format(user_name, int(time.time()))
			try:
				self.cursor.execute(cmd)
				self.db.commit()
			except:
				self.db.rollback()
	def parse_cmd(self, recv_content):
		recv_msg_buf = recv_content.split(' ')#格式标准化
		recv_msg = []
		for buf in recv_msg_buf:
			if buf != "":
				recv_msg.append(buf.strip())
		return recv_msg
	def evaluate(self, user_name, recv_msg):
		content = ""
		movie_name = recv_msg[1]
		#可能需要处理
		nice = float(recv_msg[2])
		if nice > 10:
			nice = 10
		elif nice < 0:
			nice = 0
		cmd = 'select id from user_info where wx_id = "{}";'.format(user_name)#记录到数据库
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		user_id = results[0][0]
		cmd = 'select id from douban_movie where title = "{}";'.format(movie_name)
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		if len(results) == 0:
			content = "抱歉,电影名输入有误,请重新输入。"
		else:

			for row in results:
				movie_id = row[0]
				cmd = 'select liking from like_movie where user_id={} and movie_id={};'.format(user_id, movie_id)
				self.cursor.execute(cmd)
				results = self.cursor.fetchall()
				if len(results) == 0:
					cmd = 'insert into like_movie(user_id, movie_id, liking) values({}, {}, {});'.format(user_id, movie_id, nice)
					try:
						self.cursor.execute(cmd)
						self.db.commit()
						content = '评价成功,感谢您的支持。{}:{}分'.format(movie_name, nice)
					except:
						self.db.rollback()
						content	= '评价失败,请重新输入。{}:{}分'.format(movie_name, nice)
				else:
					cmd = 'update like_movie set liking={} where user_id={} and movie_id={};'.format(nice, user_id, movie_id)
					try:
						self.cursor.execute(cmd)
						self.db.commit()
						content = '更新评分成功。{}:{}分'.format(movie_name, nice)
					except:
						self.db.rollback()
						content	= '评价失败,请重新输入。{}:{}分'.format(movie_name, nice)
		return content
	def recommend(self, user_name, recv_msg):
		content = ""
		cmd = 'select id from user_info where wx_id="{}";'.format(user_name)
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		if len(results) != 1:
			return content
		user_id = results[0][0]
		cmd = 'select * from like_movie where user_id={};'.format(user_id)
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		line = {}
		if len(results):
			for row in results:
				movie_id = row[1]
				score = row[2] if row[2] != None else -1
				line[movie_id] = score
		
		cmd = 'select id from user_info where wx_id<>"{}";'.format(user_name)
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		areas = {}
		for other_user in results:#遍历每一个用户
			cmd = 'select * from like_movie where user_id={};'.format(other_user[0])
			self.cursor.execute(cmd)
			results = self.cursor.fetchall()
			line_other = {}
			if len(results):
				for row in results:
					movie_id = row[1]
					score = row[2] if row[2] != None else -1
					line_other[movie_id] = score
			tup = self.compute(line, line_other)
			areas[other_user[0]] = tup
		neighbor_id = -1
		for (key, val) in areas.items():
			if val[0] == -1:
				del areas[key]
			elif neighbor_id == -1 and val[1] != 0:#首次赋值
				neighbor_id = key
			elif neighbor_id != -1 and val[1] != 0 and val[0] < areas[neighbor_id][0]:#更新
				neighbor_id = key
		print areas
		if neighbor_id == -1:
			return self.will(line)
			#return "抱歉,由于您的评价次数过少,系统暂时推算不出您的兴趣爱好。\n请多多评价,过段时间再试。"
		cmd = 'select * from like_movie where user_id={};'.format(neighbor_id)
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		movies_id = []
		for row in results:
			if not line.has_key(row[1]):
				movies_id.append(row[1])
		if not len(movies_id):
			return self.will(line)
			#return "抱歉,由于您的评价次数过少,系统暂时推算不出您的兴趣爱好。\n请多多评价,过段时间再试。"
		for mov_id in movies_id:
			cmd = 'select * from douban_movie where id={};'.format(mov_id)
			self.cursor.execute(cmd)
			result = self.cursor.fetchone()
			title = result[1].encode("utf-8") if result[1] != None else ""
			score = result[2] if result[2] != None else 0
			num = result[3] if result[3] != None else 0
			link = result[4].encode("utf-8") if result[4] != None else ""
			date_time = result[5] if result[5] != None else ""
			address = result[6].encode("utf-8") if result[6] != None else ""
			other_address = result[7].encode("utf-8") if result[7] != None else ""
			actors = result[8].encode("utf-8") if result[8] != None else ""
			if score:
				content += '{}\n{}\n{}\n{}\n{}\n评价人数:{}\n评分:{}\n{}\n\n'.format(title, date_time, address, other_address, actors, num, score, link)
			else:
				content += '{}\n{}\n{}\n{}\n{}\n评价人数:{}\n{}\n\n'.format(title, date_time, address, other_address, actors, num, link)
		return content
	def compute(self, line, line_other):
		area=0.0
		common = dict.fromkeys([x for x in line if x in line_other])
		common_num = len(common)
		x = len(line) - common_num
		y = len(line_other) - common_num
		if 0 == common_num:
			area = -1
		else:
			for key in common:
				area += (line[key] - line_other[key])**2
			area = (area*x)/(common_num**2)
		return (area, y)#area越小越相近,-1为无交集,y为可推荐的数量
	def will(self, line):
		cmd = 'select count(id) from douban_movie;'
		self.cursor.execute(cmd)
		result = self.cursor.fetchone()
		movie_sum = result[0]
		movie_sum -= 100
		rand = random.randint(0, movie_sum)
		cmd = 'select * from douban_movie limit {},100;'.format(rand)
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		max_score_addr = 0
		max_score = 0.0
		index = 0
		for row in results:
			if row[2] != None and row[2] > max_score and not line.has_key(row[0]):
				max_score_addr = index
				max_score = row[2]
			index += 1
		title = results[max_score_addr][1].encode("utf-8") if results[max_score_addr][1] != None else ""
		score = results[max_score_addr][2] if results[max_score_addr][2] != None else 0
		num = results[max_score_addr][3] if results[max_score_addr][3] != None else 0
		link = results[max_score_addr][4].encode("utf-8") if results[max_score_addr][4] != None else ""
		date_time = results[max_score_addr][5] if results[max_score_addr][5] != None else ""
		address = results[max_score_addr][6].encode("utf-8") if results[max_score_addr][6] != None else ""
		other_address = results[max_score_addr][7].encode("utf-8") if results[max_score_addr][7] != None else ""
		actors = results[max_score_addr][8].encode("utf-8") if results[max_score_addr][8] != None else ""
		content = '{}\n{}\n{}\n{}\n{}\n评价人数:{}\n评分:{}\n{}\n为提高您的推荐质量,请您多使用评价功能。另外,您评价过的电影不会再次推荐给您。\n'.format(title, date_time, address, other_address, actors, num, score, link)
		return content
	def search(self, user_name, recv_msg):
		return self.browse(user_name, recv_msg[1:])
	def browse(self, user_name, recv_msg):
		movie_name = recv_msg[0]
		content = ""
		cmd = 'select * from douban_movie where title like "{}";'.format(movie_name)#精准查找
		self.cursor.execute(cmd)
		results = self.cursor.fetchall()
		#print 'select "{}" have results num:{}.'.format(movie_name, len(results))
		if len(results):
			for row in results:
				title = row[1].encode("utf-8") if row[1] != None else ""
				score = row[2] if row[2] != None else 0
				num = row[3] if row[3] != None else 0
				link = row[4].encode("utf-8") if row[4] != None else ""
				date_time = row[5] if row[5] != None else ""
				address = row[6].encode("utf-8") if row[6] != None else ""
				other_address = row[7].encode("utf-8") if row[7] != None else ""
				actors = row[8].encode("utf-8") if row[8] != None else ""
				if score:
					content += '{}\n{}\n{}\n{}\n{}\n评价人数:{}\n评分:{}\n{}\n\n'.format(title, date_time, address, other_address, actors, num, score, link)
				else:
					content += '{}\n{}\n{}\n{}\n{}\n评价人数:{}\n{}\n\n'.format(title, date_time, address, other_address, actors, num, link)
			cmd = 'select id from user_info where wx_id = "{}";'.format(user_name)#更新查找记录
			self.cursor.execute(cmd)
			results = self.cursor.fetchall()
			user_id = results[0][0]
			cmd = 'select id from douban_movie where title = "{}";'.format(movie_name)
			self.cursor.execute(cmd)
			results = self.cursor.fetchall()
			for row in results:
				movie_id = row[0]
				cmd = 'insert into seek_movie(user_id, movie_id, seek_time) values({}, {}, {})'.format(user_id, movie_id, int(time.time()))
				try:
					self.cursor.execute(cmd)
					self.db.commit()
				except:
					self.db.rollback()
		else:#模糊查找
			cmd = 'select * from douban_movie where title like "%{}%" limit 5;'.format(movie_name)
			self.cursor.execute(cmd)
			results = self.cursor.fetchall()
			print 'like "{}" have results num:{}.'.format(movie_name, len(results))
			if len(results) == 0:
				content = "抱歉,暂时没有收录该影片。"#找不到
			else:
				content = "您在找的可能是:\n"#模糊匹配到
				for row in results:
					title = row[1].encode("utf-8") if row[1] != None else ""
					score = row[2] if row[2] != None else 0
					num = row[3] if row[3] != None else 0
					link = row[4].encode("utf-8") if row[4] != None else ""
					date_time = row[5] if row[5] != None else ""
					address = row[6].encode("utf-8") if row[6] != None else ""
					other_address = row[7].encode("utf-8") if row[7] != None else ""
					actors = row[8].encode("utf-8") if row[8] != None else ""
					content += '{}\n{}\n{}\n{}\n{}\n评价人数:{}\n评分:{}\n{}\n\n'.format(title, date_time, address, other_address, actors, num, score, link)
		return content

	def on_text(self, recMsg):
		content = ""
		user_name = recMsg.FromUserName
		recv_content = recMsg.Content
		self.update_user_info(user_name)#检查用户是否存在,不存在则创建
		
		recv_msg = self.parse_cmd(recv_content)#解析收到的命令
		exe_cmd = recv_msg[0]
		content = ""
		if exe_cmd == '评价':
			content = self.evaluate(user_name, recv_msg)
		elif exe_cmd == '推荐':
			content = self.recommend(user_name, recv_msg)
		elif exe_cmd == '搜索':
			content = self.search(user_name, recv_msg)
		elif exe_cmd == '怎么用':
			content = "您可以发送以下内容给我:\n搜索 无问西东\n评价 秦时明月 8.9\n推荐\n怎么用"
		else:
			content = self.browse(user_name, recv_msg)
		self.db.close()
		return content

	def on_image(self, recMsg):
		content = "感谢您的图片,但是我暂时不能识别图片。。。"
		return content

	def on_event(self, recMsg):
		#print recMsg.Event
		content = ""
		if recMsg.Event == "subscribe":
			db = pymysql.connect(host='localhost', port=3306, user='root', password='186386', db='douban', charset='utf8')
			cursor = db.cursor()
			cmd = 'select * from user_info where wx_id = "{}";'.format(recMsg.FromUserName)
			cursor.execute(cmd)
			results = cursor.fetchall()
			if len(results) == 0:
				cmd = 'insert into user_info(wx_id, start_time) values("{}", "{}");'.format(recMsg.FromUserName, int(time.time()))
				try:
					cursor.execute(cmd)
					db.commit()
				except:
					db.rollback()
			db.close()
			content = "感谢您的关注与支持,评价电影超过一定次数后,本平台将为您提供个性化推荐服务。您可以发送以下内容给我:\n搜索 无问西东\n评价 秦时明月 8.9\n推荐\n怎么用"
			return content
		elif recMsg.Event == "unsubscribe":
			return content
		else:
			return content

	def POST(self):
		try:
			webData = web.data()
			#print webData
			content = ""
			recMsg = receive.parse_xml(webData)
			toUser = recMsg.FromUserName
			fromUser = recMsg.ToUserName
			if isinstance(recMsg, receive.Msg) and recMsg.MsgType == 'text':#主要业务逻辑
				content = self.on_text(recMsg)
			elif isinstance(recMsg, receive.Msg) and recMsg.MsgType == 'image':
				content = self.on_image(recMsg)
			elif isinstance(recMsg, receive.Msg) and recMsg.MsgType == 'event':
				content = self.on_event(recMsg)
			else:
				print "暂不支持"
				return "success"

			if content == "":
				return "success"
			replyMsg = reply.TextMsg(toUser, fromUser, content)
			data = replyMsg.send()
			return data
		except Exception, Argment:
			print "fail, but I pretend to be success."
			return "success"

if __name__ == '__main__':
	app = web.application(urls, globals())
	app.run()

  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/645918
推荐阅读
相关标签
  

闽ICP备14008679号