Plus是一个介绍数学之美与实际应用的网络杂志,其中包含了数学知识、轶闻趣事、历史典故等许多精彩的内容。该杂志恰好有一个Podcast栏目,提供了不少采访与讲座的mp3音频。于是, 我使用Python脚本将所有的Podcast文件都下载了下来,用于上下班路途上不适宜看书的时候听。

该脚本引入了四个模块:

  • re用于正则表达式匹配,将Podcast标题转为音频文件名。这是由于Linux系统下的文件名应避免包含字符/><|:&。所以,如果Podcast标题包含了这些字符,就需要将它们替换掉。

  • shutil用于将从网络上下载的音频数据流转存为本地文件。

  • requests用于向网站服务器发出GET请求,以获取HTML页面。

  • html.parser用于解析得到的HTML页面内容,从中匹配并提取出感兴趣的内容,包括Podcast子页面的链接,mp3文件的url等。使用时,需要由该模块中的HTMLParser类派生出子类,重写其中的成员函数handle_starttaghandle_data,即可以实现对HTML标签及其属性与包含的内容进行提取与处理。

具体代码如下:

import re
import shutil
import requests
from html.parser import HTMLParser # Remove characters unsuitable to be used in a file name.
def StringToFileName(s):
s = s.replace('#', 'No.')
s = re.sub('[?]', '', s)
s = re.sub('[&+$*!@%^|<>/]', '_', s)
s = re.sub(':\s*', '-', s) return s # Class for parse podcast main page and localize the links to subpages.
class PlusPodcastPageParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self) self.root_url = 'https://plus.maths.org'
self.subpage_url_list = list()
self.subpage_title_list = list() self.is_subpage_div_found = False
self.is_subpage_span_found = False
self.is_subpage_link_found = False def handle_starttag(self, tag, attrs):
if (not self.is_subpage_link_found and not self.is_subpage_div_found and tag == 'div'):
if (len(attrs) > 0):
for attr in attrs:
if (attr[0] == 'class' and attr[1] == 'views-field views-field-title'):
self.is_subpage_div_found = True
break
elif (not self.is_subpage_link_found and self.is_subpage_div_found and tag == 'span'):
if (len(attrs) > 0):
for attr in attrs:
if (attr[0] == 'class' and attr[1] == 'field-content'):
self.is_subpage_span_found = True
break
elif (not self.is_subpage_link_found and self.is_subpage_span_found and tag == 'a'):
if (len(attrs) > 0):
for attr in attrs:
if (attr[0] == 'href'):
self.is_subpage_link_found = True
self.subpage_url_list.append(self.root_url + attr[1])
break def handle_data(self, data):
if (self.is_subpage_link_found):
podcast_file_name = StringToFileName(data)
self.subpage_title_list.append(podcast_file_name) # Reset pattern searching flags and prepare for the next search.
self.is_subpage_div_found = False
self.is_subpage_span_found = False
self.is_subpage_link_found = False # Class for parse podcast subpage which contains the mp3 file.
class PlusPodcastSubpageParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self) self.root_url = 'https://plus.maths.org'
self.podcast_url = '' self.is_subpage_div_found = False
self.is_subpage_span_found = False
self.is_podcast_link_found = False def handle_starttag(self, tag, attrs):
if (not self.is_podcast_link_found and not self.is_subpage_div_found and tag == 'div'):
if (len(attrs) > 0):
for attr in attrs:
if (attr[0] == 'class' and attr[1] == 'field-item even'):
self.is_subpage_div_found = True
break
elif (not self.is_podcast_link_found and self.is_subpage_div_found and tag == 'span'):
if (len(attrs) > 0):
for attr in attrs:
if (attr[0] == 'class' and attr[1] == 'file'):
self.is_subpage_span_found = True
break
elif (not self.is_podcast_link_found and self.is_subpage_span_found and tag == 'a'):
if (len(attrs) > 0):
for attr in attrs:
if (attr[0] == 'href'):
self.is_podcast_link_found = True
self.podcast_url = attr[1]
break number_of_podcast_pages = 16
mp3_file_counter = 1 for page_idx in range(0, number_of_podcast_pages):
if (page_idx > 0):
page_url = 'https://plus.maths.org/content/podcast?page=' + str(page_idx)
else:
page_url = 'https://plus.maths.org/content/podcast' response = requests.get(page_url)
if (response.status_code == 200):
current_page = response.text
del response
page_parser = PlusPodcastPageParser()
page_parser.feed(current_page) if (len(page_parser.subpage_url_list) == len(page_parser.subpage_title_list)):
# Iterative over each found subpage url.
for subpage_idx in range(len(page_parser.subpage_url_list)):
response = requests.get(page_parser.subpage_url_list[subpage_idx])
if (response.status_code == 200):
current_subpage = response.text
del response
subpage_parser = PlusPodcastSubpageParser()
subpage_parser.feed(current_subpage) if (len(subpage_parser.podcast_url) > 0):
print ('*** Downloading ' + subpage_parser.podcast_url + ' ...')
response = requests.get(subpage_parser.podcast_url, stream = True)
with open(str(mp3_file_counter) + '-' + page_parser.subpage_title_list[subpage_idx] + '.mp3', 'wb') as mp3_file:
shutil.copyfileobj(response.raw, mp3_file)
del response mp3_file_counter = mp3_file_counter + 1
else:
print ('Cannot get the podcast subpage: ' + page_parser.subpage)
else:
print ('The numbers of subpage urls and titles should be the same!')
else:
print ('Cannot get the podcast page: ' + page_url)

