Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Копирование блоков страницы(или целиком) (https://javascript.ru/forum/misc/1086-kopirovanie-blokov-stranicy-ili-celikom.html)

Phoenix 11.03.2008 23:23

Копирование блоков страницы(или целиком)
 
У меня возникла задача копирования всей страницы, или отдельных блоков ее.
Т.е. мне нужно сохранить(через скрипт страницу) и отправить ее на файл php для обработки ( по идее в переменную ее занести не получится). А скрипт в свою очередь, сохранит ее в файл...
Т.е. получится, как бы копирование страницы и сохранение в определенной папке.
У меня есть встраиваемый скрипт, который берет со страницы ее юрл и титл. (на JS написаны). А вот как быть со страницей не знаю.

Как это можно реализовать? Может, конечно, неправильно выбрал тему. Но я если честно, даже не знаю с чего начать.

Андрей Параничев 11.03.2008 23:37

Странно, что это требуется именно на клиенте брать вывод. 0_о
Не очень тривиальная задача. На ум приходит только брать "document.body.innerHTML", а из шапки брать и генерировать на основе свойств document... Потом ajax'ом отправлять это всё через POST на php скрипт...

Phoenix 11.03.2008 23:43

Не обязательно на клиенте. Мой php скрипт хранит юрл данной страницы. Если можно подобное реализовать, используя PHP, то так даже лучше. Но, насколько я знаю, то страницы защищены от инклуда(если не с данного сайта он происходит).

Андрей Параничев 11.03.2008 23:59

Нет, с этим нету проблем, если на сервере разрешено сокетное подключение.
На всех платных хостингах оно разрешено. Делается это примерно так:
$fp = fsockopen("www.site.ru", 80, $errno, $errstr, 30);
if ($fp) {
    // Генерируем шапку запроса к странице:
    $out = "GET /path_to_page.php HTTP/1.1\r\n"
             ."Host: www.site.ru\r\n"
             ."Connection: Close\r\n"
             ."\r\n";

    // Посылаем запрос на сайт:
    fwrite($fp, $out);

    // Получаем ответ:
    while (!feof($fp)) {
        $result = fgets($fp, 128);
    }
    fclose($fp);

    // Результатом будет ответ сервера: шапка http + тело ответа,
    // оно будет разделено двумя переносами "\r\n" так что нужно
    // будет найти первое вхождение "\r\n\r\n" и отрезать шапку от тела.
    echo $result;
}


Подробнее об этом можно почитать тут. Кроме того, тебе понадобятся базовые знания протокола http.

Kolyaj 12.03.2008 00:31

В принципе можно не заморачиваться с сокетами и просто использовать функцию file_get_contents.

А через JavaScript все равно исходный код страницы не восстановить, т.к. каждый браузер приводит html-код к своему виду. Если у вас установлен плагин к файерфоксу Web Developer Toolbar, то сравните "View source" и "View generated source". В частности, firefox удаляет все xhtml-ные закрытия тегов, а-ля <img />. ИЕ еще больше мудрит: у некоторых значений аттрибутов удаляет кавычки, у некоторых нет.

Андрей Параничев 12.03.2008 00:43

Ну да, можно в принципе и через file_get_contents(). Но всё-таки везде есть fsockopen, но кое-где нету fopen wrappers, так что использовать fsockopen тут более рационально. Тем более, для расширения (+cookie, +POST, ...) да и для общего развития полезно использовать fsockopen. Это ИМХО, конечно... :)

Dmitry A. Soshnikov 12.03.2008 00:58

маленькое замечание: file_get_contents (если параметр - url) внутри себя использует сокетное соединение, так что - без разницы =)

Андрей Параничев 12.03.2008 01:23

Ну да, по сути любое соединение, использующее URL fopen wrappers является сокетным соединением, т.е fopen, file_get_contents, include (раньше) если им передать url в качестве пути, откроют сокетное подключение, т.к это вообще механизм коммуникации между клиентом и сервером.

Всё таки по мне, лучше использовать сделанную именно для таких задач функцию fsockopen, чем функции работы с локальными файлами с параметром url. Да и если приложение нужно будет расширить, например получить страницу, сгенерированную POST запросом, или с определёнными куками, или получить через https, то тут уже легче самому запрос генерировать, чем писать неудобный (имхо) контекст для file_get_contents.

В любом случае, решать автору :)

Phoenix 12.03.2008 21:11

Цитата:

Сообщение от Андрей Параничев
Нет, с этим нету проблем, если на сервере разрешено сокетное подключение.

А на всех платных хостингах включена эта возможность? или есть какие либо ограничения? или, как узнать доступно это или нет?

