2019.10.5
我是个假面骑士厨,虽然很感谢某视频网站引进了正版的假面骑士。但这也直接断绝了曾经极其方便的资源,大量的资源被清洗。虽然本人也很乐意花钱买会员看正版,只是突然发现很多网站下载免费视频都要下载客户端,于是乎想写个爬虫下载视频。经过断断续续一周的摸索,最后决定写一个可以下普通视频和VIP视频的爬虫。 程序仅用于自己娱乐,不用于商业用途。
下载中....
一. 使用到的Python库
urllib.request模块定义了有助于在复杂环境中打开URL(主要是HTTP)的函数和类-基本身份验证和摘要身份验证,重定向,Cookie等。可以实现通过代码来模拟向服务器发送请求并获取html代码,以达到爬取网页内容的目的。
urllib.request.urlopen(url, data=None, [timeout, ], cafile=None, capath=None, cadefault=False, context=None) :用于向服务器发起请求,实例化HTTP对象,获取url的资源,通过 read() 方法获取其内容( 如果要显示html,还要用decode()将其转为‘utf-8’编码 )。
该模块将URL(统一资源定位符)字符串分解成其组件(地址方案,网络位置,路径等),将组件重新组装成URL,并指定“相对URL”定义用于基于“基本URL”转换为绝对URL的标准接口。 此处用于将搜索的关键词中包含的中文转换为utf-8编码的字符。
Beautiful Soup提供了一些用于 导航,搜索和修改解析树的简单方法和Pythonic习惯用法:用于剖析文档并提取所需内容的工具箱。
Beautiful Soup会自动将传入文档转换为Unicode,将传出文档转换为UTF-8。您不必考虑编码,除非文档未指定编码并且Beautiful Soup无法检测到编码。然后,您只需要指定原始编码即可。
Beautiful Soup位于流行的Python解析器(如lxml和html5lib)的顶部,使您可以尝试不同的解析策略或提高灵活性。
bs4.BeautifulSoup.find_all( name, attrs, recursive, text, limit, **kwargs )
传入html文本,选择parser(如'html.parser')之后便可以实例化一个BeautifulSoup对象。之后便可以使用 find_all(tag_name) 来寻找 所有的 tag_name标签的内容。返回一个列表,是获得的内容。
用于自动化Web应用程序以进行测试,可模拟人工对浏览器进行各种各样的操作,但一定要下载与自己浏览器相同版本的driver。
selenium.webdriver
用于实例化一个浏览器类。我使用的是Chrome浏览器,所以在使用这个库之前需要安装 官网。
selenium.webdriver.ActionChains
用于模拟执行链式行为的库,可以模拟鼠标键盘对浏览器的行为。 (缺陷:只能对html进行模拟键鼠的行为,无法进行系统的操作)
Windows系统下,Python可以使用此库来打开剪切板和关闭剪切板并获取其内容。 这也是为何我的程序只能在windows下运行的原因。
用于自动化对GUI进行操作,对比ActionChains的优势在于: pyautogui 可以操作浏览器上系统的操作。
缺陷: 鼠标的焦点必须停留在要操作的窗口,否则,将会有意想不到的结果发生
二. 思路解析
(注:下面出现的代码并不完整,完整的代码请到该项目的我的github仓库)
1. 利用API类来获取接口
利用我所知的一个接口(页面内有其他的接口的转换),使用pyautogui模拟鼠标点击,html内才会显示所有的接口,爬下来,以作备用。
接口们
2. 爬取首页的专辑链接
由于我从一开始就是想下载整部作品,并且我在调试时用于搜索的URL出来的网页只有一个合辑(有些页面拥有多个合辑),并且不同的作品可能有不同的标签名。所以我写出来的成品只适合我用于调试的那个合辑,如果要用作其他作品的爬取,则要修改Get_list()的内容。才能获取正确的链接。
1. 根据输入的关键词搜索到腾讯视频的首页,获取第一集的超链接,跳转到第一集的播放页面,从而从侧边栏的剧集中获取所有视频的链接,使用列表存储。
# get the html by keyword
main_res = request.urlopen(self.url)
result_html = main_res.read()
# change the encode
main_data = result_html.decode("utf-8")
main_soup = BeautifulSoup(main_data, 'html.parser')
# get the first video from album
href = main_soup.find_all('a', attrs={'_stat': 'video:poster_num'})[0]['href']
# jump to the play page
play_res = request.urlopen(href)
play_html = play_res.read()
play_data = play_html.decode("utf-8")
play_soup = BeautifulSoup(play_data, 'html.parser')
# Get all the link of page
# The first link is incorrect
self.links = []
for list in play_soup.find_all('a', attrs={'_stat': "videolist:click"})[5:]:
self.links.append('https://v.qq.com' + list['href'])
以上的代码仅适合我的关键词的页面,其他的剧集需要根据实际的html代码爬取。
播放界面
剧集列表
2. 利用API类获取的接口进入到页面,使用selenium模拟浏览器行为,打开用接口加载的网页
url = '接口' + link
# use webdriver simulate the action of chrome
browser = webdriver.Chrome(executable_path='./chromedriver.exe')
browser.get(url)
time.sleep(10) # wait the url loading
selenium使用webdriver库来实例化浏览器对象,可以模拟浏览器的行为。 有趣的是:selenium会真的打开一个浏览器。所以,有以下注意事项:
必须下载匹配自己电脑的浏览器的driver,比如我使用的是chorme,就下载了chromedriver.exe(Mac和Linux环境下也有自己的版本)。
必须填写executable_path这个参数,告诉selenium要使用哪个driver。
可以使用time包下的sleep()函数来让模拟的浏览器休眠一定时间,让其加载好例如js等文件,获取完整的html。
selenium可以使用"find_element[s]_by_[....]( )"系列的函数来查找html中的元素,例如
# find the first element whose tag name is 'div'
right_click = browser.find_element_by_tag_name('div')
# find all elements whose tag name is 'div'
right_click = browser.find_elements_by_tag_name('div')
3. 使用pyautogui来自动化右键页面,复制视频的真实地址
right_click = browser.find_element_by_tag_name('div')
# ActionChain could simulate the action of mouse and keyboard
rightclick = ActionChains(browser)
# double right click, get the menu
rightclick.context_click(right_click)
rightclick.context_click(right_click).perform()
time.sleep(1)
# choose the "copy video address..." option
pyautogui.typewrite(['down', 'down', 'down', 'down', 'down'])
time.sleep(1)
# it must write the "enter", else the choice can't be chosen
pyautogui.typewrite(['enter'])
time.sleep(1)
右键的模拟使用了selenium内的ActionChains类,先实例化一个对象。然后先使用find_element类函数找到需要点击的html控件或者标签。
context_click()函数是actionchains中模拟右键行为的函数,我在这里被坑过,click()是左键的函数。并且,必须使用perform()函数来使actionchains对象进行连锁操作,否则不会进行一连串操作。
其实actionchains中也有选择右键菜单的函数,比如send_keys()函数,但遗憾的是,此类函数只能操作页面的右键的菜单选择的行为。而我爬视频中的右键菜单是只有系统的菜单才会有视频的真实地址的,所以这就需要用到pyautogui了
pyautogui使用 typewrite() 来对系统选项进行操作, 并且最后一定要执行'enter',否则爬虫不会将其识别为选择了菜单(Mac系统不是enter)
pyautogui的缺点就是不能让鼠标焦点离开要操作的界面,否则它会操作其他的界面,出现奇怪的现象。
也是因为这些win32的库,致使这个程序只能在windows系统下运行。
4. 获取剪切板的内容,得到视频真实地址,利用os写入系统
import win32clipboard as wc
wc.OpenClipboard()
url = wc.GetClipboardData(win32con.CF_TEXT)
wc.CloseClipboard() # it must be close, else we will get the same url from clipboard
打开剪切板使用完之后, 一定要关闭剪切板,否则下次剪切板的内容永远都不会改变!
三. 总结
这次的爬虫主要是写着玩一下。最初只是为了写爬虫而已,谁知道后来陆陆续续地出现了接口下载VIP视频,用selenium来模拟浏览器行为,用pyautogui来操作GUI。嘛,我觉得当中遇到的错误挺有趣的,所以记录一下,希望以后不要犯相同的错误。希望自己能慢慢成为舍友那样的大牛。