老父亲让我帮忙下载个微信公众号的音频
具体而言就是下下来这个页面上列表里所有的音频文件:https://mp.weixin.qq.com/mp/homepage?__biz=MzA4NzMzMjczMg==&hid=9&sn=fe1ec70d80401265f5c7018120879a63&scene=18&uin=&key=&devicetype=Windows+10+x64&version=6302019a&lang=zh_CN&ascene=7&fontgear=2
需要读者:学会基本的python编程
很遗憾到最后还是决定不按照时间顺序来写,那样脉络太不清晰了,不然我是很想记录我是怎么遇到其中的每一个问题的。
以下源码:
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
import requests as rq
if __name__=='__main__':
driver=webdriver.Firefox()
base_url='https://mp.weixin.qq.com/mp/homepage?__biz=MzA4NzMzMjczMg==&hid=11&sn=bb7bc45d8a49ff0607153db985d2c2c2&scene=18&uin=&key=&devicetype=Windows+10+x64&version=6302019a&lang=zh_CN&ascene=7&fontgear=2'
driver.get(base_url)
# time.sleep(3)
for i in range(1,10):
js="var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
time.sleep(1)
eles=driver.find_elements_by_class_name('list_item')
num=0
href=[None]
for ele in eles:
href.append(ele.get_attribute('href'))
num+=1
for i in range(1,num+1):
driver.get(href[i])
all_handles = driver.window_handles
new_handle = all_handles[-1]
driver.switch_to.window(new_handle)
time.sleep(3)
a=driver.find_elements_by_class_name('weui-audio-btn')
a[-1].click()
au=driver.find_element_by_tag_name('audio')
title=driver.title
h=au.get_attribute('src')
print(title)
filepath='D:'+'\\'+title+'.mp3'
open(filepath, 'wb').write(rq.get(h).content)
Part 1 初识Splinter
一开始老父亲发了个链接
https://blog.csdn.net/lpwmm/article/details/108722225
这个博主用的是Splinter,所以一开始我打算用Splinter。
Splinter是Python一个操作浏览器的包,但其实是基于Selenium来实现的。有人说这东西更简便,经过后来的研究我反正没看出来。Splinter最大的问题在于用的人少,网上很少能找到相关的资料,所以最终没有选择它。
这篇微博最大的优点在于他和我要爬的都是微信公众号,有极大的相似点,所以后面借鉴了很多。
Part 2 点亮前置技能:HTML
其实Web编程主要就是HTML,CSS,JavaScript
一个网页本质上还是一个文档。HTML告诉我们这个文档里有什么东西;CSS规定了这个文档里文字等内容的样式,就是怎么显示,字体、颜色之类;JavaScript是写在文档里的程序,负责组织人机交互之类的,其实就是响应。
在本次任务中,基本不涉及CSS和JavaScript,只需要了解HTML就好。具体参见runoob.com(菜鸟教程)和www.w3school.com.cn,以下附上链接:
菜鸟教程:https://www.runoob.com/html/html-tutorial.html
w3school:https://www.w3school.com.cn/h.asp
只需要知道这个网页大概是如何运作的就好,不需要了解那么多,尤其是很多细节并不需要。
Part 3 分析任务
我们的任务其实就是两部分:①寻找到真正的音频地址 ②下载
其中第①部分是大头,②只需要调用一下函数就能解决
我们分析一下①任务:
我们的原始url是:
https://mp.weixin.qq.com/mp/homepage?__biz=MzA4NzMzMjczMg==&hid=9&sn=fe1ec70d80401265f5c7018120879a63&scene=18&uin=&key=&devicetype=Windows+10+x64&version=6302019a&lang=zh_CN&ascene=7&fontgear=2
我们要从这里一个一个打开里面内嵌的网址,然后从这些网址里:(这里举一个例子)https://mp.weixin.qq.com/s?__biz=MzA4NzMzMjczMg==&mid=2650878896&idx=2&sn=a2015a04ca0beae19baad45a86b73db0&scene=19#wechat_redirect 找到具体的音频文件下载。
从代码角度分析,我们需要实现两个功能:1 操作浏览器实现交互 2 从网页里提取我们需要的信息
Part 4 Selenium!Selenium!
Selenium可以说是很强大了,它是这次任务的核心。
一定要推荐一位博主的文章,写的很详细,是我最大的助力:
https://www.cnblogs.com/yoyoketang/tag/selenium/
Selenium - 安装
安装selenium
1 打开cmd
2 输入pip install selenium,回车
3 好的,看着他自动安装就好
(不得不说python这点太™方便了)
相关驱动:getodriver/chromedriver
selenium其实就是操控你的浏览器,你不同的浏览器有不同的类去实现。selenium 3 比起selenium 2 需要额外安装一个软件:对于firefox是getodriver.exe,对于chrome是chromedriver.exe。
我用的是firefox,所以底下都写firefox相关的了。chrome其实差不太多,我都会附各种链接,那些链接里提到chrome相关的事。
https://github.com/mozilla/geckodriver/releases/tag/v0.27.0
从这里可以下载getodriver,稍微有点慢,所以耐心等待。我没有找到国内的好的下载地址。
另外,请尽量保证你的getodriver是最新版,要不然可能会有bug,以下我会提到。
剩下的东西可以参考:https://www.cnblogs.com/yoyoketang/p/selenium.html
Selenium 基本操作
from selenium import webdriver是我们引用库
driver=webdriver.Firefox()创建一个driver对象
driver.get(url)访问url这个网址,url是一个str变量,例:`driver.get('www.baidu.com')
Selenium 切换页面
有的网页在driver.get()之后默认打开新标签页,但是我们selenium还停留在原来的标签页,所以需要我们切换过去
每一个网页都是一个handle句柄(我也不知道具体是啥,我理解成线程一样的东西)
我们有driver.switch_to.window(handle)来切换到handle对应的页面上(handle是一个str类型变量)
我们要知道新打开来的那个句柄是什么,采取这样的方法:
all_handles = driver.window_handles
new_handle = all_handles[-1]
new_handle就是我们找到的新打开的页面的句柄
我们首先用driver.window_handles返回一个列表,是所有的句柄。
句柄的最后一个元素就是新打开的了
参考网站:
https://www.cnblogs.com/jinbaobao/p/13901750.html
https://www.cnblogs.com/Chan94/p/9883352.html
https://www.cnblogs.com/yoyoketang/p/6128611.html
Selenium JS指令 - 滚动页面
我们的页面不是一次性显示出来的,很多网站(就比如这次我们要面对的)需要到最底部才会往下加载,所以我们需要让程序滚动到道最底部让他加载一下。
参考网址:https://www.cnblogs.com/yoyoketang/p/6128655.html
JS就是JavaScript,前文说过大致的作用,我们就是要让这个网页执行一个程序(做出响应)
具体我没有研究JS,只是抄了上面网址的方法:
滚动页面到底部:
js="var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
当然也可以使用键鼠事件,控制键盘点空格。具体其他的可以自己研究。
键鼠参考网址:https://www.cnblogs.com/yoyoketang/p/6128607.html
Selenium Profile配置文件更改
参考网址:https://www.cnblogs.com/yoyoketang/p/7657436.html
由于我很早就加上这个代码了,所以甚至不知道这个东西究竟需不需要,有兴趣的自己去看就好,不是重点。
而且后来写到最后我也给删了。
Selenium 定位元素 重点
参考网址:
https://www.cnblogs.com/yoyoketang/p/6123890.html(我们今天用到的不需要装他说的那些,因为不用XPath)
https://www.cnblogs.com/yoyoketang/p/6128599.html
https://www.cnblogs.com/yoyoketang/p/7153053.html
这是最重要的部分。经过简单的学习,我们知道网页都是由一个个元素组成。我们要找的链接当然也在元素里面。我们这部分要做的,就是F12观察页面的源代码,分析我们从哪里能找到我们要找的元素。
首先第一步我们找到页面里面每一条故事的地址。
这里定义一下称谓,最初的网址
https://mp.weixin.qq.com/mp/homepage?__biz=MzA4NzMzMjczMg==&hid=9&sn=fe1ec70d80401265f5c7018120879a63&scene=18&uin=&key=&devicetype=Windows+10+x64&version=6302019a&lang=zh_CN&ascene=7&fontgear=2
我们叫做首页
点进去以后的网址是:https://mp.weixin.qq.com/s?__biz=MzA4NzMzMjczMg==&mid=2650878896&idx=2&sn=a2015a04ca0beae19baad45a86b73db0&scene=19#wechat_redirect
叫做故事页面
我们首先进入一个故事页面:直接在首页里点进去,查看它的网址:https://mp.weixin.qq.com/s?__biz=MzA4NzMzMjczMg==&mid=2650878972&idx=1&sn=74c7684b0f5e10b70ce48dfd9dd4e2a4&scene=19#wechat_redirect
我们再在首页里F12看一下控制台,右键页面中《狠毒的王子》条目,点检查
框选出来的就是检查到的元素,我们在这附近找一找,就能发现网址 。点进去,确实是到了故事页面。
接下来我们来找一下这个元素的特征。它的class属性是:'list_item js_post',我们先把焦点放到控制台上,点Ctrl+F,搜索一下list_item
我们发现,只有在有故事页面的网址的地方,才有list_item
好!我们发现了特征,我们可以通过这个来找网址了。
使用driver.find_elements_by_class_name('list_item')就可以找到一个元素的列表了。这句话的含义是,根据class的name来找元素。至于怎么把元素里的网址提取出来,将是底下“获取元素属性”要说的事情,这里就先不说了。
这里class是list_item js_post,中间有个空格,这个坑可以看一眼第三个参考网址
也有其他方式去定位元素,请详见参考网址。这里不具体说很多。
进入到故事页面,我们还需要找到音频真正的地址。首先,老父亲一开始给我发的那个网址里,帮我避开一个坑:微信公众号需要先点击播放按钮才会有音频的元素出来!! 所以我们需要先点一下播放的按钮,然后去找音频。
如何点击呢?我们只需要找到按钮这个元素btn,btn.click()就可以点击了
定位元素btn也是类似的步骤,这里我是这样做的:driver.find_elements_by_class_name('weui-audio-btn')
最后,我们需要定位到音频元素,我从控制台的element里找了很久都没有找到。后来从百度搜到可以在network里找到类型为media的文件,但依旧不知道怎么用selenium去找这个文件。最终是从老父亲发的那个链接里,把那位博主本来用splinter写的改写成了selenium版的——直接按标签名字找audiodriver.find_element_by_tag_name('audio')
Selenium 获取元素属性
参考网址:https://www.cnblogs.com/yoyoketang/p/6486927.html
element.get_attribute(str)就可以获取对应的属性,括号里参数是一个字符串,写属性名。element是一个元素对象。返回值就是属性的值。
driver.title就是直接获取了当前页面的标题,就是你标签页上显示的。
比如在获取故事页面链接:ele.get_attribute('href')
比如在获取最终的音频链接时:au.get_attribute('src')
这里说一下,href就是超链接,src就是引用资源,就比如这篇markdown,参考网址就是类似于href,而嵌入的图片,如下图,代码里也是一个链接,但是显示出来是图片。
Part 5 requests下载
其实这部分没怎么研究,就是把老父亲给的链接里的代码改了改。
filepath='D:'+'\\'+title+'.mp3'
open(filepath, 'wb').write(rq.get(h).content)
open涉及到另一个库,os,用来进行文件操作,具体知识可见菜鸟教程:https://www.runoob.com/python/os-file-methods.html
filepath填你想要放置的路径就可以了
rq是在前面调用头文件的时候把requests缩写过来了,用get('链接').content就可以获取那个页面的数据,然后写入本地的文件里。
Part 6 代码解析
再贴一遍代码方便翻页:
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
import requests as rq
if __name__=='__main__':
driver=webdriver.Firefox()
base_url='https://mp.weixin.qq.com/mp/homepage?__biz=MzA4NzMzMjczMg==&hid=11&sn=bb7bc45d8a49ff0607153db985d2c2c2&scene=18&uin=&key=&devicetype=Windows+10+x64&version=6302019a&lang=zh_CN&ascene=7&fontgear=2'
driver.get(base_url)
# time.sleep(3)
for i in range(1,10):
js="var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
time.sleep(1)
eles=driver.find_elements_by_class_name('list_item')
num=0
href=[None]
for ele in eles:
href.append(ele.get_attribute('href'))
num+=1
for i in range(1,num+1):
driver.get(href[i])
all_handles = driver.window_handles
new_handle = all_handles[-1]
driver.switch_to.window(new_handle)
time.sleep(3)
a=driver.find_elements_by_class_name('weui-audio-btn')
a[-1].click()
au=driver.find_element_by_tag_name('audio')
title=driver.title
h=au.get_attribute('src')
print(title)
filepath='D:'+'\\'+title+'.mp3'
open(filepath, 'wb').write(rq.get(h).content)
driver=webdriver.Firefox()
base_url='https://mp.weixin.qq.com/mp/homepage?__biz=MzA4NzMzMjczMg==&hid=11&sn=bb7bc45d8a49ff0607153db985d2c2c2&scene=18&uin=&key=&devicetype=Windows+10+x64&version=6302019a&lang=zh_CN&ascene=7&fontgear=2'
driver.get(base_url)
先创建webdriver的实例driver,url里填写需要爬的网址,我时间有限没有做UI,就是自己直接改代码里的地址。
接着访问地址。
time.sleep()是为了等页面刷新,网络不好要自己调一调延时的。下文中的time.sleep()都是一样的道理。(括号里填延时的秒数)
for i in range(1,10):
js="var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
time.sleep(1)
eles=driver.find_elements_by_class_name('list_item')
这里是做几次下拉页面的操作,还是时间有限(toulan)。做细致一点应当是能判断是否到头的,想做的可以自己做,我就直接这样了。
eles是获取了整个首页里的故事页面地址列表,eles是一个由元素组成的队列。
num=0
href=[None]
for ele in eles:
href.append(ele.get_attribute('href'))
num+=1
先把地址都存下来。因为你只要切换出去页面,它就找不到那个元素在哪儿了,所以先存地址,免得以后来回换。
for i in range(1,num+1):
driver.get(href[i])
all_handles = driver.window_handles
new_handle = all_handles[-1]
driver.switch_to.window(new_handle)
time.sleep(3)
a=driver.find_elements_by_class_name('weui-audio-btn')
a[-1].click()
au=driver.find_element_by_tag_name('audio')
title=driver.title
h=au.get_attribute('src')
print(title)
filepath='D:'+'\\'+title+'.mp3'
open(filepath, 'wb').write(rq.get(h).content)
整个循环是打开每一个页面去找地址,然后下载。
a是存储了播放按钮元素,au存储了当前故事页面的音频真实地址。
最后两行把东西下载下来。
Part 7 其他提醒
- 注意定位元素时element和elements单复数的区别——前者返回一个元素对象,后者返回一个元素对象组成的列表
- 如果在切换句柄的时候报错,请尝试更新你的getodriver
- 这个程序莫名其妙有时候下着下着,中间会突然点不到按钮导致程序终止(不点按钮后面就找不到音频元素了),不知道怎么解决。
浙公网安备 33010602011771号