Scrapy之PhantomJS , Selenium动态爬虫

简介

很多网页具有动态加载的功能,简单的静态页面爬虫对它就无能为力了。这时候就需要PhantomJS+Selenium两大神器

简单点说PhantomJS就是一个没有界面的浏览器,提供了JavaScript接口

PhantomJS在linux下的安装

先安装依赖包

sudo apt-get install build-essential g++ flex bison gperf ruby perl libsqlite3-dev libfontconfig1-dev libicu-dev libfreetype6 libssl-dev libpng-dev libjpeg-dev python libx11-dev libxext-dev

下载PhantomJS

wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2

官方下载超级慢, 可以使用下面的地址下载

https://bitbucket.org/ariya/phantomjs/downloads/

Selenium

Selenium是一个自动化的测试工具,这里主要用到了它的Webdriver操作浏览器。Selenium可以操作大多数主流浏览器(可能需要相应的驱动),当然也可以操作无界面的浏览器PhantomJS。 
直接pip安装:

pip3 install selenium

使用Selenium操作PhantomJS:

from selenium import webdriver

driver = webdriver.PhantomJS()    # 获取浏览器对象
driver.get('http://www.baidu.com/')
print driver.page_source

融合

简单说这三者的关系就是:Scrapy通过Selenium使用PhantomJS,爬取加载过JS的页面。

spider.py

在自定义的spider类里,我们要控制何时使用下载器中间件(默认所有请求都会经过中间件)。例如我需要先爬取文章列表页,再获取列表页里的文章页url,再以此爬取文章详情页。在爬取列表页时,不需要经过下载器中间件执行JS,而爬取正文页就需要经过加载过JS的页面。

class mySpider(Spider):
    name = 'myspider'
    start_urls = [....]

    def parse(self, response):
        """
        解析文章列表页
        """
        urls = response.xpath('.....')
        for url in urls:
            request = Request(url=url, callback=self.parse_post, dont_filter=True)
            request.meta['PhantomJS'] = True
            yield request

    def parse_post(self, response):  
         """
        解析文章正文页
        """    
        item = myItem()
        item['title'] = response.xpath('.....')  

对于每一个爬取详情页的request,我们都加上了一个PhantomJS的meta:

request.meta['PhantomJS'] = True

当请求经过下载器中间件时,检查请求中是否有这个meta,决定这个请求要不要使用中间件。

JSMiddleware.py

class PhantomJSMiddleware(object):
    @classmethod
    def process_request(cls, request, spider):

        if request.meta.has_key('PhantomJS'):
            driver = webdriver.PhantomJS() 
            driver.get(request.url)
            content = driver.page_source.encode('utf-8')
            driver.quit()  
            return HtmlResponse(request.url, encoding='utf-8', body=content, request=request)

下载器中间件首先判断请求是否需要经过中间件,然后用PhantomJS打开请求的url,将加载好JS的页面装入HtmlResponse,返回给spider继续处理。 
注意:如果把爬虫添加到定时任务,需要给phantomjs指定可执行文件的路径,因为crontab不会加载用户自定义的环境变量,比如

driver = webdriver.PhantomJS(executable_path='/usr/local/bin/phantomjs')
另外还要在setting.py中开启中间件:

DOWNLOADER_MIDDLEWARES = {
    'MySpider.middlewares.JSMiddleware.PhantomJSMiddleware': 100
}

大招

运用PhantomJS , Selenium的方式, 有点类似于使用代理的方式, Selenium会模拟一个ip去访问目标服务器网站, 但对于一些过滤固定ip的网站, 往往这部分请求会被过滤掉, 其实单独使用PhantomJS也是可以直接抓取网站的, 只是看起来不如PhantomJS, Selenium的方式优雅

下列js代码就是需要运行phantomg

保存为request.js文件。然后在当前目录下命令行运行:就会返回整个网页的源码,然后爬虫你懂得的小解析一下就可以抽取出xici代理的免费ip了

phantomjs request.js http://www.xicidaili.com/
/***********************************
code:javascript
system:win  ||  linux
auther: luyi
mail : [email protected]
github: luyishisi
blog: https://www.urlteam.org
date:2016.9.12
逻辑说明:使用phantomjs无界面浏览器作为操作平台,破解对方针对js解析的反爬虫辨别
************************************/
var page = require('webpage').create(),
    system = require('system'),
    address;
address = system.args[1];
 
//init and settings
page.settings.resourceTimeout = 30000 ;
page.settings.XSSAuditingEnabled = true ;
//page.viewportSize = { width: 1000, height: 1000 };
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36';
page.customHeaders = {
    "Connection" : "keep-alive",
    "Cache-Control" : "max-age=0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8,en;q=0.6",
};
page.open(address, function() {
  console.log(address);
  console.log('begin');
});
//加载页面完毕运行
page.onLoadFinished = function(status) {
  console.log('Status: ' + status);
  console.log(page.content);
  phantom.exit();
};

直接在工程中使用下面的代码获取抓取的页面

common = 'c://phantomjs/phantomjs' + ' requests.js '+ temp_url
str_body =  str(os.popen(common).read())
print str_body
发布了69 篇原创文章 · 获赞 8 · 访问量 9394

猜你喜欢

转载自blog.csdn.net/u011414629/article/details/103451885