Python采集JavaScript

/ 0评 / 0

    之前在上bilibili的时候就想通过python的采集办法来获取视频封面,但是在人工手动解读代码的时候发现了一些问题:BiliBili的主页由JS动态生成,当http去访问时还会重定向到https(主页),所以直接用BeautifulSoup采集的页面所得到的BeautifulSoup对象总是一个空值,并不能够完成采集。

    而书本所给的思路则是面对小批量的数据所产生的结果:

    python爬虫的最佳实践(五)--selenium+PhantomJS的简单使用

    而上面的这个方法试用性强但是模拟浏览器运行js得到结果这个过程应该很累吧,虽然一个无头浏览器PhantomJs配上自动测试工具Selenium算是最小预算了,但是如果面对大批量的评论、用户或者连接的话怕是效率不存在(因为我是老年机也不会干这种大批量的测试)。本来数据采集就是针对某一特性而进行分类管理和下载的方式,本着效率至上的原则一步一步去探究了(没学过js完全慌了)

    

哇,BILIBILI很调皮啊,直接在主体的第一行就写上了封面的位置,只不过象征性的写了一句display:none,这明显是开的后门。如果我从这个位置拿的话肯定是GET 200的状态拿到了。封面图片PNG/JPG。但是这句是JS渲染上去的属性,也就是说还是得用selenium(所以这是个被废弃的方案,待会做)这样一来则说明想从页面拿是行不通了。

    在上面尝试无果之后我换了种思路:之前的API


    其实在看到这些json格式的数据时候我就在想这些会是什么东西,挨个查看了之后发现了这些东西里包含了播放数目,已经加载的一些弹幕、评论以及相关视频的一些信息,还有bilibili自己的广告和站题什么的还有用户的头像。但是搜遍了整条街的json也没看见封面,我返回上一级试了试结果又是一堆没我想要的东西的json,我觉得是我打开方式不对,想看看bilibili的api文档结果还被墙了。

    然后三折腾四折腾找到了我想要的这个:http://www.bilibili.com/index/ding.json

    但是这是一个不定项选择题。并不是指哪取哪的,这样就很尴尬了。经过一番折腾之后我回过头发现,原来selenium也是很好用的的嘛(╮(╯▽╰)╭)于是进入正题:

强大的selenium+PhantomJS

    只能说是之前的我太年轻了。因为很多网站毕竟复杂了,可能不同需求就有着不同办法,但是终归能拿到手HTML代码就好操作了,所以有了上面的经历后(特别绝望)顺便查阅了一些相关的文档:当网页使用AJAX动态加载(PJAX也行)的时候我就很麻烦了。页面上有一些简单的文字, 是手工敲在 HTML 代码里的,打开页面两秒钟之后,页面就会被替换成一个Ajax 生成的内容。 如果用传统的方法采集这个页面,只能获取加载前的页面,而真正需要的信息( Ajax 执行之后的页面)却抓不到。然后就凉了。

    所以依旧是以上的问题。我们用老套但是非常强大的办法来解决吧:

    日常pycharm安装之后去官网下载这个无头浏览器(官网下载好慢啊)办妥这一切之后就很简单了

from bs4 import BeautifulSoup
from selenium import webdriver
import time
import re

driver = webdriver.PhantomJS(executable_path='C:/Users/Administrator/Desktop/phantomjs-2.1.1-windows/bin/phantomjs')
driver.get("https://www.bilibili.com/video/av12092863/index.html")
time.sleep(4)
pageSource = driver.page_source
bsObj = BeautifulSoup(pageSource,"html.parser")
images = bsObj.findAll("img", {"src": re.compile("//cdn.kelovp.tech/.*\.jpg")})
print "http:"+images[0].get("src")
driver.close()

    由于我自己失了志直接把压缩包解压在了桌面,所以webdriver的驱动路径也是在桌面,我让浏览器等4秒再去看看。然后把网页源码返回给我,生成beautifulsoup对象,然后就是老套路了。。

    

    封面图片直接搞定,这个组合意外的好用。

处理重定向

    这是之前采集就遇到的一个非常让我头疼的事情,这里区分一下:由于是客户端重定向是在服务器将页面内容发送到浏览器之前,由浏览器执行 JavaScript 完成的页面跳转,而不是服务器完成的跳转。当使用浏览器访问页面的时候,有时很难区分这两种重定向。由于客户端重定向执行很快,加载页面时你甚至感觉不到任何延迟,所以会让你觉得这个重定向就是一个服务器端重定向。但是, 在进行网络数据采集的时候,这两种重定向的差异是非常明显的。根据具体情况,服务器端重定向一般都可以轻松地通过 Python urllib 库解决,不需要使用 Selenium。客户端重定向却不能这样处理, 除非有工具可以执行JavaScript。说白了之前我写的程序的等待就是为了等这些个JS执行完毕再去采集,很难说这些东西什么时候执行完全,所以可以通过定时检查来看看页面是否发生了跳转。

    这里我没找到什么好的例子来执行,那书上的程序来测试吧:

from selenium import webdriver
import time
from selenium.webdriver.remote.webelement import WebElement
from selenium.common.exceptions import StaleElementReferenceException
def waitForLoad(driver):
    elem = driver.find_element_by_tag_name("html")
    count = 0
    while True:
        count += 1
        if count > 20:
            print("Timing out after 10 seconds and returning")
        return
    time.sleep(.5)
    try:
        elem == driver.find_element_by_tag_name("html")
    except StaleElementReferenceException:
            return
driver = webdriver.PhantomJS(executable_path='D:/phantomjs/bin/phantomjs')
driver.get("http://pythonscraping.com/pages/javascript/redirectDemo1.html")
waitForLoad(driver)
code = driver.page_source
driver.close()
print(code)

这个程序每半分钟检查一次网页,看看 html 标签还在不在,时限为 10 秒钟,不过检查的时间间隔和时限都可以根据实际情况随意调整。



发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注