Python 爬虫 PhantomJs 获取JS动态数据

Python 爬虫 PhantomJs 获取JS动态数据

字数2034 阅读2900 评论16 

上篇文章我非常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 知乎(度娘更不用说了)上面搜索相关资料很少 别人也就说用这个 也没说咋用 对于新手来讲 还是希望能有一个完整的过程分析


没有更多推荐了,返回首页