Python简易爬虫教程(三)--爬取喜马拉雅音频

上一篇我们重点介绍了如何把爬取到的图片下载下来。没错,如果你还记得的话,我们使用的是urlretrieve这个Python自带的下载模块。所以,到现在,爬虫框架的三个基本组成:获取网页,寻找信息,收集信息,我们已经学习完成。相信大家现在已经可以独立地编写自己的爬虫,爬取自己感兴趣的网站了。

然而,随着不断实践,我们会发现,不是所有网站都是像我们前面爬取的搜狐新闻和新浪图片那样简单的。大部分网站,尤其是内容网站,会对自己的数据进行保护,采取一些反爬虫的措施。最常见的,分以下这几种。

第一种,最简单的呢,是一些网站需要登陆才能访问特定资源。比如微博,知乎,tumblr等等。它需要确定我们的用户身份,才能允许读取我们的数据列表,比如粉丝,关注话题,收藏等等。那么遇到这种情况呢,我们只需要让我们的爬虫模拟浏览器登陆就可以了。哈哈,大家不要忘记啦,这依然属于爬虫的第一个步骤,即,先登陆,再获取网页源代码。所以,我们依然可以使用requests这个库进行模拟登陆,获取代码的操作。这个比较简单,网上随便都可以搜索到两行代码,本节就不再赘述了。

那么第二种,最直接的,也是最有效的。隐藏资源的链接。如图所示,这里的href是一个javascript,在网页源码里不明示。

image

这种情况,需要浏览器监测到我们点击了这个链接,触发这个JavaScript,才会向网站发出一个请求,网站才会反馈给浏览器一个真正的href地址。那么,我们在爬取这一类网页的时候,就要面临一个如何模拟浏览器发出点击请求的问题。这一类的网站很多,典型的特点就是,链接必须单击打开,如果右键在新标签页打开,就会跳转到about:blank空标签页。相信大家又有这样的经历。

image

这种网站,处理的重点在于,弄清楚浏览器发出的请求是什么,网站返回的又是什么。然后我们才能模拟。所以,这一篇教程主要介绍,当我们遇到这种网页的时候,该怎么处理,这样大家能够爬取的网站就会更多了。

我们以爬取喜马拉雅网站上的免费音频为例。

打开专辑的页面。

image

我们尝试使用requests的get,发现出现错误,无法获得网页源代码。这就属于上面说的第一种类型,网站识别到我们是爬虫,阻止我们获取代码。因此,我们使用requests.session, 把自己伪装成浏览器。


page = 'https://www.ximalaya.com/qinggan/209378/' #专辑地址

session = requests.session()#使用session方法

r = session.get(page, headers=headers)

#这个headers就是包含浏览器特征的一些数据,为了将我们伪装成浏览器。

headers = {

        "User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',

        'host': 'www.ximalaya.com',

        'Accept-Language': 'zh-CN,zh;q=0.9,ja;q=0.8', 'Accept-Encoding': 'gzip, deflate, br',

        'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",

        'Upgrade-Insecure-Requests': '1',

        'Connection': 'keep-alive',

        'Cache-Control': 'max-age=0'}

这个音频的href是<a title="《摸金天师》第001章 百辟刀" href="/youshengshu/4756811/18556415">《摸金天师》第001章 百辟刀</a>, 显然,这不是一个完整的url地址。我们结合浏览器的地址栏,将其补上。


    soup1 = BeautifulSoup(r.text, 'html.parser')

    audios = soup1.find_all(class_='text _OO')

    print(audios)

    for audio in audios:

        audio_name = audio.a['title']

        audio_url = 'https://www.ximalaya.com' + audio.a['href']

        audio_id = re.sub('/qinggan/209378/', '', audio.a['href'])

好了,现在我们跳转到这条音频的页面去。

image

这下我们发现,我们找不到这个音频的地址在哪里。这个播放按钮只是对应一个空的标签 i,里面没有href,底下对应一个JavaScript。

image

这就是我们这节需要解决的情况了。我们将检查工具切换到network这个标签下的XHR子标签,看看当我们点击这个播放按钮,触发这个JavaScript之后,会发生什么,浏览器会发出什么请求,我们又会收到什么反馈。 这是获得音频地址的重点了。

image
image

我们发现,点击这个按钮之后,出现了一个album?albumId这一项。这里面我们发现,浏览器发出一个get式的requests请求。请求的链接是https://www.ximalaya.com/revision/play/album?albumId=209378&pageNum=1&sort=0&pageSize=30。我们打开这个链接看一下。

image

