美文网首页菜鸟PythonPython开发
python爬虫的最佳实践(五)--selenium+Phant

python爬虫的最佳实践(五)--selenium+Phant

作者: Darkeril | 来源:发表于2016-05-05 19:51 被阅读52697次

    Ps:又到了我们的ps环节,不知道上次大家尝试的如何,这次我们将简单介绍如何使用selenium+PhantomJS来抓取异步加载的网页数据信息。当然,selenium是一个非常强大的自动化工具,可以做非常多的事,有兴趣的同学可以自行了解一下。

    这次我们的顺序稍稍变化一下,因为牵扯到配置环境。

    环境配置

    • selenium
      pip install -U selenium
      建议采用pycharm安装,别忘了我们这个强大的IDE
    • PhantomJS
      这个不同的操作系统有各自对应的版本,这是官网的下载页面http://phantomjs.org/download.html,去下载你对应操作系统版本的phantomjs.下载完后,解压缩可以看到在文件夹的bin目录下有对应的phantomjs的可执行文件,拷贝一份放入一个环境变量可以搜索到的地方,或者直接把phantomjs的bin目录加入环境变量即可~

    简单介绍一下PhantomJS,这是一个基于webkit的没有界面的浏览器,也就是它可以像浏览器解析网页,功能非常强大。但是据我测试。。解析的结果不一定和火狐或者chrome完全一样,但是完全够我们用。
    简单介绍一下selenium,这是一个web的自动测试工具,可以模拟人的操作。支持市面上几乎所有的主流浏览器,同时也支持PhantomJS这种无界面浏览器。

    因为selenium+Firefox或者Chrome太慢了,所以我们选用selenium+PhantomJS。
    想试试selenium+Firefox的同学直接下载最新版的Firefox即可,不需要插件,但是chrome的话需要一个插件叫chromedriver,我会放到群里,闲话不多说,gogogo!

    代码预览

    #coding:utf-8
    import unittest
    from selenium import webdriver
    from bs4 import BeautifulSoup
    
    
    class seleniumTest(unittest.TestCase):
        def setUp(self):
            self.driver = webdriver.PhantomJS()
    
        def testEle(self):
            driver = self.driver
            driver.get('http://www.douyu.com/directory/all')
            soup = BeautifulSoup(driver.page_source, 'xml')
            while True:
                titles = soup.find_all('h3', {'class': 'ellipsis'})
                nums = soup.find_all('span', {'class': 'dy-num fr'})
                for title, num in zip(titles, nums):
                    print title.get_text(), num.get_text()
                if driver.page_source.find('shark-pager-disable-next') != -1:
                    break
                elem = driver.find_element_by_class_name('shark-pager-next')
                elem.click()
                soup = BeautifulSoup(driver.page_source, 'xml')
    
        def tearDown(self):
            print 'down'
    
    if __name__ == "__main__":
        unittest.main()
    

    小伙伴们是不是惊奇的发现今天的代码怎么略不一样了~因为今天除了爬虫相关,顺道教大家一些python 的小知识~

    代码剖析

    import unittest
    什么是unittest呢?看字面意思估计大部分人已经懂了,就是单元测试的意思,这个库是python自带的给我们提供测试用的库,很好用,今天我顺道介绍一下这个库的简单使用。
    今天的这段代码是一个简单的测试用例
    class seleniumTest(unittest.TestCase):
    继承TestCase类,表明这是一个测试类。setup方法是初始化方法,在unittest的main方法调用之初执行,然后tearDown是在测试完成的时候执行,中间的每个方法必须以test开头。这是一些简单的规则,大概了解之后我们就可以开心的使用单元测试了~

    def setUp(self):
          self.dirver = webdriver.PhantomJS()
    

    首先在我们的setup方法中初始化我们的webdriver,如果你用的是pycharm就可以看到webdriver后面会有多种方法,可以创建火狐的,chrome等各种浏览器的webdriver。

    初始化完成之后开始解析,今天我们抓取斗鱼tv的房间信息,用浏览器打开http://www.douyu.com/directory/all,然后选择查看网页源代码,发现竟然可以直接在源码中看到房间信息,心中一喜,难道不是异步的方式么?这太好抓了,直接requests请求然后分析就可以了啊。紧接着再点开第二页,查看网页源代码。发现竟然和第一页一模一样,顿时失望,依然是采用的js异步的方式来加载数据的,只不过这次返回的不是json格式而直接是html。难道我们需要像上一章那样么?nono,今天我们直接使用PhantomJS模拟浏览器的访问过程,然后通过dirver.get方法获取浏览器加载完成后的源码。这样子无论是否异步,我们取到的source都是和我们在浏览器中看到的完全一样。是不是感觉简便了很多呢?

    dirver.get('http://www.douyu.com/directory/all')
    soup = BeautifulSoup(dirver.page_source, 'xml')
    

    这两句想必大家也能理解了,其实就是换了一种方式去获取到网页源码而已。这次连带js渲染出来的网页也都获取到了。接下来

     titles = soup.find_all('h3', {'class': 'ellipsis'})
     nums = soup.find_all('span', {'class': 'dy-num fr'})
     for title, num in zip(titles, nums):
          print title.get_text(), num.get_text()
    

    这段代码是在源码中取出我们想要的信息,可能同学们也发现了,这和我们第三节讲的不太一样,这是因为我们的解析方式换成了xml而不是原本的lxml了,lxml属于一种更加高效的解析模式,但是我为什么要更换呢。因为在我写这段代码的时候发生了一个小插曲,原本我也是用lxml的方式去解析的,但是发现每次只能解析出来32条信息,但是很明显斗鱼每个小分页里最少都有100多个房间,我查看了driver返回的page_source,发现没有问题,于是我想可能是beautifulsoup的解析出了问题,打印soup,发现只有源代码的一半,后面一半莫名奇妙丢失了。原本我以为是网页中有多个</html>标签导致解析出错,后来发现也不是这个问题,百度google很久也没有结果,所以只能换一种解析模式,当我换成xml的时候发现解析无误。暂时我也不知道原因,有兴趣的同学可以尝试解决一下这个问题。

    那么上面这段代码取出了我们需要的信息,beautifulsoup的find方法要是不了解的话可以参看官方文档。接下来:

    elem = driver.find_element_by_class_name('shark-pager-next') 
    elem.click() 
    soup = BeautifulSoup(driver.page_source, 'xml')
    

    第一行代码是webdriver里面带有的定位标签的方法,我们通过观察发现斗鱼页面中下一页这个标签只出现一次,并且是独立样式,所以我们直接通过class进行定位,取到这个控件,然后执行element的click()方法模拟鼠标点击,这样,页面就自动跳到了下一页,接着继续解析网页源码。

    if driver.page_source.find('shark-pager-disable-next') != -1: 
          break
    

    这段代码是跳出循环用的,什么时候跳出循环呢?我们通过观察发现,当到最后一页时候斗鱼下一页的标签就会变灰,如图所示:

    STU5R92IEHAZ{881KZ(72LD.png

    于是,我们发现了有个唯一的shark-pager-disable-next样式,那么我们只需要在源码中找这个样式,如果有则说明已经解析到最后一页,直接跳出循环结束程序就好~

    至此,今天的代码就讲解完毕了。有没有觉得比上次的观察法方便了很多呢?附带一提,有兴趣的通许可以吧今天代码中self.dirver = webdriver.PhantomJS()换成self.dirver = webdriver.Firefox(),看看会发生什么有趣的事情,我就不剧透了~

    写在最后

    惯例了,demo已经给你们了,也讲解完毕,现在需要你们自己实践了,去尝试抓取一下其他TV吧,推荐抓一下战旗,因为加载方式又和斗鱼完全不一样了,有挑战性点~下一节我们讲解如何在爬虫中使用多进程!

    附加部分

    一些seleium的小互动操作

    • 填入表单数据
    #coding:utf-8
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    
    driver = webdriver.Firefox()
    driver.get('https://www.baidu.com/')
    elem = driver.find_element_by_id('kw')
    elem.send_keys(u'爬虫')
    elem.send_keys(Keys.RETURN)
    print(driver.page_source)
    
    • 滚动致页面最下方
    #coding:utf-8
    from selenium import webdriver
    import time
    
    driver = webdriver.Firefox()
    driver.get('http://www.jianshu.com/collections')
    time.sleep(1)
    for i in range(10):
        dirver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
        time.sleep(1)
    

    使用selenium模拟人的操作行为,这次换成了火狐浏览器,可以看得更加清楚~

    有兴趣的同学可以加群498945822一起交流学习哦~~
    发现问题的同学欢迎指正,直接说就行,不用留面子,博主脸皮厚

    相关文章

      网友评论

      • 789f88991b67:我用phantomjs爬取js渲染的翻页,但是只能click一次,再次click就不行了
      • j4fan:楼主好,用phantomjs抓js页面遇到乱码怎么办呢?求回复,谢谢
      • 小幸运Q:弱弱的问一句......如果想给phathomjs动态切换代理的话该怎么办啊?(•̩̩̩̩_•̩̩̩̩)
      • jiang:很有帮助,谢谢!
      • 168954a01fbb:用beautifulsoup 只能抓静态的网页吧?
      • Morning遇到:我的代码是这样的
        driver = webdriver.PhantomJS(executable_path='D:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe')
        def search(keyword):
        url_keyword = urllib.parse.quote(keyword)
        url = "http://wzdig.pbc.gov.cn:8080/dig/ui/search.action?q=&quot; + url_keyword
        # url = "http://www.tianyancha.com/search/&quot; + url_keyword + "?checkFrom=searchBox"
        print(url)
        driver.get(url)
        soup = BeautifulSoup(driver.page_source, "lxml")
        print(soup)
        search("123")
        但是它运行出来的结果依然还是js界面,这个怎么弄,求大神指点
      • Garfield_Liang:楼主的QQ群现在都没有人在。。。
      • vansnowpea:主题写的是PhantomJS ,但截图用的是火狐浏览器吗?
      • c8cb05d0cde1:跟楼上有同样的情况出现...
      • 85751fc48454:出了点问题,一直返回:
        NoSuchElementException: Message: Error Message => 'Unable to find element with class name 'shark-pager-next''


        elem = driver.find_element_by_class_name("shark-pager-next")
        改成
        elem = driver.find_element_by_css_selector("#J-pager > a.shark-pager-next")
        之后就还是找不到。
        NoSuchElementException: Message: Error Message => 'Unable to find element with css selector '#J-pager > a.shark-pager-next'' :cold_sweat:
      • 谢小路:@Darkeril 发现个问题,获取的title 和 num 并不是对应的,原因是新秀直播的title 和 在线直播的title 属性值相同... :smiley: 写的很好...
        5f81c4f8cecd:那就不要用find_all方法啊,我用的是soup.select方法,可以是对应的
        谢小路:@Darkeril 嗯呢,好好挺好使的,之前我不太熟悉这个异步加载,总是构造url...
        Darkeril:@谢小路 只是写个例子,都是临时想起来抓个斗鱼,所以没做区分

      本文标题:python爬虫的最佳实践(五)--selenium+Phant

      本文链接:https://www.haomeiwen.com/subject/svzlrttx.html