Дискуссии: Парсинг сайта при помощи PhantomJS

Парсинг сайта при помощи PhantomJS + CasperJS

By Firepush |

В данной статье я расскажу о том, как при помощи скриптового браузера PhantomJS со связкой с CasperJS мне удалось собрать ссылки на RSS-ленты нужных сайтов. Начало истории можно узнать в предыдущей статье про алгоритм нахождения тем новостей.

 

О существовании подобных инструментов я узнал совсем недавно из свежей статьи на Хабре про SlimerJS. Последний отличается от Фантома другим браузерным движком и тем, что видно окно браузера. Изучив тему внимательней, я понял что CasperJS значительно облегчает написание кода. Но сделать так, чтобы Slimer заработал вместе с ним, у меня не получилось. Плюнув, я установил Фантом – все пошло без проблем.

 

Вся прелесть в том, что нам не нужно имитировать браузер, так как мы им и являемся! Вся возня с куками, прописыванием мета-информации и прочим, как при работе с curl – в прошлом. Некоторое время я поупражнялся с примерами из FAQ, пробежался вдоль по документации CasperJS и приступил.

 

Но немного отвлечемся. Напомню, что на руках у меня был список из более чем двух тысяч ссылок на самые разные ресурсы из Яндекс-Новостей. Задача: имея этот список, получить список ссылок на rss-ленты. От парсинга яндекс-подписок я отказался по причинам, указанным в прошлой статье. Удивительно, что мне не сразу пришла мысль, что помимо кривых яндекс-подписок, есть другие крутые RSS-читалки, учитывая что сам активно пользуюсь Feedler. А что, если они тоже предоставляют ссылки на rss-ленты?

 

В первую очередь посмотрел упомянутый Feedler. Отпадает – rss ссылок не дает. Стал гуглить и почти сразу наткнулся на digg.com. Минималистичный дизайн сразу приглянулся. Зарегистрировался, проверил – идеально! Помимо того, что определяет 90% всех ссылок, делает это почти всегда верно, причем, если находит несколько лент, показывает все по убыванию важности (тоже весьма точно). Но и это не все! Как оказалось, не нужно даже каждый раз при поиске вписывать ссылку в поисковую форму: искомое слово подставляется get-параметром:

 

voBhqPa

 

Просто подарок судьбы!

 

Итак, формализуем. Скрипт должен авторизоваться на сайте, потом по циклу генерировать урл в формате, как на скрине выше, открывать страницу и парсить ссылки на RSS. Ничего сложного.

 

Но, как всегда, возникли некоторые затруднения. Логин только через fb, twitter или g+. А еще иногда процесс парсинга непонятно почему прерывался. Поскольку окно браузера не отображается в Фантоме, я долго не мог понять в чем дело. На помощь пришла функция, позволявшая сделать скриншот браузера и сохранить в корень программы. Так я определил, что во всем виновато всплывающее окно, предлагающее похвалить Digg в соцсетях, и блокирующее все действия. Благо, это было легко исправить, указав, что, если на странице есть элемент с определенным css-селектором, нужно нажать на него (крестик этого окна) и продолжаем дальше.

 

Код программы привожу ниже:

 

 

 

//Login with google

var username = ‘**********’, password = ‘*****’;

 

var casper = require(‘casper’).create();

casper.start(‘http://digg.com/session/google?display=page&next=%2Freader’, function () {

this.fill(‘form#gaia_loginform’, {

‘Email’: username,

‘Passwd’: password

}, true); // submit

 

});

 

//check login status

casper.then(function() {

this.echo(this.getCurrentUrl());

this.capture(‘scr2.png’, {

top: 0,

left: 0,

width: 1920,

height: 1080

});

});

 

//huge array of urls

var urls = [

“newizv.ru”,

“finance.obozrevatel.com”,

“echomsk.spb.ru”,

“kurs.ru”,

//about 2000 urls here

“42.tut.by”,

“report.az”,

]

 

//main code

while(urls.length) {

var url = urls.shift();

var link = ‘http://digg.com/reader/search/’ + url;

casper.thenOpen(link, function() {

this.echo(this.getCurrentUrl()); //show in console current url

this.wait(2000); //waiting for result in page

});

 

//check if popup exists, if true – close it.

casper.then(function() {

if (this.exists(“div.btn-modal-close”)) {

this.click(“div.btn-modal-close”);

}

});

 

casper.then( function() {

this.echo(this.fetchText(‘div.discovery-feed-item-feed-url’));

var res = this.fetchText(‘div.discovery-feed-item-feed-url’) + ‘\n’;

var fs = require(‘fs’);

fs.write(“myfile.txt”, res, ‘a’); // a – append to file

}

);

};

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

//Login with google

var username = ‘**********’, password = ‘*****’;

 

var casper = require(‘casper’).create();

casper.start(‘http://digg.com/session/google?display=page&next=%2Freader’, function () {

this.fill(‘form#gaia_loginform’, {

‘Email’: username,

‘Passwd’: password

}, true); // submit

 

});

 

//check login status

casper.then(function() {

this.echo(this.getCurrentUrl());

this.capture(‘scr2.png’, {

top: 0,

left: 0,

width: 1920,

height: 1080

});

});

 

//huge array of urls

var urls = [

“newizv.ru”,

“finance.obozrevatel.com”,

“echomsk.spb.ru”,

“kurs.ru”,

//about 2000 urls here

“42.tut.by”,

“report.az”,

]

 

//main code

while(urls.length) {

var url = urls.shift();

var link = ‘http://digg.com/reader/search/’ + url;

casper.thenOpen(link, function() {

this.echo(this.getCurrentUrl()); //show in console current url

this.wait(2000); //waiting for result in page

});

 

//check if popup exists, if true – close it.

casper.then(function() {

if (this.exists(“div.btn-modal-close”)) {

this.click(“div.btn-modal-close”);

}

});

 

casper.then( function() {

this.echo(this.fetchText(‘div.discovery-feed-item-feed-url’));

var res = this.fetchText(‘div.discovery-feed-item-feed-url’) + ‘\n’;

var fs = require(‘fs’);

fs.write(“myfile.txt”, res, ‘a’); // a – append to file

}

);

};

Результат на выходе получился не самым читаемым, так как fetchText не поддерживает разделителей. Впрочем, все ссылки все равно начинаются на http, поэтому с их последующим разделением проблем не было.

 

 

Add Comment

Required fields are marked *. Your email address will not be published.