有網(wǎng)友在 Quora 上提問,「你用 Python 寫過最牛逼的程序/腳本是什么?」。本文摘編了3 個國外程序員的多個小項目,含代碼。
Manoj Memana Jayakumar, 3000+ 頂
更新:憑借這些腳本,我找到了工作!可看我在這個帖子中的回復,《Has anyone got a job through Quora? Or somehow made lots of money through Quora?》
1. 電影/電視劇 字幕一鍵下載器
我們經常會遇到這樣的情景,就是打開字幕網(wǎng)站subscene 或者opensubtitles, 搜索電影或電視劇的名字,然后選擇正確的抓取器,下載字幕文件,解壓,剪切并粘貼到電影所在的文件夾,并且需把字幕文件重命名以匹配電影文件的名字。是不是覺得太無趣呢?對了,我之前寫了一個腳本,用來下載正確的電影或電視劇字幕文件,并且存儲到與電影文件所在位置。所有的操作步驟僅需一鍵就可以完成。懵逼了嗎?
請看這個 Youtube 視頻:https://youtu.be/Q5YWEqgw9X8
源代碼存放在GitHub:subtitle-downloader
更新:目前,該腳本支持多個字幕文件同時下載。步驟:按住 Ctrl ,選擇你想要為其下載字幕的多個文件 , 最后執(zhí)行腳本即可
2. IMDb 查詢/電子表格生成器
我是一個電影迷,喜歡看電影。我總是會為該看哪一部電影而困惑,因為我搜集了大量的電影。所以,我應該如何做才能消除這種困惑,選擇一部今晚看的電影?沒錯,就是IMDb。我打開http://imdb.com,輸入電影的名字,看排名,閱讀和評論,找出一部值得看的電影。
但是,我有太多電影了。誰會想要在搜索框輸入所有的電影的名字呢? 我肯定不會這樣做,尤其是我相信“如果某些東西是重復性的,那么它應該是可以自動化的”。因此,我寫了一個 python 腳本, 目的是為了使用 非官方的 IMDb API 來獲取數(shù)據(jù)。我選擇一個電影文件(文件夾),點擊右鍵,選擇‘發(fā)送到’,然后 點擊 IMDB.cmd (順便提一下,IMDB.cmd 這個文件就是我寫的 python 腳本),就是這樣。
我的瀏覽器會打開這部電影在IMDb網(wǎng)站上的準確頁面。
僅僅只需點擊一個按鍵,就可以完成如上操作。如果你不能夠了解這個腳本到底有多酷,以及它可以為你節(jié)省多少時間,請看這個 Youtube視頻:https://youtu.be/JANNcimQGyk
從現(xiàn)在開始,你再也不需要打開你的瀏覽器,等待加載IMDb的頁面,鍵入電影的名字。這個腳本會幫你完成所有的操作。跟往常一樣,源代碼放在了GitHub:imdb,并且附有操作說明。當然,由于這個腳本必須去掉文件或文件夾中的無意義的字符,比如“DVDRip, YIFY, BRrip”等,所以在運行腳本的時候會有一定比例的錯誤。但是經過測試,這個腳本在我?guī)缀跛械碾娪拔募隙歼\行的很好。
2014-04-01更新:
許多人在問我是否可以寫一個腳本,可以發(fā)現(xiàn)一個文件夾中所有電影的詳細信息,因為每一次只能發(fā)現(xiàn)一個電影的詳細信息是非常麻煩的。我已經更新了這個腳本,支持處理整個文件夾。腳本會分析這個文件夾里的所有子文件夾,從 IMDb上抓取所有電影的詳細信息 ,然后打開一個電子表格,根據(jù)IMDb 上的排名,從高到低降序排列所有的電影。這個表格中包含了 (所有電影)在 IMDb URL, 年份,情節(jié),分類,獲獎信息,演員信息,以及其他的你可能在 IMBb找到的信息。下面是腳本執(zhí)行后,生成的表格范例:
Your very own personal IMDb database! What more can a movie buff ask for? ;)Source on GitHub:imdb
你也可以有一個個人IMDb數(shù)據(jù)庫!一個電影愛好者還能夠要求更多嗎?:)
源代碼在GitHub:imdb
3. theoatmeal.com 連載漫畫下載器
我個人超級喜歡 Matthew Inman 的漫畫。它們在瘋狂搞笑的同時,卻又發(fā)人深省。但是,我很厭煩重復點擊下一個,然后才能閱讀每一個漫畫。另外,由于每一個漫畫都由多福圖片組成,所以手動下載這些漫畫是非常困難的。
基于如上原因,我寫了一個 python 腳本 ,用來從這個站點下載所有的漫畫。這個腳本利用 BeautifulSoup (http://www.crummy.com/software/B…) 解析 HTML 數(shù)據(jù), 所以在運行腳本前,必須安裝 BeautifulSoup。 用于下載燕麥片(馬修.英曼的一部漫畫作品)的下載器已經上傳到GitHub:theoatmeal.com-downloader 。(漫畫)下載完后的文件夾是這樣的 :D
4.someecards.com 下載器
成功地從http://www.theoatmeal.com下載了整部漫畫后,我在想是否我可以做同樣的事情 , 從另一個我喜歡的站點— 搞笑的,唯一的http://www.someecards.com. 下載一些東西呢?
somececards 的問題是,圖片命名是完全隨機的,所有圖片的排放沒有特定的順序,并且一共有52 個大的類別, 每一個類別都有數(shù)以千計的圖片。
我知道,如果我的腳本是多線程的話,那將是非常完美的,因為有大量的數(shù)據(jù)需要解析和下載,因此我給每一個類別中的每一頁都分配一個線程。這個腳本會從網(wǎng)站的每一個單獨的分類下載搞笑的電子賀卡,并且把每一個放到單獨的文件夾。現(xiàn)在,我擁有這個星球上最好笑的電子賀卡私人收藏。下載完成后,我的文件夾是這樣的:
沒錯,我的私人收藏總共包括:52個類別,5036個電子賀卡。 源代碼在這里:someecards.com-downloader
編輯:很多人問我是否可以共享我下載的所有文件,(在這里,我要說)由于我的網(wǎng)絡不太穩(wěn)定,我沒辦法把我的收藏上傳到網(wǎng)絡硬盤,但是我已經上傳一個種子文件,你們可以在這里下載:somecards.com Site Rip torrent
種下種子,傳播愛:)
Akshit Khurana,4400+ 頂
感謝500多個朋友在Facebook上為我送出的生日祝福
有三個故事讓我的21歲生日變的難忘,這是最后一個故事。我傾向于在每一條祝福下親自評論,但是使用 python 來做更好。
…
1.# Thanking everyone who wished me on my birthday
2.importrequests
3.importjson
4.
5.# Aman's post time
6.AFTER = 1353233754
7.TOKEN = ''
8.
9.defget_posts():
10. """Returns dictionary of id, first names of people who posted on my wall
11. between start and end time"""
12. query = ("SELECT post_id, actor_id, message FROM stream WHERE "
13. "filter_key = 'others' AND source_id = me() AND "
14. "created_time > 1353233754 LIMIT 200")
15.
16. payload = {'q': query,'access_token': TOKEN}
17. r = requests.get('https://graph.facebook.com/fql',params=payload)
18. result = json.loads(r.text)
19. returnresult['data']
20.
21.defcommentall(wallposts):
22. """Comments thank you on all posts"""
23. #TODO convert to batch request later
24. forwallpost inwallposts:
25.
26. r = requests.get('https://graph.facebook.com/%s' %
27. wallpost['actor_id'])
28. url = 'https://graph.facebook.com/%s/comments' % wallpost['post_id']
29. user = json.loads(r.text)
30. message = 'Thanks %s :)' % user['first_name']
31. payload = {'access_token': TOKEN,'message': message}
32. s = requests.post(url,data=payload)
33.
34. print"Wall post %s done" % wallpost['post_id']
35.
36.if__name__ == '__main__':
37. commentall(get_posts())
…
為了能夠順利運行腳本,你需要從Graph API Explorer(需適當權限)獲得 token。 本腳本假設特定時間戳之后的所有帖子都是生日祝福。
盡管對評論功能做了一點改變,我仍然喜歡每一個帖子。
當我的點贊數(shù),評論數(shù)以及評論結構在 ticker(Facebook一項功能,朋友可以看到另一個朋友在做什么,比如點贊,聽歌,看電影等) 中爆漲后,我的一個朋友很快發(fā)現(xiàn)此事必有蹊蹺。
盡管這個不是我最滿意的腳本,但是它簡單,快捷,有趣。
當我和Sandesh Agrawal在網(wǎng)絡實驗室討論時,有了寫這個腳本的想法。 為此,Sandesh Agrawal耽擱了實驗室作業(yè),深表感謝。
Tanmay Kulshrestha,3300+ 頂
好了,在我失去這個項目之前(一個豬一樣的朋友格式化了我的硬盤,我的所有代碼都在那個硬盤上)或者說,在我忘記這些代碼之前,我決定來回答這個問題。
整理照片
當我對圖像處理感興趣之后,我一直致力于研究機器學習。我寫這個有趣的腳本,目的是為了分類圖片,很像 Facebook 做的那樣(當然這是一個不夠精確的算法)。 我使用了 OpenCV 的人臉檢測算法,“haarcascade_frontalface_default.xml”,它可以從一張照片中檢測到人臉。
你可能已經察覺到這張照片的某些地方被錯誤地識別為人臉。 我試圖通過修改一些參數(shù)(來修正這一問題),但還是某些地方被錯誤地識別為人臉,這是由相機的相對距離導致的。我會在下一階段解決這一問題(訓練步驟)。
這個訓練算法需要一些訓練素材,每個人需要至少需要100-120個訓練素材(當然多多益善)。 我太懶了,并沒有為每一個人挑選照片,并把它們復制粘帖到訓練文件夾。所以,你可能已經猜到,這個腳本會打開一個圖片,識別人臉,并顯示每一個人臉(腳本會根據(jù)處于當前節(jié)點的訓練素材給每一個人臉預測一個名字)。伴隨著每次你標記的照片,Recognizer 會被更新,并且還會包含上一次的訓練素材。 在訓練過程中,你可以增加新的名字。我使用 python 庫 tkinter 做了一個 GUI。 因此,大多數(shù)時候,你必須初始化一小部分照片(給照片中的人臉命名),其他的工作都可以交給訓練算法。 因此,我訓練了 Recognizer ,然后讓它(Recognizer)去處理所有的圖片。
我使用圖片中包含的人的人名來命名圖片,(例如: Tanmay&*****&*****)。 因此,我可以遍歷整個文件夾,然后可以通過輸入人名的方法來搜索圖片。
初始狀態(tài)下,當一個人臉還沒有訓練素材時(素材庫中還沒有包括這個人臉的名字),需要詢問他/她的名字。
我可以增加一個名字,像這個樣子:
當訓練了幾個素材后,它會像這個樣子:
最后一個是針對應對那些垃圾隨機方塊而使用的變通解決方案。
帶名字的最終文件夾。
所以,現(xiàn)在尋找圖片變得相當簡單。順便提一下,很抱歉(我)放大了這些照片。
…
importcv2
importsys
importos,random,string
#choices=['Add a name']
importos
current_directory=os.path.dirname(os.path.abspath(__file__))
fromTkinterimportTk
fromeasygui import *
importnumpy asnp
x= os.listdir(current_directory)
new_x=[]
testing=[]
foriinx:
ifi.find('.')==-1:
new_x+=[i]
else:
testing+=[i]
x=new_x
g=x
choices=['Add a name']+x
y= range(1,len(x)+1)
defget_images_and_labels():
globalcurrent_directory,x,y,g
ifx==[]:
return(False,False)
image_paths=[]
foriing:
path=current_directory+''+i
forfilename inos.listdir(path):
final_path=path+''+filename
image_paths+=[final_path]
# images will contains face images
images = []
# labels will contains the label that is assigned to the image
labels = []
forimage_path inimage_paths:
# Read the image and convert to grayscale
img = cv2.imread(image_path,0)
# Convert the image format into numpy array
image = np.array(img,'uint8')
# Get the label of the image
backslash=image_path.rindex('')
underscore=image_path.index('_',backslash)
nbr = image_path[backslash+1:underscore]
t=g.index(nbr)
nbr=y[t]
# If face is detected, append the face to images and the label to labels
images.append(image)
labels.append(nbr)
#cv2.imshow("Adding faces to traning set...", image)
#cv2.waitKey(50)
# return the images list and labels list
returnimages,labels
# Perform the tranining
deftrain_recognizer():
recognizer = cv2.createLBPHFaceRecognizer()
images,labels = get_images_and_labels()
ifimages==False:
returnFalse
cv2.destroyAllWindows()
recognizer.train(images,np.array(labels))
returnrecognizer
defget_name(image_path,recognizer):
globalx,choices
#if recognizer=='':
# recognizer=train_recognizer()
cascadePath = "haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)
#recognizer=train_recognizer()
x1=testing
globalg
printimage_path
image = cv2.imread(image_path)
img = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
predict_image = np.array(img,'uint8')
faces = faceCascade.detectMultiScale(
img,
scaleFactor=1.3,
minNeighbors=5,
minSize=(30,30),
flags = http://cv2.cv.CV_HAAR_SCALE_IMAGE
)
for(x,y,w,h)infaces:
f= image[y:y+w,x:x+h]
cv2.imwrite('temp.jpg',f)
im='temp.jpg'
nbr_predicted,conf = recognizer.predict(predict_image[y: y + h,x: x + w])
predicted_name=g[nbr_predicted-1]
print"{} is Correctly Recognized with confidence {}".format(predicted_name,conf)
ifconf>=140:
continue
msg='Is this '+predicted_name
reply = buttonbox(msg,image=im,choices=['Yes','No'])
ifreply=='Yes':
reply=predicted_name
directory=current_directory+''+reply
ifnotos.path.exists(directory):
os.makedirs(directory)
random_name=''.join(random.choice(string.ascii_uppercase + string.digits)for_inrange(7))
path=directory+''+random_name+'.jpg'
cv2.imwrite(path,f)
else:
msg = "Who is this?"
reply = buttonbox(msg,image=im,choices=choices)
ifreply == 'Add a name':
name=enterbox(msg='Enter the name',title='Training',strip=True)
printname
choices+=[name]
reply=name
directory=current_directory+''+reply
ifnotos.path.exists(directory):
os.makedirs(directory)
random_name=''.join(random.choice(string.ascii_uppercase + string.digits)for_inrange(7))
path=directory+''+random_name+'.jpg'
printpath
cv2.imwrite(path,f)
# calculate window position
root = Tk()
pos = int(root.winfo_screenwidth() * 0.5),int(root.winfo_screenheight() * 0.2)
root.withdraw()
WindowPosition = "+%d+%d" % pos
# patch rootWindowPosition
rootWindowPosition = WindowPosition
defdetect_faces(img):
globalchoices,current_directory
imagePath = img
faceCascade = cv2.CascadeClassifier(cascPath)
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.3,
minNeighbors=5,
minSize=(30,30),
flags = http://cv2.cv.CV_HAAR_SCALE_IMAGE
)
print"Found {0} faces!".format(len(faces))
m=0
for(x,y,w,h)infaces:
m+=1
padding=0
f= image[y-padding:y+w+padding,x-padding:x+h+padding]
cv2.imwrite('temp.jpg',f)
im='temp.jpg'
msg = "Who is this?"
reply = buttonbox(msg,image=im,choices=choices)
ifreply == 'Add a name':
name=enterbox(msg='Enter the name',title='Training',strip=True)
printname
choices+=[name]
reply=name
directory=current_directory+''+reply
ifnotos.path.exists(directory):
os.makedirs(directory)
random_name=''.join(random.choice(string.ascii_uppercase + string.digits)for_inrange(7))
path=directory+''+random_name+'.jpg'
printpath
cv2.imwrite(path,f)
defnew(img,recognizer):
imagePath = current_directory+''+img
printimagePath
get_name(imagePath,recognizer)
cascPath = 'haarcascade_frontalface_default.xml'
b=0
os.system("change_name.py")
forfilename inos.listdir("."):
b+=1
ifb%10==0orb==1:
os.system("change_name.py")
recognizer=train_recognizer()
iffilename.endswith('.jpg')orfilename.endswith('.png'):
printfilename
imagePath=filename
#detect_faces(imagePath)
new(imagePath,recognizer)
os.remove(filename)
raw_input('Done with this photograph')
…
我想進一步修改它的搜索功能,其中會包含更多的搜索類型,比如基于地理位置,微笑的臉,傷心的臉等等。(這樣我就可以在 Skylawns 上 搜索快樂的 Tanmay & 沮喪的 Akshay & 快樂的…)
我還寫了很多腳本,但那都是很久之前的事情了,我也懶得再去檢查這些代碼了,我會列出部分代碼。
GitHub 鏈接:tanmay2893/Image-Sorting
Gmail 郵件通知
在那段時間,我沒有智能手機。 導致我常常錯過來自于我所在的研究所的郵件(在我的研究所的郵件 ID),我寫了一個腳本,可以在我的筆記本上運行,而且能給我的手機發(fā)信息。我使用 python 的 IMAP 庫來獲取郵件。我可以輸入一些重要的人的名字,這樣一來,當這些人給我發(fā)了郵件后,我可以收到短信通知。對于短信, 我使用了way2sms.com(寫了一個 python 腳本,自動登陸我的賬戶,然后發(fā)送 短信)。
PNR(Passenger Name Record旅客訂座記錄,下同)狀態(tài)短訊
鐵路方面不經常發(fā)送 PNR 狀態(tài)消息。因此,我寫了一個腳本,可以從印度鐵路網(wǎng)站獲取 PNR 狀態(tài)。這是非常容易的,因為那個網(wǎng)站沒有驗證碼,即使有,也只是形同虛設的驗證碼(在過去,一些字母會被寫在看起來像圖片一樣的東西上面,因為他們?yōu)檫@些字母使用了一個 “check” 的背景圖)。 我們可以輕松地從 HTML 網(wǎng)頁得到這些字母。我不明白他們這樣做的目的是什么,難道僅僅是為了愚弄他們自己嗎? 不管怎么樣,我使用短信息腳本來處理它,經過一段時間間隔,它會在我的筆記本上運行一次,就像是一個定時任務,只要 PNR 狀態(tài)有更新,它就會把更新信息發(fā)送給我。
YouTube 視頻下載器
這個腳本會從 Youtube 頁面下載所有的 Youtube 視頻 以及他們所有的字幕文件(從Download and save subtitles下載)。為了使下載速度更快一點,我使用了多線程。還有一個功能是,即使你的電腦重啟了,仍然可以暫停和恢復播放下載的(視頻)。我原本想做一個UI的,但是我太懶了… 一旦我的下載任務完成,我就不去關心 UI 的事情了。
板球比分通知器
我猜想這個功能已經在別的地方提到過了。一個窗口通知器。(在右下角的通知區(qū)域,它會告訴你實時比分以及評論信息)。如果你愿意的化,在某些時間段,你也可以關掉它。
WhatsApp 消息
這個并不太實用,我只是寫著玩玩。因為 Whatsapp 有網(wǎng)頁版,我使用 selenium 和 Python 下載我的所有聯(lián)系人的顯示圖片,并且,一旦有人更新了他們的顯示圖片,我將會知道。(如何做到的?非常簡單,在設定好時間間隔后,我會一遍又一遍的不停下載所有的頭像信息,一旦照片的尺寸發(fā)生變化,我將會知道他/她更新了顯示圖片)。然后我會給他/她發(fā)一個信息,不錯的頭像。我僅僅使用了一次來測試它的可用性。
Nalanda 下載器
我們一般在這個叫 ‘Nalanda’ 的網(wǎng)站上下載一些教學課件以及其他的課程資料, ‘Nalanda’ 在 BITS Pilani (Nalanda). 我自己懶得在考試前一天下載所有的課件,所以,我寫了這個這個下載器,它可以把每一門科的課件下載到相應的文件夾。
代碼:
…
importmechanize,os,urllib2,urllib,requests,getpass,time
start_time = time.time()
frombs4 importBeautifulSoup
br=mechanize.Browser()
br.open('https://nalanda.bits-pilani.ac.in/login/index.php')
br.select_form(nr=0)
name=''
whilename=='':
try:
print'*******'
username=raw_input('Enter Your Nalanda Username: ')
password=getpass.getpass('Password: ')
br.form['username']=username
br.form['password']=password
res=br.submit()
response=res.read()
soup=BeautifulSoup(response)
name=str(soup.find('div',attrs={'class':'logininfo'}).a.string)[:-2]
except:
print'Wrong Password'
f=open('details.txt','w')
f.write(username+'n'+password)
f.close()
print'Welcome, '+name
print'All the files will be downloaded in your Drive C in a folder named "nalanda"'
#print soup.prettify()
div=soup.find_all('div',attrs={'class':'box coursebox'})
l=len(div)
a=[]
foriinrange(l):
d=div[i]
s=str(d.div.h2.a.string)
s=s[:s.find('(')]
c=(s,str(d.div.h2.a['href']))
path='c:nalanda'+c[0]
ifnotos.path.exists(path):
os.makedirs(path)
a+=[c]
#print a
overall=[]
foriinrange(l):
response=br.open(a[i][1])
page=response.read()
soup=BeautifulSoup(page)
li=soup.find_all('li',attrs={'class':'section main clearfix'})
x=len(li)
t=[]
folder=a[i][0]
print'Downloading '+folder+' files...'
o=[]
forjinrange(x):
g=li[j].ul
#print g
#raw_input('')
ifg!=None:
temp=http://g.li['class'].split(' ')
#raw_input('')
iftemp[1]=='resource':
#print 'yes'
#print '********************'
o+=[j]
h=li[j].find('div',attrs={'class':'content'})
s=str(h.h3.string)
path='c:nalanda'+folder
ifpath[-1]==' ':
path=path[:-1]
path+=''+s
ifnotos.path.exists(path):
os.makedirs(path)
f=g.find_all('li')
r=len(f)
z=[]
foreinrange(r):
p=f[e].div.div.a
q=f[e].find('span',attrs={'class':'resourcelinkdetails'}).contents
link=str(p['href'])
text=str(p.find('span').contents[0])
typ=''
ifstr(q[0]).find('word')!=-1:
typ='.docx'
elifstr(q[0]).find('JPEG')!=-1:
typ='.jpg'
else:
typ='.pdf'
iftyp!='.docx':
res=br.open(link)
soup=BeautifulSoup(res.read())
iftyp=='.jpg':
di=soup.find('div',attrs={'class':'resourcecontent resourceimg'})
link=di.img['src']
else:
di=soup.find('div',attrs={'class':'resourcecontent resourcepdf'})
link=di.object['data']
try:
ifnotos.path.exists(path+''+text+typ):
br.retrieve(link,path+''+text+typ)[0]
except:
print'Connectivity Issues'
z+=[(link,text,typ)]
t+=[(s,z)]
ift==[]:
print'No Documents in this subject'
overall+=[o]
#raw_input('Press any button to resume')
#print overall
print'Time Taken to Download: '+str(time.time()-start_time)+ ' seconds'
print'Do you think you can download all files faster than this :P'
print'Closing in 10 seconds'
time.sleep(10)
…
我自己的 DC++
這個腳本并不是很有用,目前只有一些學生在用它, 況且,DC ++ 已經提供了一些很酷的功能。我原本可以優(yōu)化我自己的版本,但是,由于我們已經有了DC ++,我并沒有這么做,盡管我已經使用 nodeJS 和 python 寫了一個基礎版本。
工作原理:
打開 DC++ , 進入一個中心站點,然后連接,我寫了一個 python 腳本來做這件事。 腳本會在 PC上創(chuàng)建一個服務器(可以通過修改 SimpleHTTPRequestHandler 來完成)。
在服務器端(使用了NodeJS),它會拿到 PC 的連接,共享給其他的用戶。
這個是主頁面:
這個頁面顯示了所有的用戶和他們的鏈接。因為我給 Nick 加了一個超鏈接,所以在鏈接這一攔是空的。
所以,當用戶數(shù)量增加以后,這個頁面會列出所有的用戶列表。基本上,這個頁面充當了一個你和另外一個人聯(lián)系的中間人角色。 我還做了一個在所有用戶中搜索特定文件的功能。
這里是客戶端的 python 文件(這是一段很長的代碼,我上傳到了 Ideone)
所有這些代碼僅僅用于教育目的。
-
python
+關注
關注
56文章
4797瀏覽量
84692 -
腳本
+關注
關注
1文章
389瀏覽量
14866
原文標題:你用 Python 寫過哪些牛逼的程序/腳本?
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論