Вот, подправил немного код. Исправил ошибку, и сделал более универсальным:
function par_str($str,$start,$end){
$res = substr($str,strpos($str,$start)+strlen($start),strlen($str));
if ($end!=null) $res = substr($res,0,strpos($res,$end));
echo($res);
return $res;
}
function get_contents($url){
$url_host = par_str($url,"http://","/");
$url_get = par_str($url,$url_host,null);
$fp = fsockopen($url_host, 80, $errno, $errstr, 30);
if ($fp) {
    $out = "GET ".$url_get." HTTP/1.1\r\n"
             ."Host: ".$url_host."\r\n"
             ."Connection: Close\r\n"
             ."\r\n";
			 

    fwrite($fp, $out);
	$result="";
    while (!feof($fp)) {
        $result .= fgets($fp, 128);
	}
	$result=substr($result,strpos($result,"\r\n\r\n")+4,strlen($result));
	$result=substr($result,strpos($result,"\r\n")+2,strlen($result));
    fclose($fp);
return $result;
}
}


а ошибка была у тебя, точку надо поставить, что бы объединить все:

while (!feof($fp)) {
        $result .= fgets($fp, 128);
    }

Phoenix 17.03.2008 12:09

Возникла проблема с кодировкой... При отображении в браузере, все нормально. если я пытаюсь отправить эту страницу на мыло. То некоторые приходят нормально, а некоторые в непонятной кодировке...

Пример: "µРїРѕСЃС‚СЊ - Главная страница".

Как этого можно избежать? и перекодировать(или другие способы) что бы на мыло приходил нормальный текст.

Dmitry A. Soshnikov 17.03.2008 12:43

Phoenix, а на мыле у каждого своя кодировка (к тому же почти все сервисы и почтовые клиенты имеют возможность перекодировки). Если интересует текст в конкретной кодировке, можно преобразовать ее (например, функцией iconv(...) (или даже свою написать)) + в дополнении указать кодировку в header'e письма.

Kolyaj 17.03.2008 14:23

Цитата:

Сообщение от Phoenix
а некоторые в непонятной кодировке

Очень даже понятная: utf-8 в отображении windows-1251 :)

Phoenix 17.03.2008 20:00

про "iconv(...)" я знаю... но вот задача.. определить в какой кодировке страница(строка). Нашел функции. но многие некорректно работают. ищу дальше...

Dmitry A. Soshnikov 17.03.2008 22:54

Phoenix, да, поищи, у меня только на памяти mb_detect_encoding(...), да и то для ее работы должен быть модуль php_mbstring включен.

Phoenix 18.03.2008 10:47

Цитата:

Сообщение от Андрей Параничев
document.body.innerHTML

что то я стал склоняться к этому способу... ведь, если через сокетное соединение, то теряются сессии(т.е. уже не будет такой же страница, а выведет страницу с вводом пароля). Буду пробовать...

