美文网首页Python爬虫pythonPython 开发
Python 爬虫 PhantomJs 获取JS动态数据

Python 爬虫 PhantomJs 获取JS动态数据

作者: Daemon1993 | 来源:发表于2016-01-26 11:54 被阅读38138次

    上篇文章我非常high的爬取了一个正常网页的数据
    对是正常

    不正常的来了

    这次研究的就是那些“不正常”的网页 当时是我太天真 后面发现水又深
    介于现在JS H5的大趋势 大部分网站都是混入了JS数据加载 数据是延迟加载的

    这样如果我们用原始的urllib.open(url) 加载出来的都是还没有加载js数据之前的 所以爆炸了

    所以按照上篇文章那么正常的提取数据显然不可取了 那毕竟那是静态的 战场上 敌人也不会像抗日神剧剧情一样让你当靶子不是

    我当时的想法就是要让让网页JS渲染数据加载完全了 我们才开始解析 这样才行 想想就行了 然而我并不会


    并不会

    后面查了一些资料

    • 无非两种实现
      1 分析JS源码 找出请求 自己模拟实现 难度比较高 麻烦
      2 模拟浏览器实现 三方库多 简单 但是效率会慢一点

    然后搜到了很多相关的库 这里使用的是 Selenium + PhantomJs 网上推荐比较多

    • Selenium是一个用于Web应用程序测试的工具
    • Phantom JS是一个服务器端的 JavaScript API 的 WebKit

    看了一下Selenium的Api 发现没有PhantomJS 他也可以使用FireFox来实现如同PhantomJs的功能
    介于网上都是推荐PhantomJS 所以我也这样实现
    Selenium就像一个大容器 里面放着PhantomJs来实现JS的渲染 我们直接操作Selenium的Api就行

    这次选取的目标是 淘宝模特的网站 为什么是这个呢 除了美女多


    美女多就够了

    还有就是我学习的资料就是用的这个
    Python学习的网站这个里面就是用这个作为实例
    但是这个后续可能因为淘宝改版了网站结构 他的例子不能成功 所以我才研究JS的动态加载

    开始套路 这里环境Windows
    1 安装Selenium 用Pip 安装 如果Pip不能被找到 记得设置环境变量Python/Script
    2 下载PhantomJs 然后将 解压后的执行文件放在被设置过环境变量的地方 不设置的话 后续代码就要设置 所以这里直接放进来方便


    Paste_Image.png

    这里检查一下

    Paste_Image.png

    能找到 说明Ok

    下面是全部实现代码

    官网的一些配置
    #coding=utf-8
    __author__ = 'Daemon'
    
    import urllib2,re,os,datetime
    from selenium import webdriver
    
    class Spider:
        def __init__(self):
            self.page=1
            self.dirName='MMSpider'
            #这是一些配置 关闭loadimages可以加快速度 但是第二页的图片就不能获取了打开(默认)
            cap = webdriver.DesiredCapabilities.PHANTOMJS
            cap["phantomjs.page.settings.resourceTimeout"] = 1000
            #cap["phantomjs.page.settings.loadImages"] = False
            #cap["phantomjs.page.settings.localToRemoteUrlAccessEnabled"] = True
            self.driver = webdriver.PhantomJS(desired_capabilities=cap)
    
        def getContent(self,maxPage):
            for index in range(1,maxPage+1):
                self.LoadPageContent(index)
    
    #获取页面内容提取
        def LoadPageContent(self,page):
            #记录开始时间
            begin_time=datetime.datetime.now()
            url="https://mm.taobao.com/json/request_top_list.htm?page="+str(page)
            self.page+=1;
    
            USER_AGENT='Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.130 Safari/537.36'
            headers = {'User-Agent':USER_AGENT }
    
            request=urllib2.Request(url,headers=headers)
            response=urllib2.urlopen(request)
    
            #正则获取
            pattern_link=re.compile(r'<div.*?class="pic-word">.*?<img src="(.*?)".*?'
                                r'<a.*?class="lady-name".*?href="(.*?)".*?>(.*?)</a>.*?'
                                r'<em>.*?<strong>(.*?)</strong>.*?'
                                r'<span>(.*?)</span>'
                                 ,re.S)
            items=re.findall(pattern_link,response.read().decode('gbk'))
    
            for item in items:
            #头像,个人详情,名字,年龄,地区
                print u'发现一位MM 名字叫%s 年龄%s 坐标%s'%(item[2],item[3],item[4])
                print u'%s的个人主页是 %s'%(item[2],item[1])
                print u'继续获取详情页面数据...'
            #详情页面
                detailPage=item[1]
                name=item[2]
                self.getDetailPage(detailPage,name,begin_time)
    
        def getDetailPage(self,url,name,begin_time):
            url='http:'+url
            self.driver.get(url)
            base_msg=self.driver.find_elements_by_xpath('//div[@class="mm-p-info mm-p-base-info"]/ul/li')
            brief=''
            for item in base_msg:
                print item.text
                brief+=item.text+'\n'
                #保存个人信息
            icon_url=self.driver.find_element_by_xpath('//div[@class="mm-p-model-info-left-top"]//img')
            icon_url=icon_url.get_attribute('src')
    
            dir=self.dirName+'/'+name
            self.mkdir(dir)
    
        #保存头像
            try:
                self.saveIcon(icon_url,dir,name)
            except Exception,e:
                print u'保存头像失败 %s'%e.message
    
        #开始跳转相册列表
            images_url=self.driver.find_element_by_xpath('//ul[@class="mm-p-menu"]//a')
            images_url=images_url.get_attribute('href')
            try:
                self.getAllImage(images_url,name)
            except Exception,e:
                print u'获取所有相册异常 %s'%e.message
    
            end_time=datetime.datetime.now()
            #保存个人信息 以及耗时
            try:self.saveBrief(brief,dir,name,end_time-begin_time)
            except Exception,e:
                print u'保存个人信息失败 %s'%e.message
    
    
    #获取所有图片
        def getAllImage(self,images_url,name):
            self.driver.get(images_url)
        #只获取第一个相册
            photos=self.driver.find_element_by_xpath('//div[@class="mm-photo-cell-middle"]//h4/a')
            photos_url=photos.get_attribute('href')
    
            #进入相册页面获取相册内容
            self.driver.get(photos_url)
            images_all=self.driver.find_elements_by_xpath('//div[@id="mm-photoimg-area"]/a/img')
    
            self.saveImgs(images_all,name)
    
    
        def saveImgs(self,images,name):
            index=1
            print u'%s 的相册有%s张照片, 尝试全部下载....'%(name,len(images))
    
            for imageUrl in images:
                splitPath = imageUrl.get_attribute('src').split('.')
                fTail = splitPath.pop()
                if len(fTail) > 3:
                    fTail = "jpg"
                fileName = self.dirName+'/'+name +'/'+name+ str(index) + "." + fTail
                print u'下载照片地址%s '%fileName
    
                self.saveImg(imageUrl.get_attribute('src'),fileName)
                index+=1
    
    
        def saveIcon(self,url,dir,name):
            print u'头像地址%s %s '%(url,name)
    
            splitPath=url.split('.')
            fTail=splitPath.pop()
            fileName=dir+'/'+name+'.'+fTail
            print fileName
            self.saveImg(url,fileName)
    
        #写入图片
        def saveImg(self,imageUrl,fileName):
            print imageUrl
            u=urllib2.urlopen(imageUrl)
            data=u.read()
            f=open(fileName,'wb')
            f.write(data)
            f.close()
    
        #保存个人信息
        def saveBrief(self,content,dir,name,speed_time):
            speed_time=u'当前MM耗时 '+str(speed_time)
            content=content+'\n'+speed_time
    
            fileName=dir+'/'+name+'.txt'
            f=open(fileName,'w+')
            print u'正在获取%s的个人信息保存到%s'%(name,fileName)
            f.write(content.encode('utf-8'))
    
    #创建目录
        def mkdir(self,path):
            path=path.strip()
            print u'创建目录%s'%path
            if os.path.exists(path):
                return False
            else:
                os.makedirs(path)
                return True
    
    spider=Spider()
    #获取前5页
    spider.getContent(5)
    

    效果如下 只获取了第一个相册的第一页的 如果要全部的 还要涉及到模拟下滑加载更多这里先不作了解:

    Paste_Image.png Paste_Image.png

    妹子不得来告我吧

    闭着眼睛删除

    声明一遍 如果有不能展示的 联系我 我会删掉的。。。


    Paste_Image.png

    现在来分析一下 实现过程

    • 第一页 任务列表 正常网页 看看结构 来用正则获取任务详情页面
    Paste_Image.png Paste_Image.png
    • 页面详情 使用PhantomJS 来加载 然后根据Xpath来获取 XPath是个宝贝啊 特别好用很粗暴一下子可以拿到想要的
    粗暴提取

    上篇文章有相关资料 不做详细分析 这个丑丑的正则

    1. 基本信息获取 观察结构



      对应的代码


      获取基本信息
    2. 然后头像也是一样


      Paste_Image.png
      获取头像
    3. 获取相册地址 进入相册页面



      获取相册链接

    4. 最后在相册里面获取第一页展示的

    相册列表结构分析 拿到相册数据 下载相册内容

    到此结束 保存相关信息的代码 上面也给出了 这里不做详细说明

    基本分析 就是用google浏览器的F12 来分析结构 然后 抽取内容 感觉Python 相关资料很少啊 尤其是中文的
    这个PhantomJs 之所以这里给出分享过程 因为我确实在Google 知乎(度娘更不用说了)上面搜索相关资料很少 别人也就说用这个 也没说咋用 对于新手来讲 还是希望能有一个完整的过程分析

    嘿嘿嘿

    写的时候听的歌
    我等到花儿都谢了
    我睡不着的时候会不会有人陪着我
    我难过的时候会不会有人安慰我
    我想说话的时候会不会有人了解我
    我忘不了你的时候你会不会来疼我

    不会

    联系方式965204390@qq.com

    相关文章

      网友评论

      • Hx5u6p:嘿嘿嘿
      • 0133f3090916:好文.
      • 3ae2578af453:为什么我看https://mm.taobao.com/self/model_info.htm?user_id=687471686&is_coment=false这个页面是可以直接爬取的啊,就是静态的啊
      • CSU_IceLee:楼主,是不是用phantomjs就可以啦 不需要selenium吗?我想在服务器上跑爬虫,但是服务器没有图形化界面,所以没法用selenium
        CSU_IceLee: @Daemon1993 恩恩 找到了 不过发现这两个搭配起来速度有点慢啊
        Daemon1993:@CSU_IceLee phantomjs 本来就是一组api 应该是可以直接在服务器上运行的 可以看看官方文档 http://phantomjs.org/api/
      • d24f126fea97:淘宝网页改版了,请问楼主改版之后如何获取相册,能更新一下代码吗?
      • neobuger:非常感谢,也是找了好多资料,没有讲怎么具体使用的, 看了你的文章写的很详细, 虽然是没弄明白... - -! 慢慢消化吧~
      • e5af08581047:楼主你好, 程序运行到下面的时候,获取不到当前的网页内容了,改怎么办
        getDetailPage:
        self.driver.get(url)

        获取到的url 是//mm.taobao.com/self/model_card.htm?user_id=74386764
        然后经过组装变成 http://mm.taobao.com/self/model_card.htm?user_id=74386764
        但是这个url 使用 self.driver.get(url) 这个方法,获取不到任何内容,
        返回的是 :
        about:blank
        e5af08581047:还是自己回答吧, 这个url是无效的url,获取到之后,需要截取后面的user_id 等内容,然后自己重新拼接一个url地址就OK了
      • f8cbc3f2d15d:楼主你好,最近使用selenium+phantomjs爬天眼查时发现得到的数据不正确,但是用chromedriver的时候就正常了。请问这是什么问题,该怎么解决呢?
      • 648be709528c:默默收藏
      • fe887616b2bf:大神 我想问一下 找不到js地址的怎么办,像京东商品的商品评价,开始时不加载,我也不知道它什么时候加载的,能给分析一下吗
      • 48ea72c6854e:我想爬网站的价格,但是价格在查看源代码的时候显示成变量或者符号,这也可以用你这种方式解决吗
      • 84f0804de463:盛赞,博主想问下,该页面”https://mm.taobao.com/json/request_top_list.htm?page=“是怎么分析得到的?非常感谢
        Daemon1993:@七仔a186 对啊 这个也是动态加载 就用PhantomJS 载入 然后用根据F12之后看到的节点结构 用正则表达式或者Xpath 获取就行了吧 有啥问题吗?
        84f0804de463:@Daemon1993 噢,soga~ 因为最近遇到了一个问题,可以帮忙看下么,下面页面的排名数据获取:http://score.5211game.com/arena/user_rank/index.html,谢谢啦(*^__^*)
        Daemon1993:@七仔a186 我也是学习的时候看别人的博客用的这个 不过没得动态加载的 就自己实现了动态的 :cry:
      • 3493646c2bf2:我也静静看:wink:
        3493646c2bf2:@Daemon1993 你就如此对待你的粉丝吗:wink:
        Daemon1993:@胡艳蓉 :sweat:
      • 到底是:呵呵呵呵我就喜欢看你静静的装b
        Daemon1993:@37b56aeceb38 花爷?

      本文标题:Python 爬虫 PhantomJs 获取JS动态数据

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