运行该程序,稍等片刻,就可以得到所有的Podcast资源了。

使用Python批量下载Plus上的Podcast的更多相关文章

  1. python——批量下载图片

    前言 批量下载网页上的图片需要三个步骤: 获取网页的URL 获取网页上图片的URL 下载图片 例子 from html.parser import HTMLParser import urllib.r ...

  2. 用Python批量下载DACC的MODIS数据

    本人初次尝试用Python批量下载DACC的MODIS数据,记下步骤,提醒自己,数据还在下载,成功是否未知,等待结果中...... 若有大佬发现步骤有不对之处,望指出,不胜感激. 1.下载Python ...

  3. 8行代码批量下载GitHub上的图片

    [问题来源] 来打算写一个的小游戏,但是图片都在GitHub仓库中,GitHub网页版又没有批量下载图片的功能,只有单独一张一张的下载,所以自己就写了个爬虫脚本模拟人的操作把整个页面上需要的图片爬取下 ...

  4. 用python批量下载图片

    一 写爬虫注意事项 网络上有不少有用的资源, 如果需要合理的用爬虫去爬取资源是合法的,但是注意不要越界,前一阶段有个公司因为一个程序员写了个爬虫,导致公司200多个人被抓,所以先进入正题之前了解下什么 ...

  5. python批量下载微信好友头像,微信头像批量下载

    #!/usr/bin/python #coding=utf8 # 自行下载微信模块 itchat 小和QQ496631085 import itchat,os itchat.auto_login() ...

  6. 用python批量下载贴吧图片 附源代码

    环境:windows 7 64位:python2.7:IDE pycharm2016.1 功能: 批量下载百度贴吧某吧某页的所有帖子中的所有图片 使用方法: 1.安装python2.7,安装re模块, ...

  7. Python 批量下载BiliBili视频 打包成软件

    文章目录 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那么针对这三类人,我给大家 ...

  8. Python - 批量下载 IIS 共享的文件

    1.说明 用 IIS 以WEB形式发布了本地文件夹,提供文件下载,并设置了访问权限:默认下载需要点击一个一个的下载,web界面如下: 3.脚本 执行脚本批量下载文件,会在当前目录创建文件夹,并压缩该文 ...

  9. python 批量下载图片

    #coding=utf-8import re,sysimport urllib def getHtml(url): page = urllib.urlopen(url) html = page.rea ...

随机推荐

  1. abp添加动态菜单

    abp中MenuDefinition封装了导航栏上的主菜单的属性,MenuItemDefinition则封装了子菜单的属性,子菜单可以引用其他子菜单构成一个菜单树. MenuDefinitio成员如下 ...

  2. 在vue中关于element UI 中表格实现下载功能,表头添加按钮,和点击事件失效的解决办法。

    因为在element 中表格是使用el-table的形式通过数据来支撑结构,所以,表格的样式没有自己写的灵活,所以有了没法添加按钮的烦恼.下面是解决的方法. 准备工作: 一.下载npm安装包两个 1. ...

  3. 原生js实现平滑滚动

    在以前的项目中有用到,在此整理一下: html部分 <span id="gotop">回到顶部</span> JS部分 // 使用requestAnimat ...

  4. 微信小程序授权登录

    目录 自定义授权页面 点击授权登录后出现微信自带的授权登录弹窗 <!--index.wxml--> <!-- 授权界面 --> <cover-view class='au ...

  5. jenkins+ant+jmeter接口测试

    <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl=" ...

  6. 使用scrapy选择器selector解析获取百度结果

    0x00 概述 需要成功安装scrapy,安装方法与本文无关,不在这多说. 0x01 配置settings 由于百度对于user-agent进行验证,所以需要添加. settings.py中找到DEF ...

  7. java构造方法的重载

    package test; public class Person { String name; int age; public Person() { System.out.println(" ...

  8. js同步、异步、延时、无阻塞加载

    一.同步加载 平常默认用的都是同步加载.如:<script src="http://yourdomain.com/script.js"></script> ...

  9. shell 批量远程主机执行命令

    [yunwei@Y24-209 ~]$cat ls.sh #!/bin/bash ip55=`cat ip1` for i in $ip55;do ping -c 1 $i if [ $? -eq 0 ...

  10. 【翻译】 Guice 动机——依赖注入的动机

    原文链接 动机 将所有的内容连接在一起时应用开发的一个单调乏味的部分.有几种方式来将数据.服务.presetntation类连接到一起.为了对比这些方法,我将为披萨订购网站编写账单代码: public ...