简介
很多网页具有动态加载的功能,简单的静态页面爬虫对它就无能为力了。这时候就需要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