原来如此啊。喜马拉雅把音频的id,名称,地址全部放在这个字典里了。这样,我们就可以模拟浏览器发送请求了,然后从它返回的这个字典里读取信息了。显然,这个url里pagenum是指专辑音频列表的页面,这个字典包含这个页面中所有音频的信息。那我们就可以根据这个字典把这个专辑这个页面的音频全部下载下来。


        get_audio = ‘https://www.ximalaya.com/revision/play/album?albumId=209378&pageNum=1&sort=0&pageSize=30' 

        audiodic = requests.get(get_audio, headers=headers) #获取这个字典

        for i in range(0,30):

        try:

            src = audiodic.json()['data']['tracksForAudioPlay'][i]['src'] #获取音频地址

            audio_name= audiodic.json()['data']['tracksForAudioPlay'][i]['trackName'] #获取音频名称

        except:

            print('不能解析')

        else:

            print(src)

        filename = './' + audio_name+'.m4a' #别忘记加上文件后缀名

        urllib_download(src, filename) #调用下载函数下载音频并命名

好了,接下来就简单了,相信urlib_download大家通过上一节的学习已经熟悉了。大家可以自行编写。然后,这个专辑一共有三页,我们通过把pagenum改成1,2,3, 就可以将整个专辑都下载下来。

完整代码如下,我还加入了多线程方法和多进程方法,为了使爬虫加速。这一块大家感兴趣的话可以了解一下。不过,不用多线程也没关系,上面那部分的代码已经是核心了,也可以直接使用。


from bs4 import BeautifulSoup

from urllib.request import urlopen

import pickle

import re

import random

import requests

from queue import Queue

import ssl

import concurrent.futures

import time

# ssl._create_default_https_context = ssl._create_unverified_context  #取消ssl认证s

#定义下载程序

def urllib_download(url, filename):

    from urllib.request import urlretrieve #这个是下载文件的库

    import os #这个是用于创建文件目录

    if os.path.exists(filename) == False: #如果文件不存在,创建文件

        urlretrieve(url, filename)

    else:

        pass

#定义爬虫

def download(page,headers):

    session = requests.session()

    r = session.get(page, headers=headers)

    get_audio = ‘https://www.ximalaya.com/revision/play/album?albumId=209378&pageNum='+p+'&sort=0&pageSize=30' 

        audiodic = requests.get(get_audio, headers=headers) #获取这个字典

        for i in range(0,30):

        try:

            src = audiodic.json()['data']['tracksForAudioPlay'][i]['src'] #获取音频地址

audio_name= audiodic.json()['data']['tracksForAudioPlay'][i]['trackName'] #获取音频名称

        except:

            print('不能解析')

        else:

            print(src)

        filename = './' + audio_name+'.m4a' #别忘记加上文件后缀名

        urllib_download(src, filename) #调用下载函数下载音频并命名

#分析页面

#

# #定义多线程方法

# def multithreading(pages,headers):

#

#    import threading

#    import time

#    threads = []

#    thread_star_time = time.time()

#    for page in pages:

#        t = threading.Thread(target=spider1,args=(page,))#注意这里参数后面要有个逗号,不然报错

#        threads.append(t)

#    print(threads)

#    for thread in threads:

#        thread.start()

#        print('线程',thread,'启动')

#        thread.join()

#    threadtime = '全部下载完成,多线程使用' + str(time.time() - thread_star_time) + '秒'

#    q.put(threadtime)

#定义 多进程方法

def multiprocessing(pages,headers):

    import multiprocessing as mp

    import time

    processes = []

    process_star_time = time.time()

    for page in pages:

        t = mp.Process(target=download,args=(page,headers,))#注意这里参数后面要有个逗号,不然报错

        processes.append(t)

    print(processes)

    for process in processes:

        process.start()

        print( '进程',process,'启动')

        process.join()

    processtime = '全部下载完成,多进程使用' + str(time.time() - process_star_time) + '秒'

    q.put(processtime)

#

if __name__ == "__main__":

    # 解析页面列表

    q=Queue()

    for p in range(1,4):

    page = 'https://www.ximalaya.com/qinggan/209378/p'+p

    headers = {

        "User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',

        'host': 'www.ximalaya.com',

        'Accept-Language': 'zh-CN,zh;q=0.9,ja;q=0.8', 'Accept-Encoding': 'gzip, deflate, br',

        'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",

        'Upgrade-Insecure-Requests': '1',

        'Connection': 'keep-alive',

        'Cache-Control': 'max-age=0'}

    global pages

    pages = []

    pages.append(page1)

    pages.append(page2)

    pages.append(page3)

    print(pages)

    # multithreading(pages)

    multiprocessing(pages,headers)

    # for i in range(1, 3):

    print(q.get())

    print('程序结束')

#全部下载完成,多进程使用1408.531194448471秒

# 程序结束

好了,到此结束。我们已经成功下载了这张专辑的所有音频。

image

好啦。感谢大家的阅读。如果你喜欢我的爬虫教程,可以关注我的账号,后续还会有更多的更新。如果有什么建议,也欢迎在评论区留言,我会悉心听取。下一篇我们应该会介绍解决此类隐藏的href的另一种方法,使用selenium库,提前预告一下,哈哈。

声明:本教程及代码仅作教学之用,无意侵犯其它网站或公司版权。本节爬取的搜狐新闻内容,版权为搜狐新闻网站所有。对于套用本教程代码非法爬取其他网站或公司非公开数据而导致的损害,本教程不承担任何责任。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容