赞
踩
暑假在家,精神状态一直不是很好,闲来无事,便学起了python。借助这一平台,想谈谈自己在学习中的心得与困惑,也算是记录暑期生活的一种方式。从6月底开始自学python爬虫,到今天断断续续学习了一个多月,期间看网上视频教程,翻各种帖子博客,收获颇多。可能是有点matlab的基础,学习中上手很快,期间爬过视频网站、淘宝、京东、百度图片、QQ好友空间图片、堆糖图片、政府网站获取文本信息等等,也写过小游戏,玩过数据库。后续如果有时间,会将自己写的代码整理好,分享在这里,以供交流学习。
曾在知乎上看到一句话,原话为“师兄说:‘matlab除了不能生孩子,其他什么都能实现’”。额,学了一个多月python后给我的感觉是,python不仅什么都能做,而且能生孩子,而且还能生一堆。。当然这里不是黑matlab,只是说它的适用范围不如python广泛。好了,废话不多说,进入今天的主题python爬虫视频网站。
所说的视频网站是一部影院,这个网站提供很多vip视频资源,可免费在线观看。该网站的视频源有很多,例如:iqiyi,youku,mgtv,acfun,papapa(一开始这个视频源我也不知道是什么,翻了源码才知道是pptvyun)等等。
以电影摔跤吧爸爸为例http://www.yibuyy.com/play/37751-0-0.html打开网站源代码
可见有papapa和mgtv两个资源,后面都跟着字符串。mgtv$$第1集$http://www.mgtv.com/b/314894/4000292.html$mgtv$,其实中间就是芒果TV的播放地址;papapa中间夹的字符串,先不管papapa中间是什么,统一叫url_id吧,后面方便称呼。
打开审查元素,进行抓包分析,可在other中找到一个get请求,Request Url是:
http://sapi.goudaitv.com/youkuyun/url.php?xml=http://www.mgtv.com/b/314894/4000292.html&type=mgtv&hd=cq&wap=0&siteuser=123&lg=
此Request Url是可以拼凑出来:“网站名(据经验来看,网站名经常变动,任意一个都行,比如我在程序中使用的是http://api.goudaitv.com/youkuyun/url.php?xml,但是会影响其Preview的网页布局,使用正则时需要改变参数) + url_id &type=视频源”*,后面的参数可以省略。
然后,查看此get请求的Preview,在video里发现一个https链接:
https://disp.titan.mgtv.com/vod.do?fmt=4&pno=1121&fid=D37570B18EB50AF1EDC92A3A24A07248&file=/c1/2017/07/04_0/D37570B18EB50AF1EDC92A3A24A07248_20170704_1_1_776.mp4,这便就是视频的绝对地址。好了,只要把视频的真实地址找到,就可以放心大胆的在python中用urllib.request.urlretrieve去下载了。问题在于,直接访问这个get请求,会出错,也就是说访问缺少参数,所以将Referer和User-Agent作为头部信息提交。
看到这儿,我们做一个大胆的假设,既然芒果视频在一部影院中的url_id是其本身的播放链接,是不是所有芒果视频的链接(包含vip)都可以这种方法解析?答案是可以的。下面动手来操作,首先进入mgtv随便找到一个视频链接,以异星觉醒为例,以下提供代码:
import requests
import re
#mgtv的异星觉醒链接
mgtv_link = 'http://www.mgtv.com/b/311566/4010142.html'
#拼凑出get请求的url
url = 'http://api.goudaitv.com/youkuyun/url.php?xml=%s&type=mgtv'%(mgtv_link)
#添加头部信息
headers = {'Referer':'http://api.goudaitv.com/youkuyun/ckplayer/ckplayer.swf',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
#访问get请求
r = requests.get(url, timeout = 30, headers = headers)
print(r.text)
#正则匹配视频的绝对地址
parse = re.findall(r'CDATA(.*?)]', r.text)
print('\n视频的绝对地址是:%s'%parse[1][1:])
程序运行结果:
看!视频的绝对地址解析出来了,只要在程序中换掉mgtv的视频链接,就可以想解析啥就解析啥了。
至此,初步解析怎么获得视频的绝对地址。但是没有考虑视频分段的情况,本文编写的程序只提供mgtv和papapa资源的下载,其它资源大多分段,暂时只提供观看。这里吐槽一下,一部影院的papapa资源源代码设计混乱,网页源码存在问题。下面提供python代码,剖析视频爬虫结合GUI展现出来。
最近找到一个可以获得视频绝对地址的解析网站,支持各大视频网站,我用PhantomJS尝试去爬取,结果成功了,下篇准备将其结合tkinter进行编程。
import requests
import re
from bs4 import BeautifulSoup
import urllib
import webbrowser
from tkinter import *
from tkinter import messagebox
from tkinter.scrolledtext import ScrolledText
import time
import threading
import os
#在一部影院中从关键字获取所有资源链接
def getlinks():
global links
global keyword
keyword = var2.get()
url = 'http://www.yibuyy.com/search.php?searchword='+keyword
r = requests.get(url, timeout = 30, headers = headers)
top = r.text.find('<!-- 头部结束 -->')
bottom = r.text.find('<!-- 尾部开始 -->')
link_all = r.text[top:bottom]
req = re.compile(r'a href="(.*?)"[\s\S]*?"sTit">(.*?)<')
links = re.findall(req, link_all) #找到所有的资源名和资源链接
return links
#根据gui里选择的资源,访问该资源
def getinfo(links, origin):
try:
r = requests.get('http://www.yibuyy.com'+links[origin-1][0], timeout = 30)
r.encoding = 'utf-8'
except:
print('没有找到分页链接或访问超时')
req = re.compile(r'span id=.*?<a>(.*?)</a>')
play_root = re.findall(req, r.text)
soup = BeautifulSoup(r.text, 'lxml')
group = soup.find_all('div', class_="downlist mb clearfix")
req_subset = re.compile(r'href="(.*?)".*?title="(.*?)"')
url_total = []
for each in group:
links_subset = re.findall(req_subset, str(each))
url_total.append(links_subset)
info = list(zip(play_root, url_total)) #找到相关资源的播放源和分集信息
return info
#选择下载资源
def choice_down(event = None):
global flag
global download_info
flag = 1 #流动字幕传入参数,控制字幕break
if len(info[play_origin-1][1]) == 1: #当视频只有一集时,设置匹配字符
num = 1
subset = info[play_origin-1][1][0][1]
reg = re.compile(r'%s\$\$%s\$(.*?)\$%s'%(info[play_origin-1][0], subset, info[play_origin-1][0]))
else:#当视频有多集时,设置匹配字符
num = int(var5.get())
subset =info[play_origin-1][1][num-1][1]
reg = re.compile(r'%s.*?%s\$(.*?)\$'%(info[play_origin-1][0], subset))
try:
r = requests.get('http://www.yibuyy.com'+info[play_origin-1][1][num-1][0],timeout = 30)#访问视频分集源代码
r.encoding = 'utf-8'
video_url = re.findall(reg, r.text) #找到url_id,用于拼凑最后的get请求链接
if info[play_origin-1][0] == 'mgtv':
res = requests.get('http://api.goudaitv.com/youkuyun/url.php?xml=%s&type=%s'%(video_url[0],'mgtv'), timeout = 30, headers = head)#访问get请求,提交头部信息
else:
res = requests.get('http://api.goudaitv.com/youkuyun/url.php?xml=%s&type=%s'%(video_url[0],'pptvyun'), timeout = 30,headers = head)#访问get请求,提交头部信息
parse = re.findall(r'CDATA(.*?)]', res.text) #从res中找到视频的真实地址
download_info = list(zip([subset],[parse[1]]))#下载集数和视频真实地址
text.insert(END,'\n%s %s下载链接:\n%s'%(keyword, download_info[0][0],download_info[0][1][1:]))#将信息插入在window中的text里
print(download_info)
label = Label(window, font=('楷体',10), fg = 'red',textvariable=var6).grid(row=7, column=0, columnspan=3)
var6.set('……全力加速,准备下载……')
var0.set('---点击开始---')
button = Button(window, text='开始', width=7, height=3, bg='blue', fg='white',font=('微软雅黑',18), command = start_down)#转到下载
button.focus_force()
button.bind("<KeyPress-Return>", start_down)
button.grid(row=4, column=2)
return download_info
except:
var3.set('访问下载链接失败或访问超时,请重试或切换播放\下载源')
def start_down(event = None):
global thread
thread += 1
th = threading.Thread(target = download)#定义多线程下载视频
th.start()
def openfile(event = None):
os.system('explorer '+os.getcwd()+'\download') #打开文件夹
#设置下载进度1
def process1(a, b, c):
per = 100.0 * a * b / c
if per > 100:
per = 100
var6.set('%s 下载进度:%.2f%% %.2fM/%.2fM 用时: %02d:%02d' % (t1,per, a*b/1024/1024, c/1024/1024, int(time.clock()-s1)//60 ,int(time.clock()-s1)- 60*(int(time.clock()-s1)//60)))
if per == 100:
var6.set('……%s 下载完毕,用时: %02d:%02d……'%(t1,int(time.clock()-s1)//60 ,int(time.clock()-s1)- 60*(int(time.clock()-s1)//60)))
#设置下载进度1
def process2(a, b, c):
per = 100.0 * a * b / c
if per > 100:
per = 100
var7.set('%s 下载进度:%.2f%% %.2fM/%.2fM 用时: %02d:%02d' % (t2,per, a*b/1024/1024, c/1024/1024, int(time.clock()-s2)//60 ,int(time.clock()-s2)- 60*(int(time.clock()-s2)//60)))
if per == 100:
var7.set('……%s 下载完毕,用时: %02d:%02d……'%(t2,int(time.clock()-s2)//60 ,int(time.clock()-s2)- 60*(int(time.clock()-s2)//60)))
#进行下载
def download(event = None):
global s1 #线程1 时间
global s2 #线程2 时间
global t1 #线程1 下载信息
global t2 #线程2 下载信息
global thread
time.sleep(1)
var3.set('<---下载过程中请勿关闭本窗口--->')
var0.set('---打开下载文件夹---')
button = Button(window, text='打开', width=7, height=3, bg='blue', fg='white',font=('微软雅黑',18), command = openfile)
button.focus_force()
button.bind("<KeyPress-Return>", openfile)
button.grid(row=4, column=2)
if not os.path.exists('download'):
os.mkdir('download')
if thread == 1: #如果是一条下载线程
label = Label(window, font=('楷体',10), fg = 'red',textvariable=eval('var%d'%(thread+6))).grid(row=thread+7, column=0, columnspan=3)
eval('var%d'%(thread+6)).set('……可继续添加下载……')
t1 = '%s %s'%(keyword,download_info[0][0])
s1 = time.clock()
if thread == 2: #如果是两条下载线程
label = Label(window, font=('楷体',10), fg = 'red',textvariable=eval('var%d'%(thread+6))).grid(row=thread+7, column=0, columnspan=3)
eval('var%d'%(thread+6)).set('╮(╯▽╰)╭只设置了两条下载线程╮(╯▽╰)╭')
t2 = '%s %s'%(keyword,download_info[0][0])
s2 = time.clock()
print(thread)
urllib.request.urlretrieve(download_info[0][1][1:], "download\%s.mp4" %eval('t%d'%thread), eval('process%d'%thread))
thread -= 1 #下载完毕,腾出线程
#打开浏览器进行观看
def browser(event = None):
num = int(var5.get())
var3.set('已在浏览器中打开,请移步浏览器进行观看')
webbrowser.open('http://www.yibuyy.com'+info[play_origin-1][1][num-1][0],0)
#定义button
def button(function):
global _button
_button = Button(window, text='确定',width=8, bg='blue', fg='white', font=('微软雅黑', 14), command = function, activebackground= 'red')
_button.grid(row=6, column=2)
_button.bind("<KeyPress-Return>", function)
return _button
#定义lab
def lab(picture):
label = Label(window, image = picture).grid(row=4, column=2)
#
def player(event = None):
global play_origin
try:
play_origin = int(var5.get())
print(play_origin)
if play_origin in down_num:
lab(img)
var0.set('---扫一扫,加关注---')
var3.set('<---下载链接为视频真实地址,选中Crtl+c可在浏览器进行观看\下载--->')
var4.set('请选择下载的集数:')
my_entry.delete(0, END)
_button.grid_forget()
button(choice_down)
else:
if len(info[play_origin-1][1]) == 1:
var3.set('<---已在浏览器中打开,请移步浏览器进行观看--->')
webbrowser.open('http://www.yibuyy.com'+info[play_origin-1][1][0][0],0)
else:
my_entry.delete(0, END)
var4.set('请输入观看的集数:')
my_entry.focus_force()
_button.grid_forget()
button(browser)
except:
var3.set('<---您输入有误,请重新输入--->')
my_entry.delete(0, END)
def middle(event = None):
global info
global down_num
try:
origin = int(var5.get())
info = getinfo(links, origin)
var3.set('<---访问papapa资源下载速度较慢,建议选择mgtv--->')
text.delete(0.0, END)
down_num = []
for i in range(len(info)):
if len(info[i][1]) == 1:
if info[i][0] == 'papapa' or info[i][0] == 'mgtv':
text.insert(END, '%s %s(下载):%s = %s'%(links[origin-1][1], info[i][0], info[i][1][0][1], str(i+1))+'\n')
down_num.append(i+1)
else:
text.insert(END, '%s %s(观看):%s = %s'%(links[origin-1][1], info[i][0], info[i][1][0][1], str(i+1))+'\n')
else:
if info[i][0] == 'papapa' or info[i][0] == 'mgtv':
text.insert(END, '%s %s(下载):共%s集 = %s'%(links[origin-1][1], info[i][0], len(info[i][1]), str(i+1))+'\n')
down_num.append(i+1)
else:
text.insert(END, '%s %s(观看):共%s集 = %s'%(links[origin-1][1], info[i][0], len(info[i][1]), str(i+1))+'\n')
my_entry.delete(0, END)
lab(godie_qr)
var0.set('---微信公众号---')
var4.set('请选择播放\下载源:')
my_entry.focus_force()
_button.grid_forget()
button(player)
except:
var3.set('<---您输入有误,请重新输入--->')
my_entry.delete(0, END)
def body(event = None):
global my_entry
global button
links = getlinks()
text.delete(0.0, END)
if len(links) != 0:
for i in range(len(links)):
var3.set('<---为您找到以上资源--->')
var7 = 'author:tianwen'
lab(godie)
var0.set('---狗带TV---')
text.insert(END,links[i][1]+' = '+str(i+1)+'\n')
label = Label(window, font=('楷体',14), textvariable=var4).grid(row=6, column=0)
var4.set('请选择资源:')
my_entry = Entry(window, textvariable=var5, font=('微软雅黑',14),relief = 'ridge')
my_entry.focus_force()
my_entry.icursor(10)
my_entry.grid(row=6, column=1)
button(middle)
else:
var3.set('没有找到该资源,请重新输入关键词')
entry.delete(0, END)
def callback():
if messagebox.askokcancel('Quit?', 'Do you really want to quit?'):
window.destroy()
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
head = {'Referer':'http://api.goudaitv.com/youkuyun/ckplayer/ckplayer.swf',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
if __name__ == '__main__':
global thread
thread = 0
#Start GUI
window = Tk()
window.title('一部影院')
window.geometry('+450+210')
window.resizable(False, False)
window.iconbitmap('material\i.ico')
photo = PhotoImage(file= 'material\ic.png')
godie = PhotoImage(file= 'material\godie.png')
godie_qr = PhotoImage(file= 'material\godie_qr.png')
img = PhotoImage(file= 'material\ma_qr.png')
var0 = StringVar()
var1 = StringVar()
var3 = StringVar()
var2 = StringVar()
var4 = StringVar()
var5 = StringVar()
var6 = StringVar()
var7 = StringVar()
var8 = StringVar()
label = Label(window, font=('楷体',14), textvariable=var1).grid(row=1, column=0)
var1.set('请输入影视信息:')
entry = Entry(window, textvariable=var2, font=('微软雅黑',14), relief = 'ridge')
entry.focus_force()
entry.grid(row=1, column=1)
Bone = Button(window, text='搜索', width=8,bg='blue', fg='white', font=('微软雅黑', 14), command = body,activebackground= 'red')
Bone.grid(row=1, column=2)
Bone.bind("<KeyPress-Return>", body)
lab(photo)
#label = Label(window, image = photo).grid(row=4, column=2)
label = Label(window, textvariable=var0, font=('微软雅黑',8)).grid(row=3, column=2)
var0.set('---信息来源---')
text = ScrolledText(window, font=('楷体',13), fg='blue',height=9,width=47)
text.grid(row=3, column=0, rowspan=2, columnspan=2)
text.insert(1.0,'此软件仅用于交流学习,请勿用于商业用途')
label = Label(window,font=('楷体',9),fg='red',textvariable=var3).grid(row=5, column=0, columnspan=2)
var3.set('<---程序准备就绪--->')
window.protocol("WM_DELETE_WINDOW", callback) #询问退出
canvas = Canvas(window, height=11, width=530)
canvas.grid(row=0, column=0, columnspan=3)
flag = 0
while True:#流动字幕
string = '交流学习使用,请勿用于商业用途(Author:Tian Wen)'
c=canvas.create_text(-150,8,text=string,fill='red', font=('楷体',9))
for x in range(0,300):
canvas.move(c,3,0)
window.update()
time.sleep(0.05)
if flag:
canvas.move(c,1000,0)
break
if flag:
break
window.mainloop()
最后使用pyinstaller将程序打包成exe文件,可在windows上运行,软件截图:
此软件交流学习使用,请勿用做商业用途。
百度云下载链接:http://pan.baidu.com/s/1o7XlRbc 密码:w7qf
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。