【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
Python 实现 CNKI批量下载 和FireFox Extension 入门学习笔记
由于需要也是为了督促自己学习新的东西,我原本想要尝试着写一个爬虫程序,能够在cnki上自动得将论文进行批量下载,学习过程中遇到了诸多情况,cnki也真是专业,不得不佩服cnki的强大。
下面进入正题:
学习、实验环境:ubuntu 14.04
工具:Eclipse , FireFox, FireBug,HttpFox
编程语言:python, js, XUL
由于我是中山大学学生,使用校园网进入cnki进行下载是不用登录的,所以我也就没进行模拟登录等方面的实现,有需要的朋友可以使用splinter进行模拟登录,也算快速便捷哈。
首先我们要实现使用python对cnki的论文实现批量下载,我们首先要对客户端和服务器之间相互传递的信息进行了解,这里我第一次使用的是wireshark,但是这个工具虽然强大,但是真不利于我们进行分析,它抓取的是我们电脑端口的信息,而不能只抓取当前网页的,在多次尝试之后我选择了HttpFox进行数据包抓取:
如图我们可以发现cnki对一个下载进行了3此redirect,我们通过对获得的数据和再一次发送的数据对比可以发现:前一次获得的url就是下一次get的url,所以我们就可以写出下载部分的核心代码,只有一点点是自己写的,许多网上一搜就有。
# -*- coding: UTF-8 -*-
import sys
import urllib2
import cookielib
import string
import re
import time
cj = cookielib.CookieJar()
cookie_support = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
url = 'http://epub.cnki.net/kns/download.aspx?filename=MBnRwcDMudGaItiamtScHVzb2Y0ZrVWRCBjaykEVXRTOjV0QHxUcTh3KNFXbHBDTyQVMNR2cP9kYGh1SXZnQnp3b3I2YqBnbUJ3KSNnRvpEUwhWTVJjNKBDcXVnSmZUayMkRVJUdytCe1AjT1ImTYdWdth1RtlGb&tablename=CMFDLAST2013'
h = {
'Referer' : url,
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0'
}
r = urllib2.urlopen(urllib2.Request(url,headers = h))
r = urllib2.urlopen(urllib2.Request(r.geturl(),headers = h))
r = urllib2.urlopen(urllib2.Request(r.geturl(),headers = h))
r = urllib2.urlopen(urllib2.Request(r.geturl(),headers = h))
data = r.read()
print data
使用FireBug获取网页源代码,随意找几个下载图标的链接url粘贴到代码中试一试成功了。
下载部分的代码成功了,那下面就是,如何从cnki的网页中获取到下载的url了,在这部分的实现中,我原本想要使用纯python的实现,使用python写一个爬虫,直接上cnki进行抓取,但是具体实现的时候碰到了很大的问题,例如:1、爬虫网页动态生成的数据困难重重;2、cnki网页在浏览器显示的url一直都是:”http://epub.cnki.net/kns/brief/default_result.aspx”;3、我们需要的网页是放在一个iframe标签里面的,这就非常蛋疼了,一直没找到获取办法
在同学的提示下,我发现了也许FireFox Extension是可行的解决方案。
学习FireFox Extension的话首先需要能至少看懂XUL代码,然后基本的模范着写,然后呢,就得学会javascript了,当然也有不用js实现的插件,例如使用python写,那使用PyXPCOM,但是我还没学会,这里页不需要哈。
(一)FF extension总体认知
FF是基于mozilla内核的,其浏览器引擎功能主要由C语言实现,但其浏览器界面及其界面上的相关操作都是由JS和XUL完成的,这就是FF的强大之处,同时它也为大家提供了很好的扩展机制。
FF扩展的开发目录结构:
可以到官网上仔细看看。
FF的工作方式:
对于任何一种新的开发语言或环境,大家通常都试图去寻找程序的入口点。可以很负责任地跟大家说,任何编译型(解释型程序)开发语言的程序都有类似C中的Main函数、Java中的主类(public static void main函数)、C#中的入口函数(static void/int Main)等作为程序入口。
这里我们呢了解这些也就够了。
这里我的目录结构是:
--chrome
--content
--overlay.js
--sample.xul
--chrome.manifest
--install.rdf
其中install.rdf代码为:
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>sample@example.net</em:id>
<em:version>1.0</em:version>
<em:type>2</em:type>
<!-- Target Application this extension can install into,
with minimum and maximum supported versions. -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.5</em:minVersion>
<em:maxVersion>4.0.*</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>DownLoadPaper</em:name>
<em:description>A test extension</em:description>
<em:creator>Liang</em:creator>
<em:homepageURL>http://www.example.com/</em:homepageURL>
</Description>
</RDF>
chrome.manifest代码为
overlay chrome://browser/content/browser.xul chrome://sample/content/sample.xul
content sample chrome/content/
overlay.js代码为:
function getURL() {
if ( window.content.document.location.href != " {
alert("Worng address");
} else {
var myWin = window.content.document.getElementById('iframeResult').contentWindow;
var hre = myWin.document.getElementsByClassName('brief_downloadIcon');
var path = prompt("save address","eg. //****/****");
path = path + "/test.csv";
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
} catch (e) {
alert("no permisson...");
}
var file = Components.classes["@mozilla.org/file/local;1"] .createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(path);
if ( file.exists() == false ) {
file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420 );
}
var outputStream = Components.classes["@mozilla.org/network/file-output-stream;1"] .createInstance( Components.interfaces.nsIFileOutputStream );
outputStream.init( file, 0x04 | 0x08 | 0x20, 420, 0 );
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"] .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
for (var i = 0; i < hre.length; i++) {
converter.charset = 'UTF-8';
var convSource = converter.ConvertFromUnicode(hre[i].href+"\n");
var result = outputStream.write( convSource, convSource.length );
}
outputStream.close();
alert("File was saved in "+path);
}
}
sample.xul代码如下:
<?xml version="1.0"?>
<overlay id="sample"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript" src="overlay.js"/>
<menupopup id="menu_ToolsPopup">
<menuitem id="DownLoadPaper" label="DownLoadPaper" oncommand="getURL();"/>
</menupopup>
</overlay>
至此,这个粗糙的辅助插件就编写完了,将文件打包压缩成zip格式,然后改名后缀为.xpi,再拖入FF就能安装了,这里需要修改一下FF的权限,使得插件能够修改本地文件,这样,工具栏里会多出一个工具,点击就能把论文下载的URL下载到一个test.csv的文件里了,windows下的用户就不要存到C盘里哈。
完整python文件为:
# -*- coding: UTF-8 -*-
import sys
import urllib2
import cookielib
import string
import re
import time
f = open('test.csv', 'r')
i = 1
for line in f:
print line
try:
cj = cookielib.CookieJar()
cookie_support = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
url = line
refer = 'http://epub.cnki.net/kns/brief/brief.aspx?pagename=ASP.brief_default_result_aspx&dbPrefix=SCDB&dbCatalog=%e4%b8%ad%e5%9b%bd%e5%ad%a6%e6%9c%af%e6%96%87%e7%8c%ae%e7%bd%91%e7%bb%9c%e5%87%ba%e7%89%88%e6%80%bb%e5%ba%93&ConfigFile=SCDBINDEX.xml&research=off&t=1431252221059&keyValue=python&S=1'
h = {
'Referer' : refer,
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0'
}
r = urllib2.urlopen(urllib2.Request(url,headers = h))
r = urllib2.urlopen(urllib2.Request(r.geturl(),headers = h))
r = urllib2.urlopen(urllib2.Request(r.geturl(),headers = h))
r = urllib2.urlopen(urllib2.Request(r.geturl(),headers = h))
data = r.read()
if data[:8] == '[TARGET]':
with open(str(i)+".caa", "wb") as up:
up.write(data)
up.close
else:
with open(str(i)+".caj", "wb") as up:
up.write(data)
up.close
print str(i)+' '+'succeed'
time.sleep(2)
except:
print str(i)+' '+'failed'
i = i + 1
这样,将test.csv与python文件放于相同目录下,运行python文件就可以下载了。
来源:oschina
链接:https://my.oschina.net/u/1782684/blog/314857