History
I am new to Python and this is my first attempt. Utilizing a legal login (omitted from the code below) to the Bob and Tom VIP website, I have created this script to access their Full Show mp3. Using the couple of Python books I have and Googling StackExchange, I have been able to get this script to the rudimentary state, albeit working, it is in.
This is initially written to run in IDLE while testing and then to have the input
portion removed to work via cron
on my fileserver.
Performance
While walking through each individual show page and downloading the mp3, the script does not take long; I am using a single Session()
. I would image extracting all the notes and links for each instance into a dict
would increase the process, but it is still limited to the speed of the connection. I'm not sure if the iGate
variable for the POST will allow multiple instances.
Note: username, password, and (possibly) identifying iGate value from myurl has been removed.
Code
"""
Webscraping Bob and Tom for Full Show and mp3.
"""
import requests
from bs4 import BeautifulSoup
from datetime import datetime, timedelta, date
from dateutil.rrule import DAILY, rrule, MO, TU, WE, TH, FR
import os
#import eyed3 #failed to install with Python devel ver
# set Bob and Tom login and basic information
usr = 'real usr removed'
pwd = 'real pwd removed'
myurl = 'https://members.bobandtom.com/pcd/egate?iGATE=real iGate removed'
login_url = 'https://members.bobandtom.com/pcd/eGateChk'
vip_url = 'http://vip.bobandtom.com/'
usr_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/62.0.3202.94'
# check which Operating System we are running on to set valid directory
if (os.name == 'nt'):
mp3dir = 'z:\\Music\\0 BobandTom'
else:
mp3dir = '/media/Music/0 BobandTom/'
# establish login session with VIP website
s = requests.Session()
hdrs = { 'User-Agent' : usr_agent }
s.headers.update(hdrs)
r = s.get(myurl)
soup = BeautifulSoup(r.content, 'html.parser')
# get iGate string
gate_val = soup.find('input', {'name' : 'iGate'}).get('value')
# establish payload for login
login_dict = { 'iGate' : gate_val,
'iType' : 'MAIN',
'iUserName' : usr,
'iPassword' : pwd }
# establish headers for login
hdrs = { 'Host' : 'members.bobandtom.com',
'Referrer' : myurl,
'Content-type' : 'application/x-www-form-urlencoded' }
# post login information
r = s.post(login_url, headers = hdrs, data = login_dict)
# START the local determination
# puts files into sorted list from directory if they exist
mp3list = sorted([f for f in os.listdir(mp3dir)
if os.path.splitext(f)[1] == '.mp3'])
# set the next mp3 we want to dowload
if not mp3list:
print("There are no MP3s in your directory.")
mp3want = str(input("What MP3 do you wish to start with [format YYYYMMDD]? "))
print("Attempting to download " + mp3want + ".mp3")
start_date = date(int(mp3want[:4]),
int(mp3want[4:6]),
int(mp3want[-2:]))
else:
mp3last = mp3list[-1] # last mp3 in our directory
print("Attempting to dowload all MP3s after " + (mp3last) + ".")
mp3want = mp3last.split(sep='.mp3', maxsplit=1)[0] # is str
start_date = date(int(mp3want[:4]),
int(mp3want[4:6]),
int(mp3want[-2:])) + timedelta(days=1)
# set last mp3 to download (the day before today)
end_date = date.today() - timedelta(days=1)
# generate the dates from start to end (weekdays only)
def daterange(start_date, end_date):
return rrule(DAILY, dtstart=start_date,
until=end_date, byweekday=(MO,TU,WE,TH,FR))
# create dates and put them in list (format: 2017/09/01/september-1-2017/)
date_links = []
for d_string in daterange(start_date, end_date):
if (os.name == 'nt'):
date_links.append(d_string.strftime("%Y/%m/%d/%B-%#d-%Y/").lower())
else:
date_links.append(d_string.strftime("%Y/%m/%d/%B-%-d-%Y/").lower())
# create list with full urls
showpage_htmls = [vip_url + date_link for date_link in date_links]
# START the d/l process
# within session, process through direct to show pages
for show_html in showpage_htmls:
try:
p_html = s.get(show_html)
p_soup = BeautifulSoup(p_html.content, 'html.parser')
# set title for SHOW NOTES
title = ''
title = p_soup.title.contents[0]
# get SHOW NOTES chunk and remove unwanted characters (original mp3notes not changed)
mp3notes = ''
mp3notes = p_soup.find('div', {'class': 'module-text'}).find('div')
mp3notes = str(title) + str('\n') + str(mp3notes).replace('<div>','').replace('<h2>','').replace('</h2>','\n').replace('<p>','').replace('<br/>\n','\n').replace('<br/>','\n').replace('</p>','').replace('</div>','').replace('\u2032','')
# set basename, mp3named and mp3showtxt
mp3basename = '{0}{1}{2}'.format(show_html.split('/')[3],show_html.split('/')[4],show_html.split('/')[5])
if (os.name == 'nt'):
mp3showtxt = mp3dir + '\\' + mp3basename + '.txt'
mp3named = mp3dir + '\\' + mp3basename + '.mp3'
else:
mp3showtxt = mp3dir + '/' + mp3basename + '.txt'
mp3named = mp3dir + '/' + mp3basename + '.mp3'
# save show notes to local
with open(mp3showtxt, 'w') as f:
try:
f.write(mp3notes)
print("Show notes " + mp3basename + " saved.")
except UnicodeEncodeError:
print("A charmap encoding ERROR occurred.")
print("Show notes for " + mp3basename + ".mp3 FAILED, but continuing")
finally:
f.close()
# FIXME need eyed3 to set mp3 tags since B&T are lazy
# get Full Show mp3 link
mp3url = p_soup.find('a', href = True, string = 'Full Show').get('href')
# get and save mp3
r = requests.get(mp3url)
with open(mp3named, 'wb') as f:
f.write(r.content)
print("Downloaded " + mp3basename + ".mp3.")
except AttributeError:
print(show_html + " did not exist as named.")
Expectations of review
- Suggestions for more efficient code, i.e.
class
ordef
usage(s). - Suggestions for trapping no show notes (
mp3showtxt
) found and skipping that d/l. - And of course any suggestions for improvement.
Thanks in advance for any and all input; it will help me continue learning.