尝试收集学校项目的图书价格波动数据。我使用Python从书籍回购聚合器(在本例中为bookscouter)中删除,但我发现由于网站必须加载数据,因此通过urllib2包获取源代码可以得到源代码在加载数据之前。加载数据后如何从中拉出来?
示例:http://bookscouter.com/prices.php?isbn=9788498383621&searchbutton=Sell
答案 0 :(得分:1)
挑战是在网络浏览器呈现数据后读取数据,这需要一些额外的技巧。如果您可以查看该网站是否具有预渲染版本 * 或API。
This article (linked from the Web archive)对您需要做的事情有很好的细分。但可以总结如下:
*轻微的咆哮 - 不得不希望预渲染版本的应该是静态网页的想法会让我感到愤怒。
答案 1 :(得分:0)
你不能只使用Python。您需要一个像PhantomJS
这样的JavaScript引擎API使用Phantom,可以非常轻松地设置Web抓取所有页面内容,静态和动态JavaScript内容(如您的情况下的Ajax调用结果)。事实上,您可以将页面事件处理程序注册到页面解析器(例如node.js + phantom.js示例)
/*
* Register Page Handlers as functions
{
onLoadStarted : onLoadStarted,
onLoadFinished: onLoadFinished,
onError : onError,
onResourceRequested : onResourceRequested,
onResourceReceived : onResourceReceived,
onNavigationRequested : onNavigationRequested,
onResourceError : onResourceError
}
*/
registerHandlers : function(page, handlers) {
if(handlers.onLoadStarted) page.set('onLoadStarted',handlers.onLoadStarted)
if(handlers.onLoadFinished) page.set('onLoadFinished',handlers.onLoadFinished)
if(handlers.resourceError) page.set('onResourceError', handlers.resourceError)
if(handlers.onResourceRequested) page.set('onResourceRequested',handlers.onResourceRequested)
if(handlers.onResourceReceived) page.set('onResourceReceived',handlers.onResourceReceived)
if(handlers.onNavigationRequested) page.set('onNavigationRequested',handlers.onNavigationRequested)
if(handlers.onError) page.set('onError',handlers.onError)
}
此时您可以完全控制正在进行的操作以及在必须下载的页面中的时间,如:
var onResourceError = function(resourceError) {
var errorReason = resourceError.errorString;
var errorPageUrl = resourceError.url;
}
var onResourceRequested = function (request) {
var msg = ' request: ' + JSON.stringify(request, undefined, 4);
};
var onResourceReceived = function(response) {
var msg = ' id: ' + response.id + ', stage: "' + response.stage + '", response: ' + JSON.stringify(response);
};
var onNavigationRequested = function(url, type, willNavigate, main) {
var msg = ' destination_url: ' + url;
msg += ' type (cause): ' + type;
msg += ' will navigate: ' + willNavigate;
msg += ' from page\'s main frame: ' + main;
};
page.onResourceRequested(
function(requestData, request) {
//request.abort()
//request.changeUrl(url)
//request.setHeader(key,value)
var msg = ' request: ' + JSON.stringify(request, undefined, 4);
//console.log( msg )
},
function(requestData) {
//console.log(requestData.url)
})
PageHelper.registerHandlers(page,
{
onLoadStarted : onLoadStarted,
onLoadFinished: onLoadFinished,
onError : null, // onError THIS HANDLER CRASHES PHANTOM-NODE
onResourceRequested : null, // MUST BE ON PAGE OBJECT
onResourceReceived : onResourceReceived,
onNavigationRequested : onNavigationRequested,
onResourceError : onResourceError
});
如您所见,您可以定义页面处理程序并控制流程以及该页面上加载的资源。因此,在您获取整个页面源之前,您可以确保所有数据都已准备就绪并已设置:
var Parser = {
parse : function(page) {
var onSuccess = function (page) { // page loaded
var pageContents=page.evaluate(function() {
return document.body.innerText;
});
}
var onError = function (page,elapsed) { // error
}
page.evaluate(function(func) {
return func(document);
}, function(dom) {
return true;
});
}
} // Parser
在这里,您可以看到onSuccess回调中加载的整个页面内容:
var pageContents=page.evaluate(function() {
return document.body.innerText;
});
该页面来自Phantomjs,如下面的代码段所示:
phantom.create(function (ph) {
ph.createPage(function (page) {
Parser.parse(page)
})
},options)
当然这可以让你了解你可以用node.js + Phantomjs做些什么,它们在组合在一起时非常强大。
您可以在Python环境中运行phantomjs,将其称为
try:
output = ''
for result in runProcess([self.runProcess,
self.runScript,
self.jobId,
self.protocol,
self.hostname,
self.queryString]):
output += '' + result
print output
except Exception as e:
print e
print(traceback.format_exc())
使用子进程Popen执行二进制文件:
def runProcess(exe):
p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while(True):
retcode = p.poll() #returns None while subprocess is running
line = p.stdout.readline()
yield line
if(retcode is not None):
break
当然,在这种情况下运行的进程是node.js
self.runProcess='node'
你需要args作为参数。