Всё о web

Для чайников и не только


Парсинг ajax сайтов (Casperjs)

Август 31, 2016

Существуют некоторое количество сайтов, которые не хотят отдавать нормальную страницу по прямому запросу. Будь то защита от копирования, использование сорт оф 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 + "\n");
      });
      file.close();
    });
  });
});

casper.run();

var baseUrl = .. - это url самого сайта, обязательно без закрывающего слеша. Он нам нужен чтобы сформировать правильные url, так как на сайте все ссылки используют относительные пути.

var pageUrl = .. - Адрес первой страницы на которой расположены ссылки на статьи.

var resultFileName = .. - Файл, куда будут сохраняться спарсенные урлы.

var nextPageSelector = .. - css селектор для ссылки, которая ведёт на следующую страницу.

var linksSelector = .. - css селектор по которому выбираются ссылки непосредственно на статьи.

Запускаем его и на выходе получаем файл со списком всех нужных урлов. Тут мы использовали 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("\n");
  var csvFile = fs.open(outputDir + 'urls.csv', 'a');
  csvFile.write("url,file\n");
  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 + "\n");
      csvFile.close();
      var pageFile = fs.open(outputDir + pageFileName, 'w');
      pageFile.write(this.getHTML());
      pageFile.close();
      
    });
  });
});

casper.run();

var inputFile = .. - Путь к файлу с ссылками (создан прошлым скриптом)

var outputDir = .. - Папка, куда всё это сохранять.

На этом всё, остаётся только подождать, пока скрипт сам, автоматически сделает всю работу.



Комментарии

Оставить комментарий:

Ваш e-mail не будет опубликован. Обязательные поля помечены *