#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.
Фактически попробуйте заменить ввод на button:
document.querySelector('button[name="btnK"]')
Комментарии:
1. пожалуйста, смотрите мой ответ выше как редактирование 1.