js 爬虫抓取网页数据(爬虫之web自动化终极杀手-百度音乐(静态网页)分析)

优采云 发布时间: 2022-01-05 00:16

  js 爬虫抓取网页数据(爬虫之web自动化终极杀手-百度音乐(静态网页)分析)

  爬虫网络自动化的终极杀手

  2017/9/14 晚上 11:43:07

  带领:

  最近写了几个简单的爬虫,踩了几个深坑。这里总结一下,给大家写爬虫的一些思路。本爬虫的内容包括:静态页面的爬取。动态页面的爬行。网络自动化的终极爬虫。

  分析:

  数据获取(主要是爬虫)

  * 静态网页抓取

  * 动态网页抓取

  数据存储(python excel存储)

  * Python Excel 操作,保存结果

  实际数据获取:百度音乐(静态网页)

  分析步骤

  1、打开百度音乐:

  2.打开浏览器调试模式F12,选择Network+all模式

  

  3.在搜索框中搜索歌曲(beat it),查看控制台

  

  * 过滤请求:ctrl + f 输入搜索关键字

  * 根据请求界面的特点查看主要请求

  * 分析请求(请求头,查询字符串,响应)

  4.通过以上分析:获取有效信息:

  * 歌曲搜索请求界面为歌曲名称

  * 获取请求方法(post, get) 百度音乐搜索歌曲是获取请求

  * 请求头(假装浏览器避免被拒绝)

  * 请求返回结果(html 或 json) 百度音乐的返回结果为 html。

  5.通过有效信息设计爬虫,获取数据

  代码

  1.View提供了访问参数url并返回结果的方法

   def view(url):

'''

:param url: 待爬取的url链接

:return:

'''

# 从url中获取host

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': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',

'Accept-Encoding': 'gzip, deflate',

'Accept-Language': 'zh-CN,zh;q=0.8',

}

# 代理

proxies = {

"http": "dev-proxy.oa.com:8080",

"https": "dev-proxy.oa.com:8080",

}

# 利用requests封装的get方法请求url,并添加请求头和代理,获取并返回请求结果。并进行异常处理

try:

res = requests.get(url, headers=headers, proxies=proxies)

res.encoding = 'utf-8'

if res.status_code == 200:

# 请求成功

# 获取网页内容,并返回

content = res.text

return content

else:

return None

except requests.RequestException as e:

# 异常处理

print(e)

return None

  2 .search_baidu_song 提供参数song_name 搜索歌曲并获取搜索结果

   def search_baidu_song(song_name):

'''

获取百度音乐搜索歌曲结果

:param song_name: 待搜索歌曲名

:return: 搜索结果

'''

def analyse():

'''

静态网页分析,利用BeautifulSoup,轻松获取想要的数据。需要对html有了解。

:return:

'''

# 初始化BeautifulSoup对象,并指定解析器为 lxml。还有其他的解析器:html.parser、html5lib等

# 详细教程可访问:http://cuiqingcai.com/1319.html《Python爬虫利器二之Beautiful Soup的用法》

html = BeautifulSoup(content, "lxml")

# beautifulsoupzui常用方法之一: find_all( name , attrs , recursive , text , **kwargs )

# find_all() 方法搜索当前tag的所有tag子节点, 并判断是否符合过滤器的条件

# tag标签名为'div'的并且标签类名为class_参数(可为 str、 list、 tuple),

search_result_divs = html.find_all('div', class_=['song-item clearfix ', 'song-item clearfix yyr-song'])

for div in search_result_divs:

# find() 方法搜索当前tag的所有tag子节点, 并返回符合过滤器的条件的第一个结点对象

song_name_str = div.find('span', class_='song-title')

singer = div.find('span', class_='singer')

album = div.find('span', class_='album-title')

# 此部分需要对html页面进行分析,一层层剥开有用数据并提取出来

if song_name_str:

# 获取结点对象内容,并清洗

song_name_str = song_name.text.strip()

else:

song_name_str = ''

if singer:

singer = singer.text.strip()

else:

singer = ''

if album:

album = album.find('a')

if album:

# 获取标签属性值

# 方法二:属性值 = album['属性名']

album = album.attrs.get('title')

if album and album != '':

album = album.strip()

else:

album = ''

else:

album = ''

# print song_name + " | " + singer + " | " + album

songInfoList.append(SongInfo(song_name_str, singer, album))

songInfoList = []

url = urls.get('baidu_song')

url1 = url.format(song_name=song_name, start_idx=0)

content = self.view(url1)

if not content:

return []

analyse(content)

url2 = url.format(song_name=song_name, start_idx=20)

content = self.view(url2)

analyse(content)

