Почему этот код phantomjs возвращает null и заголовок документа?

#javascript #phantomjs

#javascript #phantomjs

Вопрос:

Я пытаюсь изучить PhantomJS. Я был бы признателен, если бы вы помогли мне понять, почему приведенный ниже код выдает ошибку (показано ниже), и помогли мне исправить ошибку. Я пытаюсь выполнить некоторый javascript на странице, используя phantomjs. Строки кода в функции evaluate хорошо работают, когда я ввожу их в консоль Chrome, т. Е. Они дают ожидаемый результат (document.title).

Спасибо.

Код PhantomJS

 var page = require('webpage').create();

var url = 'http://www.google.com';

page.open(url, function(status) {


    var title = page.evaluate(function(query) {
        document.querySelector('input[name=q]').setAttribute('value', query);

        document.querySelector('input[name="btnK"]').click();

        return document.title;
    }, 'phantomJS');

    console.log(title);

    phantom.exit()
})
  

Ошибка

 TypeError: 'null' is not an object (evaluating 'document.querySelector('input[name="btnK"]').click')

  phantomjs://webpage.evaluate():4
  phantomjs://webpage.evaluate():7
  phantomjs://webpage.evaluate():7
null
  

Редактировать 1: В ответ на ответ Эндрю

Эндрю, это странно, но на моем компьютере кнопка является элементом ввода. На следующем скриншоте показан результат на моем компьютере.

Редактировать 2: событие щелчка ненадежно

Иногда следующее событие щелчка срабатывает, иногда нет.

 document.querySelector('input[name="btnK"]')
  

Мне не ясно, что происходит.

Об ответе

Для будущих читателей, в дополнение к ответу, суть Artjom B. полезна для понимания того, что происходит. Однако для более надежного решения я думаю, что что-то вроде waitfor.js необходимо будет использовать пример (как предложено в ответе). Я надеюсь, что можно скопировать и вставить здесь суть Artjom B. Хотя приведенная ниже суть работает (с отправкой формы); мне все еще не ясно, почему это не работает, если я пытаюсь имитировать нажатие кнопки на входе. Если кто-нибудь может прояснить это, было бы здорово.

 // Gist by Artjom B.
var page = require('webpage').create();
var url = 'http://www.google.com';
page.open(url, function(status) {
    var query = 'phantomJS';
    page.evaluate(function(query) {
        document.querySelector('input[name=q]').value = query;
        document.querySelector('form[action="/search"]').submit();
    }, query);
    setTimeout(function(){
        var title = page.evaluate(function() {
            return document.title;
        });
        console.log(title);
        phantom.exit();
    }, 2000);
});
  

Комментарии:

1. Google может доставлять разные страницы разным клиентам, поэтому это может быть «ввод» для вашего браузера, но «кнопка» для phantomjs. Попробуйте войти в document.body и проверьте, что там на самом деле.

2. Спасибо Эндрю. Это ввод, но с именем =»btnG». На этот раз он не выдал ошибку. Итак, эта часть сработала. Однако он также не нажал кнопку. Заголовок страницы, который он вернул, был «Google» таким же, как и до отправки поискового запроса.

3. Это имеет смысл. щелчок вызовет навигацию, и это требует времени. Чтобы получить новый заголовок, подождите некоторое время, например, 3 секунды, или прослушайте событие загрузки страницы следующим образом: page.onLoadFinished = function(){ ..evaluate.. } . Также проверьте casperjs, он построен на Phantomjs, но проще в использовании.

Ответ №1:

Google использует форму для отправки своих запросов. Также весьма вероятно, что Google изменил методы прототипа для своих кнопок поиска, поэтому это не самый лучший сайт для тестирования веб-очистки.

Самый простой способ сделать это — фактически выполнить отправку формы, которая немного изменяет ваш пример.

 var page = require('webpage').create();
var url = 'http://www.google.com';
page.open(url, function(status) {
    var query = 'phantomJS';
    var title = page.evaluate(function(query) {
        document.querySelector('input[name=q]').value = query;
        document.querySelector('form[action="/search"]').submit();
        return document.title
    }, query);
console.log(title);
phantom.exit();
});
  

Обратите внимание, что вам, вероятно, нужно учитывать, что ответ на этот вызов является асинхронным, поэтому прямое получение заголовка, скорее всего, приведет к неопределенной ошибке (вам нужно учитывать время, необходимое для загрузки страницы перед поиском данных; вы можете просмотреть это в ихwaitfor.js пример).

Комментарии:

1. Вы правы, вы никак не можете нажать эту кнопку с помощью phantomjs (или casperjs). Возможно, вы захотите немного подождать, прежде чем возвращать заголовок. Посмотрите на эту суть .

2. Ваша суть отлично сработала. Спасибо. Однако тот же самый setTimeout не работает при нажатии кнопки. Почему требуется отправка формы? Нажатие кнопки не отправляет форму?

3. @Curious2learn Обычно форма отправляется щелчком мыши, но я думаю, что Google использует некоторые методы для обнаружения клиента и бросает камни на пути. Действительно сложно перемещаться по сайтам Google, используя phantomjs / casperjs. Почти все другие сайты ведут себя корректно. Все еще существуют проблемы с предположениями о том, как работают phantomjs / casperjs, иначе не было бы так много вопросов по SO.

4. Спасибо, Артджом. Как вы и rknuu сказали, я не должен пробовать что-то в Google при изучении webscraping и PhantomJS.

Ответ №2:

Вы можете открыть google.com и попробуйте document.querySelector(‘input[name=»btnK»]’) в консоли имеет значение null. ввод Google

Фактически попробуйте заменить ввод на button:

 document.querySelector('button[name="btnK"]')
  

кнопка поиска в Google

Комментарии:

1. пожалуйста, смотрите мой ответ выше как редактирование 1.