笔记本安装Linux+Windows10双系统 Python爬虫+数据分析
使用环境:
PyCharm
Windows 10 HOME x64
Python基础 Python 是一门解释型, 面向对象的高级编程语言
开源, 支持交互式, 可跨平台移植的脚本语言
1991年第一个编译器诞生
使用Python3.5以上
PyCharm
基础语法 注释 # 内容
代表注释
多行注释:
1 2 3 4 5 ''' Multiple Line comments '''
变量 不可以用数字开头
标识符和关键字
什么是关键字
python一些具有特殊功能的标示符,这就是所谓的关键字 关键字,是python已经使用的了,所以不允许开发者自己定义和关键字相同的名字的标示符
查看关键字
1 2 >>> import keyword>>> keyword.kwlist
输出
格式化输出
标准输出:
1 2 pirnt("我今年10岁") pirnt("我今年11岁")
格式化输出:
1 2 3 4 5 6 7 age = 10 print ("我今年%d岁" %age)age += 1 print ("我今年%d岁" %age)age = 18 name = "xiaohua" print ("我的姓名是%s,年龄是%d" %(name,age))
%
就是代表格式化操作符,可以在字符串中相当于占位符,之后再赋值
%d
代表digital,有符号的十进制整数
%s
代表字符串, 使用str()
还有很多格式化占位符, 具体可以参考官方文档
输出中也可以插入分隔符
1 print("hello", "world", "end" sep=".")
输入 1 2 password = input ("please enter your password" ) print ("Your just entered:" , password)
判断和循环 判断语句 标准语法:
1 2 3 4 5 6 if : ... elif : ... else : ...
逻辑字符
and
和or
1 if score > 90 and score < 100
1 if score == 90 or score == 80
循环语句 while循环基本语法
1 2 3 4 5 i = 0 while i<5: print("当前是第%d次执行循环"%(i+1)) print("i=%d"%i) i+=1
for循环基础语法
1 2 3 for 临时变量 in 列表或者字符串等: ... 循环满足条件时执行的代码
1 2 3 name = 'chengdu' for x in name: print(x)
1 for i in range(0,100,10)
break
, continue
, pass
break 可以跳出循环
continue跳过当前循环
pass是空语句, 一般用作占用语句, 不做任何是事情
字符串 \
代表转义字符
1 2 3 print ("...'..." )my_str = 'I\'m a student' print (my_str)
三个双引号可以输入段落
1 2 3 4 5 6 7 8 """ this is a paragraph """
字符串的截取和连接 1 2 3 4 5 6 7 8 9 10 11 12 13 str ='chengdu' print (str ) print (str [0 :-1 ]) print (str [0 ]) print (str [2 :5 ]) print (str [2 :]) print (str * 2 ) print (str + '你好' ) print (str [:5 ]) print (str [0 :7 :2 ]) print ('------------------------------' )print ('hello\nchengdu' ) print (r'hello\npython' )
字符串有很多常用方法, 具体参考官方文档
列表 类似其他语言的数组
格式:
1 2 namesList = ['xiaoWang' ,'xiaoZhang' ,'xiaoHua' ] testList = [1 , 'a' ]
打印列表:
1 2 3 4 namesList = ['xiaoWang' ,'xiaoZhang' ,'xiaoHua' ] print (namesList[0 ])print (namesList[1 ])print (namesList[2 ])
常用列表操作
append()
list[2:2:2]
insert(1, 3)
pop()
sort()
reverse()
元组 元组类似列表
但是元组不能修改
1 2 3 4 5 tup1 = (50 ) print (type (tup1)) tup1 = (50 ,) print (type (tup1))
1 2 3 4 tup1 = ('Google' , 'baidu' , 2000 , 2020 ) tup2 = (1 , 2 , 3 , 4 , 5 , 6 , 7 ) print ("tup1[0]: " , tup1[0 ])print ("tup2[1:5]: " , tup2[1 :5 ])
元组中的元素值是不允许修改的,但我们可以对元组进行连接组合
1 2 3 4 5 6 7 tup1 = (12 , 34.56 ) tup2 = ('abc' , 'xyz' ) tup3 = tup1 + tup2 print (tup3)
1 2 3 4 5 tup = ('Google' , 'baidu' , 2000 , 2020 ) print (tup)del tupprint ("删除后的元组 tup : " )print (tup)
字典
1 info = {'name' :'班长' , 'id' :100 , 'sex' :'f' , 'address' :'地球亚洲中国北京' }
1 2 3 4 info = {'name' :'吴彦祖' ,'age' :18 } print (info['age' ]) print (info.get('sex' ))
1 2 3 >>> age = info.get('age' , 18 ) >>> age18
增删改查方法
add()
update()
remove()
get()
keys()
values()
items() —每个键值对是一个元组
for遍历所有键值对
1 2 for key, value in info.items(): print ("key=%s, value=%s" %(key, value))
使用枚举 同时拿到下标和元素内容
1 2 3 myList = ["a" ,"b" ,"c" ,"d" ] for i,x in enumerate (myList): print (i,x)
集合 Set, 类似字典的key值, 不可重复, 无序的
一样拥有差不多的增删改查方法
函数 可以自定义返回值, 和返回值的数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def print_line (): print ("-----------" ) def print_lines (num ): for i in range (0 ,num): print_line() def three_num_sum (a,b,c ): return a+b+c def three_num_avg (a,b,c ): return (three_num_sum(a,b,c))/3
全局变量和局部变量 可以用global
修饰符, 声明全局变量
文件操作 文件的打开和关闭
1 2 f = open ("test.txt" ,"w" ) f.close()
写入数据
读取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 f.read() print (content)print ("-" *30 )content = f.read() print (content)content = f.readlines() print (type (content))i=1 for temp in content: print ("%d:%s" %(i, temp)) i+=1 content = f.readline() print ("1:%s" %content)content = f.readline() print ("2:%s" %content)
文件相关操作
1 2 import osos.rename("毕业论文.txt" , "毕业论文-最终版.txt" )
1 2 import osos.remove("毕业论文.txt" )
1 2 import osos.mkdir("张三" )
1 2 import osos.chdir("../" )
1 2 import osos.listdir("./" )
1 2 import osos.rmdir("张三" )
异常处理 捕获异常 1 2 3 4 5 6 try : print ('-----test--1---' ) open ('123.txt' ,'r' ) print ('-----test--2---' ) except IOError: pass
捕获多个异常
1 2 3 4 5 6 7 8 9 try : print ('-----test--1---' ) open ('123.txt' ,'r' ) print ('-----test--2---' ) print (num) except (IOError,NameError):
捕获所有异常
1 2 3 4 try : ... except (IOError,NameError): ...
try…finally… demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import timetry : f = open ('test.txt' ) try : while True : content = f.readline() if len (content) == 0 : break time.sleep(2 ) print (content) except : pass finally : f.close() print ('关闭文件' ) except : print ("没有这个文件" )
test.txt文件中每一行数据打印,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样 做的原因是让程序运行得慢一些。在程序运行的时候,按Ctrl+c中断(取消)程序。 我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍 然被执行,把文件关闭。
网络爬虫 正片开始^^
任务 实现案例 , 爬取豆瓣电影Top250的基本信息, 包括电影名称, 评分, 评价数量, 电影概况, 电影链接等等
豆瓣Top250电影榜单
基础爬虫知识
爬虫就是按照一定规则, 自动抓取互联网程序或者脚本
可以爬取图片, 视频, 能通过浏览器访问的数据都可以用爬虫获取
爬虫的本质就是模拟浏览器打开网页, 获取我们需要的数据
流程 需要HTML、CSS、JS的基础知识
引入模块 1 2 3 4 5 6 from directory import t1import osimport bs4
此案例需要的模块
1 2 3 4 5 import bs4 import re import urllib.request,urllib.error import xlwt import sqlite3
程序框架准备 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 def main (): baseurl = "https://movie.douban.com/top250?start=" datalist = getData(baseurl) savepath = ".\\豆瓣电影Top250.xls" saveData(savepath) def getData (baseurl ): datalist = [] return datalist def saveData (savepath ): print ("..." ) if __name__ == '__main__' : main()
urllib
库附加内容get请求 1 2 3 4 import urllib.requestresponse = urllib.request.urlopen("http://www.baidu.com" ) print (response.read().decode('utf-8' ))
post请求 http://httpbin.org/
是一个测试http的网站
1 2 3 4 import urllib.parsedata = bytes (urllib.parse.urlencode({"hello" :"world" }),encoding = "utf-8" ) response = urllib.request.urlopen("http://httpbin.org/post" , data) print (response.read().decode('utf-8' ))
可以对请求加上超时时间
1 2 3 4 5 try : response = urllib.request.urlopen("http://httpbin.org/get" , timeout = 0.01 ) print (response.read().decode('utf-8' )) except urllib.error.URLError as e: print ("time out!!" )
response 里面还包含很多信息
修改请求头 1 2 3 4 5 6 7 8 9 10 url = "http://httpbin.org/post" data = bytes (urllib.parse.urlencode({'name' :'eric' }),encoding = "utf-8" ) headers = { "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36" } req = urllib.request.Request(url=url, data=data, headers=headers, method="POST" ) response = urllib.request.urlopen(req) print (response.read().decode("utf-8" ))
试着访问豆瓣 1 2 3 4 5 6 7 url = "http://www.douban.com" headers = { "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36" } req = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(req) print (response.read().decode("utf-8" ))
获取数据 对网页进行访问并获取页面信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def askURL (url ): headers = { "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36" } req = urllib.request.Request(url=url, headers=headers) html = "" try : response = urllib.request.urlopen(req) html = response.read().decode('utf-8' ) except urllib.error.URLError as e: if hasattr (e,"code" ): print (e.code) if hasattr (e, "reason" ): print (e.reason) return html
用for循环分别获取10页信息 1 2 3 4 5 baseurl = "https://movie.douban.com/top250?start=" ... for i in range (0 , 10 ): url = baseurl + str (i*25 ) html = askURL(url)
Beautiful Soup 补充内容 Beautiful Soup 4 将复杂的文档转换成树形结构, 每个节点都是python对象, 所有对象可以归纳为一下四种:
Tag - 标签
NavigableString - 标签里的内容
BeautifulSoup - 整个文档
Comment - 注释
1 2 3 4 5 6 7 print (bs.title)print (bs.a)print (bs.title.string)print (bs.a.attrs)print (bs.name)print (bs.a.string)
文档遍历 1 print (bs.head.contents[1 ])
文档搜索 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 t_list = bs.findAll("a" ) t_list = bs.findAll(re.compile ("a" )) def name_is_exists (tag ): return tag.has_attr("name" ) t_list = bs.find_all(name_is_exists) t_list = bs.find_all(id ="head" ) t_list = bs.find_all(class_=True ) t_list = bs.find_all(text = "hao123" ) t_list = bs.find_all("a" ,limit=3 )
css选择器 1 2 3 4 5 6 7 8 9 10 t_list = bs.select('title' ) t_list = bs.select('#head' ) t_list = bs.select("a[class='bri']" ) t_list = bs.select("head > title" ) t_list = bs.select(".mnav ~ .bri" )
re正则表达式补充
操作符
说明
.
表示任何单个字符
[]
字符集, 对单个字符给出取值范围
[^ ]
排除范围
*
0或者多个
+
1个或者多个
?
0或者1
|
左右表达式任意一个
{m}
表示m次
{m,n}
m到n次
^
开头
$
结尾
()
分组
\d
数字
\w
字符, 数字和字母
贪婪匹配 默认情况下,正则表达式使用最长匹配原则(也叫贪婪匹配原则)。 例如:要将”zoom”中匹配”zo?”的部 分替换成”r”,替换的的结果是”rom”。如果要将”zoom”中匹配”zo*” 的部分替换成”r”,替换后的结果是”rm”。
非贪婪匹配 当字符?紧随其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式变成了最短匹配原则(也 叫非贪婪匹配原则)。 例如:在字符串”fooood”中,”fo+?”只匹配”fo”部分,而”fo+”匹配”foooo部分。
正则表达式语法
re库
search
match()
findall()
split()
finditer()
sub()
还有一些修饰符
re.l
re.L
re.M
re.S
re.U
re.X
使用 1 2 pat = re.compile ("AA" ) m = pat.search("CAAA" )
1 print (re.findall("a" ,"ASDaDFGAa" ))
用第二个参数替换第一个参数
1 print (re.sub("a" ,"A" ,"abcdaaacga" ))
正则表达式提取 提取链接 1 2 3 findLink = re.compile (r'<a href="(.*?)">' ) link = re.findall(findLink, item)[0 ] data.append(link)
用类似逻辑提取所有需要的元素 对应正则: 1 2 3 4 5 6 7 findLink = re.compile (r'<a href="(.*?)">' ) findImgSrc = re.compile (r'<img alt=".*src="(.*?)"' , re.S) findTitle = re.compile (r'<span class="title">(.*?)</span>' ) findRating = re.compile (r'<span class="rating_num" property="v:average">(.*?)</span>' ) findJudge = re.compile (r'<span>(\d*)人评价</span>' ) findInq = re.compile (r'<span class="inq">(.*?)</span>' ) findBd = re.compile (r'<p class="">(.*?)</p>' , re.S)
提取: 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 for item in soup.find_all('div' , class_="item" ): data = [] item = str (item) data.append(findElement(findLink, item)) data.append(findElement(findImgSrc, item)) titles = re.findall(findTitle, item) if (len (titles)==2 ): ctitle = titles[0 ] data.append(ctitle) otitle = titles[1 ].replace("/" , "" ) data.append(otitle) else : data.append(titles[0 ]) data.append(' ' ) data.append(findElement(findRating, item)) data.append(findElement(findJudge, item)) inq = re.findall(findInq, item) if (len (inq) != 0 ): inq = inq[0 ].replace("。" , "" ) data.append(inq) else : data.append(" " ) bd = findElement(findBd, item) bd = re.sub('<br(\s+)?/>(\s+)?' , " " , bd) bd = re.sub('/' , " " , bd) data.append(bd.strip()) datalist.append(data)
保存到Excel表格 使用xlwt库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def saveData (datalist,savepath ): book = xlwt.Workbook(encoding='utf-8' ) sheet = book.add_sheet('豆瓣电影Top250' ,cell_overwrite_ok=True ) col = ("电影详情链接" , "图片链接" ,"影片中文名" ,"影片外文名" ,"评分" ,"评价数" ,"概况" ,"相关信息" ) for i in range (0 ,8 ): sheet.write(0 ,i,col[i]) for i in range (0 ,250 ): print ("第%d条" %(i+1 )) data = datalist[i] for j in range (0 ,8 ): sheet.write(i+1 ,j,data[j]) book.save(savepath) print ("End" )
到此为止, excel表格的保存方式结束
SQLite补充 建表非常简单:
1 2 3 4 5 import sqlite3conn = sqlite3.connect("test.db" ) print ("Opened database successfully" )c = conn.cursor()
建表语句
1 2 3 4 5 6 7 8 9 10 11 12 sql = ''' create table company (id int primary key not null, name text not null, age int not null, address char(50), salary real); ''' cursor.execute(sql) conn.commit() conn.close()
查询数据
1 2 3 4 5 6 7 8 9 10 11 12 sql = ''' select * from company ''' c.execute(sql) for row in c: print ("id = " , row[0 ]) print ("name = " ,row[1 ]) print ("address = " ,row[2 ]) print ("salary = " ,row[3 ]) conn.close() print ("Create table correctly" )
SQLite实践 首先也是建表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def init_db (dbpath ): sql = ''' create table movie250 ( id integer primary key autoincrement, info_link text, pic_link text, cname varchar, ename varchar, score numeric, rated numeric, introduction text, info text ) ''' conn = sqlite3.connect(dbpath) cursor = conn.cursor() cursor.execute(sql) conn.commit() conn.close()
然后将数据遍历并插入进数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def saveData2DB (datalist, dbpath ): conn = sqlite3.connect(dbpath) cursor = conn.cursor() for data in datalist: for index in range (len (data)): data[index] = '"' +data[index]+'"' sql = ''' insert into movie250( info_link, pic_link, cname, ename, score, rated, introduction, info) values (%s) ''' %"," .join(data) cursor.execute(sql) conn.commit() conn.close()
数据可视化 Flask入门 Flask是一个Web框架 , Python中最出名的是Django框架, 因为其内容非常全面
Flask的核心是路由转发和页面渲染, Werkzeug和Jinja2
Flask基础 Helloworld
1 2 3 @app.route('/' ) def hello_world (): return 'Hello World!'
1 2 3 @app.route('/user/<name>' ) def welcome (name ): return 'Hello World!' +name
1 2 3 @app.route('/user/<int:id>' ) def welcome2 (id ): return 'Hello World!' + id
使用jinja2渲染并返回文件
1 2 3 4 @app.route("/" ) def index (): return render_template("index.html" )
渲染同时可以传递参数到页面,
1 2 time = datetime.date.today() return render_template("index.html" , var=time)
1 <h1 > Welcome {{ var }}</h1 >
传递列表参数的时候又特定语法
1 2 3 name = ["校长" , "小王" , "小赵" ] task = {"任务" :"打扫卫生" ,"时间" :"3小时" } return render_template("index.html" , var=time, list =name, task=task)
显示列表参数
1 2 3 {% for data in list %} <li>{{ data }}</li> {% endfor %}
显示字典参数
1 2 3 4 5 6 7 8 9 任务: <br > <table > {% for key, value in task.items() %} <tr > <td > {{ key }}</td > <td > {{ value }}</td > </tr > {% endfor %} </table >
类似还有if语法
处理表单 flask 里面还自带了request
from flask import Flask, render_template, request
引入
1 2 3 4 5 6 7 8 9 10 11 12 13 @app.route("/test/register" ) def register (): return render_template("test/register.html" ) @app.route("/result" , methods=['POST' ,'GET' ] ) def result (): if request.method =='POST' : result = request.form return render_template("test/result.html" ,result=result) else : print ("GET" )
前端表单页面
1 2 3 4 5 6 7 8 <form action ="http://localhost:5000/result" method ="post" > <p > 姓名: <input type ="text" name ="name" > </p > <p > 年龄: <input type ="text" name ="age" > </p > <p > 性别: <input type ="text" name ="gender" > </p > <p > 地址: <input type ="text" name ="address" > </p > <p > <input type ="submit" value ="submit" > </p > </form >
注意此处也可以使用{{url_for('result')}}
代替来获取根路由的路径
路由通过post请求接受到表单数据以后跳转到result页面 并解析数据
1 2 3 4 5 6 7 8 <table > {% for key, value in result.items() %} <tr > <td > {{ key }}</td > <td > {{ value }}</td > </tr > {% endfor %} </table >
首页制作 实战
新创建一个Flask项目
从模板网站导入一个模板, 并分别放到templates和static文件夹下
使用render_template
设置路由
对静态html页面进行修改, 改成只留下我们所需要的内容
修改静态html内的文字内容
使用类似方式创建movie.html来使数据库中的数据可视化为表格
Movie表格可视化 路由设置, 从数据库中取出数据
1 2 3 4 5 6 7 8 9 10 11 12 13 @app.route('/movie' ) def movie_page (): datalist = [] con = sqlite3.connect("movie.db" ) cur = con.cursor() sql = "select * from movie250" data = cur.execute(sql) for item in data: datalist.append(item) cur.close() con.close() return render_template("movie.html" , movies=datalist)
然后再前端页面中建一个表格
1 2 3 4 5 6 7 8 9 10 11 12 13 <table class ="table table-striped" > <tr > <th > 排名</th > <th > 电影中文名</th > <th > 电影外文名</th > <th > 电影评分</th > <th > 评价人数</th > <th > 一句话概述</th > <th > 其他信息</th > </tr > </table >
获取数据显示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {% for movie in movies %} <tr > <td > {{ movie[0] }}</td > <td > <a href ="{{ movie[1] }}" > {{ movie[3] }} </a > </td > <td > {{ movie[4] }}</td > <td > {{ movie[5] }}</td > <td > {{ movie[6] }}</td > <td > {{ movie[7] }}</td > <td > {{ movie[8] }}</td > </tr > {% endfor %}
Echarts应用 官方中文网址: http://www.echartsjs.com/zh/index.html
新版网址: https://echarts.apache.org/
示例:
引入文件
从官方网站拷贝提供的示例源码
使用
新建score.html显示页面,
编写路由查询处理需要渲染的数据
前端解析
路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @app.route('/score' ) def score_page (): score = [] score_count = [] con = sqlite3.connect('movie.db' ) cur = con.cursor() sql = "select score, count(score) from movie250 group by score" data = cur.execute(sql) for item in data: print (item) score.append(item[0 ]) score_count.append(item[1 ]) cur.close() con.close() return render_template("score.html" , score=score, score_count=score_count)
前端解析
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 <script type ="text/javascript" > var dom = document .getElementById("main" ); var myChart = echarts.init(dom); var app = {}; option = null ; option = { color : ['#3398DB' ], tooltip : { trigger : 'axis' , axisPointer : { type : 'shadow' } }, grid : { top : '4%' , bottom : '3%' , containLabel : true }, xAxis : { type : 'category' , data : {{ score }} }, yAxis : { type : 'value' }, series : [{ data : {{ score_count }}, barWidth : '60%' , type : 'bar' }] }; ; if (option && typeof option === "object" ) { myChart.setOption(option, true ); } </script >
WordCloud应用 使用中文词云需要使用jieba
, matplotlib
, wordcloud
库
wordcloud 安装不成功的话需要到官方网址去: https://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud
1 2 3 4 5 6 import jieba from matplotlib import pyplot as plt from wordcloud import WordCloud from PIL import Image import numpy as np import sqlite3
从数据库中获取
分词
设置词云配置
生成词云
显示解析词云图片
数据库获取
1 2 3 4 5 6 7 8 9 10 con = sqlite3.connect('../movie.db' ) cur = con.cursor() sql = 'select introduction from movie250' data = cur.execute(sql) text = "" for item in data: text = text + item[0 ] cur.close() con.close()
分词
1 2 3 4 cut = jieba.cut(text) str = ' ' .join(cut)
使用图片轮廓设置词云
1 2 3 4 5 6 7 8 img = Image.open (r'../static/assets/img/tree.jpg' ) img_array = np.array(img) wc = WordCloud( background_color='white' , mask=img_array, font_path="msyh.ttc" )
生成词云图片
1 2 3 4 5 6 7 wc.generate_from_text(str ) fig = plt.figure(1 ) plt.imshow(wc) plt.axis('off' ) plt.show()
或者生成图片为文件
1 2 plt.savefig(r'../static/assets/img/word.jpg' , dpi=500 )
将图片放到页面中 直接更改原本模板中word.html中的图片路径即可, 然后删除多余的元素
—End—