前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爬虫实战 : 爬虫之 web 自动化终极杀手(下)

爬虫实战 : 爬虫之 web 自动化终极杀手(下)

原创
作者头像
serena
修改2021-08-03 14:56:10
3.9K0
修改2021-08-03 14:56:10
举报
文章被收录于专栏:社区的朋友们社区的朋友们

作者:陈象

接《 爬虫实战:爬虫之 web 自动化终极杀手 ( 上)

再理一下方案步骤:

  1. 模拟用户登录
  2. 进入个人播放页
  3. 获取cookies
  4. 获取token cookie,并将其添加到headers中。
  5. 请求页面,获取数据

代码

代码语言:txt
复制
  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仅针对获取数据的部分进行更改,使用访问数据接口,获取数据并解析。

实现步骤:

  1. 获取登录并进入播放页获取token,和其他cookies
  2. 请求数据接口
  3. 解析返回数据

代码实现:

代码语言:txt
复制
  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

  • open_workbook(filename) 读取excel文件,返回excel对象
  • sheet_by_index(sheetx) 根据工作sheet下标读取,返回sheet对象
  • sheet_by_name(sheet_name) 根据工作sheet名字读取,返回sheet对象
  • sheet.nrows 工作sheet行数
  • row_values(rowx, start_colx=0, end_colx=None),返回rowx行

数据(list)

  • xlwt:写excel
  • xlwt.Workbook(encoding=’utf-8’) 创建一个excel表格对象,指定编码方式,建议windows用户开启。
  • add_sheet(sheet_name) 添加一个sheet
  • write(r, c, label=””) 向sheet写入数据
  • write_merge(r1, r2, c1, c2, label=””) 向sheet合并单元格并写入数据,前四个参数控制区块:起始行 结束行 起始列 结束列

避免给同一个单元格重复写内容

基于此我们就可以将获取到的数据进行保存了。

excel表格操作代码:

代码语言:txt
复制
  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

主程序:

代码语言:txt
复制
  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()

[1505720129947_6778_1505720130335.png]
[1505720129947_6778_1505720130335.png]

本文采用根据完成功能进行的学习,并逐步完善代码,本文记叙了我完成这个项目的过程,目前只关注功能的实现,对于工具原理并未涉及过多。在本次爬虫编写中,主要遇到的问题是在网易云音乐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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据存储实战
  • 涉及的环境和工具:
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档