准备用爬虫入门python,做个练习。
首先解析一下网页,随便找个音频打开,我比较喜欢鬼谷子,就选他老人家了。
我用的360浏览器,直接F12,找到音频列表那片区域。
一直点到音频的的区域
获得第一个有用的信息:
div的class是"text _Vc",网页都是批量生成的,所以别的网页肯定也一样。
不行的话,随便找几个验证一下。确认没问题。
然后点开第一个网页,打开音频的播放页面。
点小三角播放,继续看F12,出现一个好大的audio,高度疑似目标。
点开后有个请求的连接,复制下来,输入到浏览器看一下。
看src,后面有个地址,是m4a格式的,再复制下来到浏览器看看。
没错,响了。
而且,这个数字和音频播放网页地址的id是一个。
确认过眼神,是要爬的虫。
这样图二的地址需要记一下,图三的是最终的资源地址。
因为是点了以后才会出现图二的地址,应该是所谓的动态加载(还没学到,了解点“动态”这个词,猜的)
那这样,三个地址都有了。
第一个地址手动输入(类似于这样的/youshengshu/29497459/),然后用BeautifulSoup把class="text _Vc"的tag匹配出来。
最后提取出音频播放页面的地址(图1的herf)和音频名称。
顺便页面总数也匹配出来保存一下。
接下来把提取到的地址最后那组数字也提取出来,拼接一个图2的地址。
再用这个地址获取图三的数据,就是src后面那一串以https开头,m4a结尾的字符串。
拿到以后就有了音频资源的地址,下载下了就完成了。
下面上源码,编译环境是3.7,需要bs4和fake_useragent这俩第三方包。
'''
python爬虫练习
获取一个专辑的网页,解析出每个音频的资源地址,下载到本地
'''
import os
import re
from urllib import request
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
def get_html(target_url):
'''
将网页解析为utf-8格式的BeautifulSoup
:param target_url: 网页地址
:return: 返回一个BeautifulSoup对象
'''
opener = request.build_opener()
opener.addheaders = [('User-Agent', UserAgent().random)]
request.install_opener(opener)
page = request.urlopen(target_url).read()
return BeautifulSoup(page, 'lxml')
def get_page(url_page, pagenumber):
'''
取得专辑某一页面的资源
:param url_page: 专辑网页地址
:param pagenumber: 专辑的页面序号
:return: 返回一个列表[页码-本页面编号, 音频名称, 音频网页地址]
'''
target_page = get_html(url_page)
package_li = str(target_page.find_all(attrs={'class', 'text _Vc'}))
pattern = '<a href="(.+?)".+?title="(.+?)">'
targets = re.findall(pattern, package_li)
page_source = []
index = 1
for target in targets:
target_link = target[0]
target_title = target[1]
page_source.append([str(pagenumber)+"."+str(index), target_title, target_link])
print("获取第%d条记录" % index)
index += 1
return page_source
def get_all_pages(page_num, base_url):
'''
获取所有页面的资源列表
:param page_num: 专辑的页面数量
:param base_url: 专辑页面的地址
:return: 返回一个专辑所有页面的资源列表[页码-本页面编号, 音频名称, 音频网页地址]
'''
source_list = []
index = 1
for i in range(int(page_num)):
if i == 0:
print("第%d页" % index)
# print(base_url)
source_list.append(get_page(base_url, index))
index += 1
continue
print("第%d页" % index)
# print(base_url + "p" + str(i + 1) + "/")
source_list.append(get_page((base_url + "p" + str(i + 1) + "/"), index))
index += 1
return source_list
def get_source(target_url):
'''
获取专辑全部音频资源
:param target_url: 专辑的首页面地址
:return: 返回一个资源列表[页码-本页面编号, 音频名称, 音频网页地址], 一个专辑名称
'''
target_html = get_html(target_url)
# <input type="number" placeholder="请输入页码" step="1" min="1" max="9" class="control-input _Xo" value="">
pattern = r'max="(\d)"'
page_max = (re.findall(pattern, str(target_html)))[0]
# <h1 class="title lO_">鬼谷子智慧</h1>
pattern = r'<h1 class="title lO_">(.+?)</h1>'
folder = (re.findall(pattern, str(target_html)))[0]
tmp_source_list = get_all_pages(page_max, target_url)
source_list = []
for item in tmp_source_list:
source_list.extend(item)
return source_list, folder
def analysis_data(source):
'''
解析资源页面,从返回的数据中提取m4a音频的地址
:param source: 音频资源列表
:return: 返回一个列表,其中每个元素都是一个m4a音频的地址
'''
pattern = r'.+/(\d+)'
url_list = []
index = 1
for item in source:
res = 'https://www.ximalaya.com/revision/play/v1/audio?id=' \
+ (re.findall(pattern, item[2]))[0] + '&ptype=1'
url_list.append(res)
print("解析链接 %d/%d" % (index, len(source)))
# debug
print(res)
index += 1
# https://www.ximalaya.com/revision/play/v1/audio?id=67064624&ptype=1
response_list = [str(get_html(a_url)) for a_url in url_list]
# debug 如果上面url打开后资源不是m4a需要修改正则表达式
pattern = '"src":"(.+?)","'
print("没有死,稍等")
return [(re.findall(pattern, response))[0] for response in response_list]
def mkdir(file_path):
'''
创建用于保存的文件夹
:param file_path: 文件夹路径
'''
folder = os.path.exists(file_path)
if not folder:
os.mkdir(file_path)
print("创建文件夹")
else:
print("文件夹已存在")
def crawl_source(file_url, file_path):
'''
爬取音频资源
:param file_url: 音频资源的地址
:param file_path: 本地文件名
'''
try:
opener = request.build_opener()
opener.addheaders = [('User-Agent', UserAgent().random)]
request.install_opener(opener)
request.urlretrieve(file_url, file_path)
except Exception as e:
print(e)
def download_source(file_url, file_path, source):
'''
批量下载音频资源
:param file_url: 全部音频资源地址的列表
:param file_path: 本地文件夹路径
:param source: 音频资源的列表,用于创建文件名,[页码-编号, 音频名称, 音频网页地址]
'''
name_list = [str(item[0]) + "." + item[1] for item in source]
index = 1
# 查看url防止出错
for item in file_url:
print(item)
for i in range(len(file_url)):
file_name = file_path + name_list[i] + '.m4a'
crawl_source(file_url[i], file_name)
print("当前进度:%d/%d" % (index, len(file_url)))
index += 1
print("下载完成,当前目录:%s" % file_path)
if __name__ == "__main__":
# 网页专辑地址
url = 'https://www.ximalaya.com/youshengshu/29497459/'
# 获取专辑内每个音频的播放页面地址,专辑名
source, folder_name = get_source(url)
# 解析每个音频播放网页,获得一个列表,包含专辑的全部音频链接
# [id, 音频名称, 音频资源地址]
download_list = analysis_data(source)
# 合成本地保存路径,并生产文件夹
folder_path = "./source/" + folder_name + "/"
mkdir(folder_path)
print("准备完毕,开始下载")
# 下载资源到本地
download_source(download_list, folder_path, source)
|