хуйу нас не матерятся
Существуют некоторое количество сайтов, которые не хотят отдавать нормальную страницу по прямому запросу. Будь то защита от копирования, использование сорт оф ReactJS либо, как в моём случае, SSO технология. Встречайте: http://www.orthopaedicsandtraumajournal.co.uk.
Наша задача - скравлить все статьи с сайта. Автоматический php парсер тут обломался и я полез смотреть причину. Для начала скачиваем wget'ом какую-нибудь страницу, например:
wget "http://www.orthopaedicsandtraumajournal.co.uk/issue/S1877-1327(16)X0004-8"
Открываем её и видим следующее:
<!-- hidden iFrame for each of the SSO URLs -->
<div class="hidden">
<iframe src="//acw.secure.jbs.elsevierhealth.com/SSOCore/update?utt=7a73f03e93ed651d4875d32-edc8135c83377a70">Your browser doesn't support iFrames!</iframe>
<iframe src="//acw.sciencedirect.com/SSOCore/update?utt=7a73f03e93ed651d4875d32-edc8135c83377a70">Your browser doesn't support iFrames!</iframe>
<iframe src="//acw.scopus.com/SSOCore/update?utt=7a73f03e93ed651d4875d32-edc8135c83377a70">Your browser doesn't support iFrames!</iframe>
<iframe src="//acw.sciverse.com/SSOCore/update?utt=7a73f03e93ed651d4875d32-edc8135c83377a70">Your browser doesn't support iFrames!</iframe>
<iframe src="//acw.mendeley.com/SSOCore/update?utt=7a73f03e93ed651d4875d32-edc8135c83377a70">Your browser doesn't support iFrames!</iframe>
<iframe src="//acw.elsevier.com/SSOCore/update?utt=7a73f03e93ed651d4875d32-edc8135c83377a70">Your browser doesn't support iFrames!</iframe>
</div>
<noscript>
<a href="http://www.orthopaedicsandtraumajournal.co.uk/action/consumeSharedSessionAction?JSESSIONID=aaageCSP07pBp-JRGRwBv&MAID=EG3%2FXcO6rdQJcCVEIjGplg%3D%3D&SERVER=WZ6myaEXBLGvmNGtLlDx7g%3D%3D&ORIGIN=501907480&RD=RD">Redirect</a>
</noscript>
<!-- redirect to the product page after all iFrames are rendered -->
<script>
setTimeout(redirectFun,2000);
var iFramesList = document.getElementsByTagName("iframe");
var renderedIFramesCount = 0;
var numberOfIFrames = iFramesList.length;
for (var i = 0; i < iFramesList.length; i++) {
var iFrame = iFramesList[i];
bindEvent(iFrame, 'load', function(){
renderedIFramesCount = renderedIFramesCount + 1;
if (renderedIFramesCount >= numberOfIFrames)
{
redirectFun();
}
});
}
var doRedirect = true;
function redirectFun() {
if (doRedirect)
window.location.href = "http://www.orthopaedicsandtraumajournal.co.uk/action/consumeSharedSessionAction?JSESSIONID=aaageCSP07pBp-JRGRwBv&MAID=EG3%2FXcO6rdQJcCVEIjGplg%3D%3D&SERVER=WZ6myaEXBLGvmNGtLlDx7g%3D%3D&ORIGIN=501907480&RD=RD";
doRedirect = false;
}
function bindEvent(el, eventName, eventHandler) {
if (el.addEventListener){
el.addEventListener(eventName, eventHandler, false);
} else if (el.attachEvent){
el.attachEvent(eventName, eventHandler);
}
}
</script>
Клиенту отдаётся страница со скрытыми фреймами. Затем скрипт ждёт загрузки фреймов и только потом загружает реальную страницу. Ок, мы живём в 21 веки и у нас есть CasperJS!
Для начала пишем скриптик для сбора урлов всех статей с этого сайта:
var fs = require('fs');
var casper = require('casper').create();
var baseUrl = 'http://www.orthopaedicsandtraumajournal.co.uk';
var resultFileName = 'links.txt';
var nextPageSelector = '.prevIssue > a';
var linksSelector = '.detail h3 > a';
var pageUrl = 'http://www.orthopaedicsandtraumajournal.co.uk/issue/S0268-0890(05)X0085-8';
casper.start();
casper.then(function(){
casper.repeat(200, function(){
casper.thenOpen(pageUrl, function(){
console.log(this.getCurrentUrl());
aList = this.evaluate(function(selector) {
var al = [];
jQuery(selector).each(function() {
al.push(jQuery(this).attr('href'));
});
return al;
}, linksSelector);
pageUrl = this.evaluate(function(selector){
return document.querySelector(selector).href;
}, nextPageSelector);
var file = fs.open(resultFileName, 'a');
aList.map(function(item) {
file.write(baseUrl + item + "
");
});
file.close();
});
});
});
casper.run();
Запускаем его и на выходе получаем файл со списком всех нужных урлов. Тут мы использовали casper.repeat(200 ... это значит скрипт повторится 200 раз, меняйте его по собственному усмотрению. Мы вынуждены использовать такую неудобную конструкцию потому что в casperjs нет никакого аналога while цикла.
Теперь пишем следующий скриптик, он по очереди откроет каждый урл и сохранит страницу в указанную папку, а чтобы было всё ещё красивее, положим рядом .csv файл в котором покажем, какой .html файл по какому урл был скачен. Код:
var fs = require('fs');
var casper = require('casper').create();
var inputFile = 'links.txt';
var outputDir = 'data/';
casper.start(inputFile, function(){
var links = this.fetchText('pre').split("
");
var csvFile = fs.open(outputDir + 'urls.csv', 'a');
csvFile.write("url,file
");
csvFile.close();
this.each(links, function(self, link){
self.thenOpen(link, function() {
console.log(this.getCurrentUrl());
var d = new Date();
var pageFileName = d.getTime() + '.html';
var csvFile = fs.open(outputDir + 'urls.csv', 'a+');
csvFile.write(this.getCurrentUrl() + "," + pageFileName + "
");
csvFile.close();
var pageFile = fs.open(outputDir + pageFileName, 'w');
pageFile.write(this.getHTML());
pageFile.close();
});
});
});
casper.run();
На этом всё, остаётся только подождать, пока скрипт сам, автоматически сделает всю работу.