return songInfoList[0:30]

  这样,我们就得到了百度网歌搜索结果的数据。然后就是保存数据,这个我们最后再说。

  网易云音乐(动态网页)

  当我们通过上述静态网页数据获取方式获取网易云音乐的数据时,可能会遇到这样一个问题:没有可查看网页源代码的数据,只有网页的骨架。数据根本找不到,但是当你打开开发者工具查看DOM树时,你可以找到你想要的数据。这时候我们遇到了动态网页,数据是动态加载的。无法获取网页数据。

  目前有两种解决方案:

  通过查看访问动态数据界面获取数据。使用网络自动化工具获取网页的源代码以获取数据。

  (目前网易云已经不能再单纯通过访问url获取数据,我们可以使用web自动化工具selenium和PhantomJS获取网页源代码。) 方案一的实现(通过查看访问动态数据接口获取数据) ):打开网易云音乐:打开浏览器调试模式F12,选择网络+所有模式

  

  在搜索框中搜索歌曲(击败它),检查控制台

  

  过滤请求是XHR,发现请求的名字是一样的。这时候我们看一下这些名字,就看到了Request URL中查找关键字搜索的请求。这个请求是一个 POST 请求。这应该是获取搜索数据的接口,通过查看响应或者预览来查看请求的返回结果。正是我们想要的。

  

  我们不要高兴得太早,我们还没有弄清楚Form Data是如何组成的。params + encSecKey 是如何生成的?我看过网络爬虫《如何爬取网易云音乐的评论?》》,得知网易对api做了加密,因为个人道教太浅,看不懂这里加密参数的顺序和内容,所以放弃了这个计划,我真的不甘心,只好改了到选项二。

  方案二实现:

  由于该解决方案暂时行不通,因此不会影响我们的工作进度。让我们改变我们的想法并继续前进。我想到了使用web自动化测试工具selenium来模拟浏览器的人工操作。用这种方式导出网页数据应该没有问题,我想马上去做。

  环境配置安装selenium

  建议自动使用python包管理工具:pip install -y selenium

  其他方法可以参考:selenium+python自动化测试环境搭建

  2. 安装 PhantomJS

  PhantomJS 是一个基于 webkit 的 JavaScript API。它使用 QtWebKit 作为其核心浏览器功能,并使用 webkit 编译、解释和执行 JavaScript 代码。你可以在基于 webkit 的浏览器中做的任何事情,它都能做到。它不仅是一个隐形浏览器,还提供CSS选择器,支持Web标准、DOM操作、JSON、HTML5、Canvas、SVG等,还提供处理文件I/O的操作,使可以对操作系统进行文件读写等。 PhantomJS 的用途非常广泛,比如网络监控、网页截图、无需浏览器的网页测试、页面访问自动化等。

  下载 PhantomJS

  目前官方支持三种操作系统,包括windows\Mac OS\Linux三种主流环境。可以根据自己的运行环境选择要下载的包

  3. 安装 PhantomJS

  下载完成后,解压文件,将phantomjs.exe放到pythond目录下(C:\Python27\phantomjs.exe)。这样后续的加载就不需要指定目录了。也可以放在特定目录下,使用时指定phantomjs.exe路径即可。双击打开phantomjs.exe,验证安装成功。如果出现下图,则安装成功。

  

  4.代码实现步骤:

   def dynamic_view(url):

'''

使用自动化工具获取网页数据

:param url: 待获取网页url

:return: 页面数据

'''

# 初始化浏览器driver

driver = webdriver.PhantomJS()

# 浏览器driver访问url

driver.get(url)

# 坑:不同frame间的转换(网易云在数据展示中会将数据动态添加到'g_iframe'这个框架中,如果不切换,会报"元素不存在"错误。)

driver.switch_to.frame("g_iframe")

# 隐式等待5秒,可以自己调节

driver.implicitly_wait(5)

# 设置10秒页面超时返回,类似于requests.get()的timeout选项,driver.get()没有timeout选项

driver.set_page_load_timeout(10)

# 获取网页资源(获取到的是网页所有数据)

html = driver.page_source

# 坑:退出浏览器driver,必须手动退出driver。

driver.quit()

# 返回网页资源

return html

  

   def search_163_song(song_name):

pass

  同样是使用BeautifulSoup对Web资源进行对象化,通过对象过滤来获取数据。没想到网易云音乐的数据也可以通过这种方式获取。如果你能做到这一点,你就可以应付大部分网站。

  选择 PhantomJS 是因为它不需要可视化页面,并且节省了内存使用。但是也有一个问题,请大家继续往下看。眼见为实。

  5. .Spotify

  解决方案:通过网络自动化获取数据。通过请求动态数据接口获取数据计划实现:

  方案一:

  使用web自动化工具获取数据:配置类似网易云配置,模拟用户操作浏览器打开网页,用户登录,进入搜索页面,获取页面数据

   def spotify_view(url):

'''

使用自动化工具获取网页数据

:param url: 待获取网页url

:return: 页面数据

'''

spotify_name = 'manaxiaomeimei'

spotify_pass = 'dajiagongyong'

spotify_login = 'https://accounts.spotify.com/en/login'

# 初始化浏览器driver

driver = webdriver.PhantomJS()

# 模拟用户登录()

# 浏览器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_class_name('ng-invalid-required')

# 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)

# 搜索打开歌曲url

driver.get(url)

time.sleep(5)

# 搜索获取网页代码

html = driver.page_source

return html

  

  点击运行后,一切都平静了。代码突然报错(如下图)。查了资料,修改了代码。

  

  网络开通计划

  在 input 元素中添加 clear() 以清除原创字符。更换浏览器

  方案实施:

  方案一:

  获取到对象后,添加清除对象的方法(username.clear(), password.clear())

  实施结果

  场景 1 失败。原因不明,大部分是webdriver与PhantomJS不兼容。

  场景2:

  换浏览器,这次选择使用chrome浏览器进行自动操作。

  安装chrome自动化控制插件。

   # 初始化浏览器driver

driver = webdriver.Chrome()

  我以为可以通过这种方式获得数据。Burning Goose,还是没有获得,报错(如下图)

  

  这里:您应该检查请求并找出令牌是什么。并尝试将令牌添加到请求标头中。

  

  查看 cookie

  

  但是我们登录后的cookie列表中并没有这样的cookie!

  

  预计这个cookie应该在网络播放器加载时植入。验证一下:

  

  从上表可以看出。当玩家加载时植入令牌。

  至此,问题已经解决了大半。

  继续“爬虫战斗:爬虫网络自动化的终极杀手(第​​ 2 部分)”

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线