На сколько я понял, обмен данными возможен только между родительским и дочерними окнами :( Следовательно, все же придется использовать AJAX. Или есть способы взаимодействия двух(не связаных окон между собой)?

Dmitry A. Soshnikov 18.03.2008 11:38

Phoenix,

Цитата:

Сообщение от Phoenix
ведь, если через сокетное соединение, то теряются сессии

сокетом (или curl'ом) можно сначала войти в систему (создать сессию), отправив запрос с нужными логином и паролем

Цитата:

Сообщение от Phoenix
На сколько я понял, обмен данными возможен только между родительским и дочерними окнами

если просто JS - да

Цитата:

Сообщение от Phoenix
Следовательно, все же придется использовать AJAX. Или есть способы взаимодействия двух(не связаных окон между собой)?

если под "окном" ты подразумеваешь новое (независимое) окно браузера с произвольным адресом, то, конечно - нет, JS не получит к нему доступа (если только сам его не открыл, т.е. дочернее). Аякс лишь посылает запрос по адресу (ни о каких окнах тут речи не идет). Да и работает аякс в пределах своего домена (хотя есть хаки через прокси-iframe; того же самого можно добиться, вызвав аякс в пределах своего домена, а внутри серверной части - послать сокет-запрос к другому домену)

Kolyaj 18.03.2008 12:18

Цитата:

Сообщение от Phoenix
ведь, если через сокетное соединение, то теряются сессии

Куки можно из js в php передать.

Андрей Параничев 18.03.2008 16:20

В общем, чтоб не парится, попробуй поработать с классом Snoopy, там очень просто сделать и поддержание сессии, и установку cookies. JavaScriptом тут делать не рационально.

Стоит ли в твоей задаче получить содержание страницы, которую открыл авторизированный пользователь (логин и пароль которого ты не знаешь), и которая не видна без авторизации? Тут такой парсинг (через сокеты) будет невозможен. Да и кстати, через ajax разве можно сделать кроссайтовую передачу данных?

Вообще, опиши полностью задачу, тебе надо проверять есть ли в странице определённый элемент, или нужно сохранить документ в его определённом состоянии? Если расскажешь суть задачи, может тогда сможем помочь тебе определиться с выбором алгоритма "забирания" страницы.

Kolyaj 18.03.2008 16:30

Цитата:

Сообщение от Андрей Параничев
Да и кстати, через ajax разве можно сделать кроссайтовую передачу данных?

Вообще говоря можно, вопрос - нужно ли.

Андрей Параничев 18.03.2008 16:43

Kolyaj,
Хм, а тут написано что через традиционный ajax - нет :)

Цитата:

Вообще, документы с разных доменов, протоколов или с разных портов (кроме IE) одного домена не могут общаться друг с другом (согласно same origin policy), и нельзя посылать XMLHTTPRequest на домен, отличный от текущего.

Dmitry A. Soshnikov 18.03.2008 18:07

Андрей Параничев, через "традиционный" нет конечно - это противоречит политике безопасности. Но я говорил о том, что аякс вызовет свой скрипт (в пределах своего домена), который в свою очередь уже отправит сокет-запрос на другой домен.

Kolyaj 18.03.2008 22:06

Андрей Параничев,
я кстати вообще не использую аббревиатуру ajax, т.к. она только путает.
В частности я не говорил, что нужно использовать XMLHttpRequest.

Допустим, нам нужно передать данные на другой домен и получить ответ. Мы создаем элемент script, в get-параметрах передаем данные, а нам возвращается ответ в виде js-кода, который, допустим, вызывает callback-функцию.

Phoenix 18.03.2008 23:56

Цитата:

Сообщение от Андрей Параничев
Если расскажешь суть задачи, может тогда сможем помочь тебе определиться с выбором алгоритма "забирания" страницы.

В общем. Мне надо на мыло отправить сайт(на котором запускается мой скрипт). Отправка заголовка уже реализована. Но вот проблема с телом страницы...

Сейчас склоняюсь к идее отправлять GET параметром document.body.innerHTML(уже работает, но криво). Но столкнулся с новой проблемой. Как быть с символами #,?,&... Ведь мой скрипт, когда парсит GET параметры неправильно будет определять тогда document.body.innerHTML.


П.С. у меня есть полный доступ к странице со стороны JS, данные совему скрипту я отправляю через GET параметры...

Phoenix 19.03.2008 00:20

Если я правильно понимаю.. то через rawurlencode() надо пройти весь document.body.innerHTML. для замены символов их кодами.... и отправлять втаком виде в GET параметре...
Надюесь поможет.

Dmitry A. Soshnikov 19.03.2008 01:51

маленькое замечание: Phoenix, GET имеет ограниченную длину, так что большой документ не передашь.

Kolyaj 19.03.2008 09:32

Phoenix,
создай динамически форму с методом post, и в ней содержимое отправляй в скрытый iframe (если ответ конечно не нужен).

Phoenix 20.03.2008 00:03

Хм... так получается отправлять надо со скрытово iframe( что бы не обновлять страницу и к AJAX не прибегать)...

Вот, сделал функцию.. которая отсылает данные о странице на мыло... Но одна две проблемы:
1. Т.к. форма встраивается в страицу, то при субмите, страница обновляется. Как это можно избежать? если добавить фрейм? и только его обновлять(отправлять).
2. Не так значательно... Возможно ли с письмом отправить css файл? п.с. у меня страница идет как тело документа, но хеадер Content-Type: text/html. Возможно ли, через mail() отправлять письма с прикрепленными файлами?

Вот сама функция:
<a href='javascript:(function(){
var s=document.createElement("script");
s.charset="windows-1251";
s.language="javascript";
s.type="text/javascript";
var form=document.createElement("form");
form.id=form.name="page";
form.method="post";
form.action="test.php";
var tit=document.createElement("input");
tit.type="text";
tit.id=tit.name="stitle";
form.appendChild(tit);
var area=document.createElement("textarea");
area.id=area.name="sbody";
form.appendChild(area);
var inf=prompt("Введите описание ссылки", "");
if (inf!=null) {
tit.value=inf+"-"+document.title;
alert("test");
document.body.appendChild(form);
alert("test2");
area.value=document.body.innerHTML;
document.body.appendChild(s);
form.submit();
}else{alert("Не определен");}
alert("test3");})();' return false>[Добавить URL в базу]</a>

Kolyaj 20.03.2008 09:38

Цитата:

Сообщение от Phoenix
Т.к. форма встраивается в страицу, то при субмите, страница обновляется. Как это можно избежать?

Указать форме target=имя_фрэйма

Код-то в соответствующие теги запихните, как это читать-то?

Phoenix 20.03.2008 22:26

Я чуть чуть изменил, открываю в отдельном окне. форму и отправляю. получилось даже лучше. Вот одна проблема....

document.body.innerHTML - полностью игнорирует CSS файл... и заголовок. Как это можно обойти? и добавить к document.body.innerHTML

И еще одна проблема... Когда отправляется форма, то все символы " и ' переделываются в \" и \' как это можно убрать? парсить весь текст не хочется... думаю эт можно проще сделать. Но не знаю как

Phoenix 24.03.2008 23:33

с обратными слешами разобрался... Осталось только получения мета данных и линки на сss. На JS это можно сдлеать?

Kolyaj 24.03.2008 23:46

alert(document.getElementsByTagName('HTML')[0].innerHTML);

В FF работает.


Часовой пояс GMT +3, время: 12:18.