作者:陈象
再理一下方案步骤:
代码
def login(driver):
spotify_name = 'manaxiaomeimei'
spotify_pass = 'dajiagongyong'
spotify_login = 'https://accounts.spotify.com/en/login'
spotify_overview = 'https://www.spotify.com/us/account/overview/'
# 模拟用户登录()
# 浏览器driver访问登录url
driver.get(spotify_login)
# 休息一下等待网页加载。(还有另一种方式:driver.implicitly_wait(3))
time.sleep(3)
# 获取页面元素对象方法(本次使用如下):
# find_element_by_id : 通过标签id获取元素对象 可在页面中获取到唯一一个元素,因为在html规范中。一个DOM树中标签id不能重复
# find_element_by_class_name : 通过标签类名获取元素对象,可能会重复(有坑)
# find_element_by_xpath : 通过标签xpath获取元素对象,类同id,可获取唯一一个元素。
# 获取页面元素对象--用户名
username = driver.find_element_by_id('login-username')
# username.clear()
# 坑:获取页面元素对象--密码
# 在通过类名获取标签元素中,遇到了无法定位复合样式,这时候可采用仅选取最后一个使用的样式作为参数,即可(稳定性不好不建议使用。尽量使用by_id)
# password = driver.find_element_by_class_name('form-control input-with-feedback ng-dirty ng-valid-parse ng-touched ng-empty ng-invalid ng-invalid-required')
password = driver.find_element_by_id('login-password')
# password.clear()
# 获取页面元素对象--登录按钮
login_button = driver.find_element_by_xpath('/html/body/div[2]/div/form/div[3]/div[2]/button')
# 通过WebDriver API调用模拟键盘的输入用户名
username.send_keys(spotify_name)
# 通过WebDriver API调用模拟键盘的输入密码
password.send_keys(spotify_pass)
# 通过WebDriver API调用模拟鼠标的点击操作,进行登录
login_button.click()
# 休息一下等待网页加载
driver.implicitly_wait(3)
def enter_web_player(driver):
'''
进入web 播放器
:param driver:浏览器控制对象
:return:
'''
# 请求个人信息页
spotify_overview = 'https://www.spotify.com/us/account/overview/'
driver.get(spotify_overview)
time.sleep(3)
web = driver.find_element_by_id('nav-link-play')
web.click()
time.sleep(3)
def spotify_view(song_name):
'''
使用自动化工具获取网页数据
:param url: 待获取网页url
:return: 页面数据
'''
# 初始化浏览器driver
driver = webdriver.Chrome()
# 用户登录
login(driver)
# 进入web播放页
enter_web_player(driver)
# 搜索打开歌曲url
spotify_song = 'https://open.spotify.com/search/results/{song_name}'
spotify_song = spotify_song.format(song_name=song_name)
driver.get(spotify_song)
time.sleep(5)
# 搜索获取网页代码并返回
html = driver.page_source
return html
通过上边的代码我们可以获取到网页完整的数据,再使用BeautifulSoup对源代码进行解析获取数据内容就可以了。可是在想一下。我们利用浏览器自动化进行操作的时候效率很低,相比于调用接口的方法获取数据慢很多,并且在对数据进行解析的时候会比较麻烦,到这里我准备使用第二个方案再次进行完成这个需求。不多说动手吧。
方案2:
在方案1的研究基础上,方案2仅针对获取数据的部分进行更改,使用访问数据接口,获取数据并解析。
实现步骤:
代码实现:
def get_cookies(driver):
'''
收集cookies
:param driver: 浏览器控制对象
:return: cookies字典
'''
# 从浏览器获取cookies
cookies = driver.get_cookies()
# 解析cookies并返回结果
cookies_dict = {}
for c in cookies:
cookies_dict[c['name']] = c['value']
return cookies_dict
def analyse(data ,songInfoList,albumInfoList):
# 获取response的json()
data = data.json()
# 解析json
songs = data.get('tracks', None)
albums = data.get('albums', None)
# 省略对json数据解析。注意判断None,将解析到是数据保存在两个list中即可。
def search_spotify_song(song_name):
'''
使用自动化工具获取网页数据
:param url: 待获取网页url
:return: 页面数据
'''
# 初始化浏览器driver
driver = webdriver.Chrome()
# 用户登录(同上)
login(driver)
# 进入web播放页(同上)
enter_web_player(driver)
# 获取cookies
cookies = get_cookies()
'''
搜索spotify歌曲,专辑
:param song_name: 待搜索歌曲名
:return: 歌曲、专辑搜索结果
'''
url = 'https://api.spotify.com/v1/search?type=album%2Cartist%2Cplaylist%2Ctrack&q={song_name}&decorate_restrictions=true&best_match=true&limit=50&market=from_token',
url = url.format(song_name=song_name)
protocol, s1 = urllib.splittype(url)
host, s2 = urllib.splithost(s1)
# 伪装浏览器,避免被kill
headers = {
'Host': host,
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36',
'Accept': 'application/json',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Origin': 'https://open.spotify.com',
'Referer': 'https://open.spotify.com/search/results/{song_name}'.format(
song_name=song_name.decode('utf-8')),
# 组装认证信息,解决token错误
'Authorization': 'Bearer %s' % cookies["wp_access_token"]
}
# 代理
proxies = {
"http": "dev-proxy.oa.com:8080",
"https": "dev-proxy.oa.com:8080",
}
try:
res = requests.get(url1, headers=headers, cookies=cookies, proxies=proxies)
if res.status.code == 200:
analyse(res ,songInfoList,albumInfoList)
except Exception, e:
print e
return songInfoList[0:30]
至此我们已经获取到了spotif平台的结果数据。同样获取到了网易和百度的数据信息。
到这里我们就需要将获取到的数据进行保存了。本次才用excel保存。
这里介绍两个excel操作库:
xlrd:读取excel
数据(list)
避免给同一个单元格重复写内容
基于此我们就可以将获取到的数据进行保存了。
excel表格操作代码:
def read_excel_by_name(self, file='file.xls', by_name=u'Sheet1'):
'''
根据名称获取Excel表格中的数据
:param file: Excel文件
:param by_name: 默认从Sheet1中取数据
:return: 返回表格数据(也可按照表格定义对象进行列于对象进行映射)
'''
# 打开excel表格
excel = Excel().open_excel(file)
# 获取工作Sheet
table = excel.sheet_by_name(by_name)
# 获取工作sheet行数
nrows = table.nrows # 行数
list = []
# 遍历每行数据进行读取
for rownum in range(0, nrows):
row = table.row_values(rownum)
if row:
search_str = row[1]
list.append(search_str)
# 返回结果list
return list
def create_excel(self):
'''
创建excel表格
'''
excel_file = xlwt.Workbook(encoding='utf-8')
def write_song(self, sheet, datas={}, l=1):
'''
写入数据到sheet中
:param sheet: 工作sheet
:param datas:待写入的数据
:param l: 开始行数
:return:
'''
max_l = 0
if l == 0:
sheet.write_merge(0, 1, 0, 0, u'查找歌曲名')
sheet.write_merge(0, 0, 1, 3, u'百度')
sheet.write(1, 1, u'歌曲名')
sheet.write(1, 2, u'歌手')
sheet.write(1, 3, u'专辑')
sheet.write_merge(0, 0, 4, 6, u'网易')
sheet.write(1, 4, u'歌曲名')
sheet.write(1, 5, u'歌手')
sheet.write(1, 6, u'专辑')
sheet.write_merge(0, 0, 7, 9, u'spotify')
sheet.write(1, 7, u'歌曲名')
sheet.write(1, 8, u'歌手')
sheet.write(1, 9, u'专辑')
else:
baidu_song = datas.get('baidu_song', {})
wangyi_song = datas.get('wangyi_song', {})
spotify_song = datas.get('spotify_song', {})
if len(baidu_song) > 0:
ll = l
for data in qq_music_song:
sheet.write(ll, 1, data.song_name.encode('utf8'))
sheet.write(ll, 2, data.singer.encode('utf8'))
sheet.write(ll, 3, data.album.encode('utf8'))
ll += 1
if max_l < ll:
max_l = ll
if len(wangyi_song) > 0:
ll = l
for data in xiami_song:
sheet.write(ll, 4, data.song_name.encode('utf8'))
sheet.write(ll, 5, data.singer.encode('utf8'))
sheet.write(ll, 6, data.album.encode('utf8'))
ll += 1
if max_l < ll:
max_l = ll
if len(spotify_song) > 0:
ll = l
for data in wangyi_song:
sheet.write(ll, 7, data.song_name.encode('utf8'))
sheet.write(ll, 8, data.singer.encode('utf8'))
sheet.write(ll, 9, data.album.encode('utf8'))
ll += 1
if max_l < ll:
max_l = ll
主程序:
def main():
# 数据写入开始行
start_line = 2
# 数据写入结束行
end_line = 2
# 读取待搜歌歌曲名excel
list = read_excel_by_name(file='search_song.xls', sheet='song')
# 创建搜索结果excel
excel = create_excel()
# 添加工作sheet, 名为 music
song_sheet = excel.add_sheet(u'music')
# 写入表格标题栏
write_song(song_sheet, l=0)
# 遍历待搜索歌曲名。并存储搜索结果。
for song in list:
baidu_song = search_baidu_song(song)
wangyi_song = search_163_song(song)
spotify_song = search_spotify_song(song)
song_datas = {
'baidu_song': baidu_song if baidu_song else {},
'wangyi_song': wangyi_song if wangyi_song else {},
'spotify_song': spotify_song if spotify_song else {}
}
# 写入单个单元格
end_line = write_song(song_sheet, datas=song_datas, l=start_line)
if start_line <= end_line:
# 合并写入单元格
song_sheet.write_merge(start_line, end_line, 0, 0, name)
start_line = end_line + 1
结果excel()
本文采用根据完成功能进行的学习,并逐步完善代码,本文记叙了我完成这个项目的过程,目前只关注功能的实现,对于工具原理并未涉及过多。在本次爬虫编写中,主要遇到的问题是在网易云音乐url加密解析的理解和破解能力。在上文贴出的代码可能有运行不成功的可能,这是从项目提取出来的相关代码。 如有错误请多多指教!
python 2.7.13:开发环境
Pychcharm:IDE
pip包管理工具:python 包管理工具
urllib库:python内置的HTTP请求库
requests库:封装后的urllib库,使用更加方便
Beautiful Soup库:提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。
selenium库:可以模拟真实浏览器,自动化测试工具,支持多种浏览器,爬虫中主要用来解决JavaScript渲染问题。
PhantomJS浏览器:PhantomJS是一个基于webkit的JavaScript API。它使用QtWebKit作为它核心浏览器的功能,使用webkit来编译解释执行JavaScript代码。
ChromeDriver驱动:ChromeDriver是Chromium team开发维护的,它是实现WebDriver有线协议的一个单独的服务。ChromeDriver通过chrome的自动代理框架控制浏览器。
xlrd库:excel读取工具
xlwt库:excel写入工具
9/17/2017 2:25:41 PM 完
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。