PDA

Ver la Versión Completa : idHTTP.get, String o StringList ?


BlackDaemon
26-09-2007, 20:55:18
Bueno, perdón por no poner un título algo mas claro, pero no se me ocurre nada mas, ya el problema que tengo es el siguiente, tengo este código fuente.

procedure TFrmPrincipal.BEnviarClick(Sender: TObject);
var
CodFuente : String;
begin
//CodFuente := TStringList.Create;
CodFuente := IdHTTP1.Get('http://localhost/wifri/entel.html');

memPagina.Text := CodFuente;
memHtml := TStringList.create;
memHtml.Text := memPagina.Text;
try
...

Resulta que quiero tener TODO el código fuente de una página en un Memo.text, peeeero resulta que no lo pega todo el código fuente, si no mas o menos hasta la mitad, ¿Eso a que se debe?
Es por que el tipo de datos String NO puede almacenar muchos caracteres ?
Pero igual lo he intentado con TstringList y nada, pero luego he visto que haciendo un

Memo.text := idHTTP.get(URL);

de igual forma no me regresa TODO el código fuente, entonces supuse que es idHTTP el que NO me regresa.. como podría hacer para que me regrese TODO el código fuente de una página ? Es algo extenso el código fuente, pero no es para tanto, alguna idea ? o algún error que estoy cometiendo ? que debo o puedo usar ?

saludos!

Al González
27-09-2007, 00:49:09
¡Hola!

El método TIdHTTP.Get no es para obtener el código fuente de una URL, es para ejecutar una URL. Son dos cosas distintas. ;)

TODO un abrazo.

Al González. :)

juanelo
27-09-2007, 01:20:46
Hola,
No tiene Frames esa pagina estas tratando de traer?.
PD: Tienes toda la razon al usar el termino traer ya que el metodo GET es precisamente para poder obtener un recurso via HTTP.
Saludos

BlackDaemon
27-09-2007, 02:16:15
Hola Al, gracias por la respuesta, pero entonces lo estoy haciendo mal :(
¿Cual sería la forma correcta de traer el código fuente de una página web?
Es que no solo es de una página, si no de varias, estoy haciendo como un bot para que me automatize algunas tareas (ya, soy flojo xD)
pero la idea es trabajar con cookies, osea sessiones, el código fuente de las páginas que tengo que bajarme van algo asi..

http://www.pagina.com/tarea.php?id=1
http://www.pagina.com/tarea.php?id=2
http://www.pagina.com/tarea.php?id=3
http://www.pagina.com/tarea.php?id=4

Osea que primero tengo que bajarme la una luego la siguiente, etc, eso lo pienso hacer con un bucle, pero ahora cambia mi pregunta.
¿Como puedo bajarme TODO el código fuente de una página web?

Juamelo

Pues no, no tiene frames, ni nada de eso, es que luego tengo que parsearlo y sacar datos de todo el código fuente, y si me regresa la mitad pues los datos son incompletos.

saludos!

Al González
27-09-2007, 02:23:06
Bueno, te comento que Get sí te regresa el código fuente de una página, pero el de la página que resulta de la llamada a la URL que primero le das como parámetro.

Eso quiere decir que una manera de obtener el código fuente de una URL es ejecutar otra URL que te lleve a ella.

Espero te sirva. Busca un tema que abrí hace tiempo, titulado "Automatización Web", presiento que será de tu interés.

Un abrazo.

Al González. :)

BlackDaemon
27-09-2007, 02:49:14
Hola Al.

Pues ya lo he visto muuchas veces ese hilo, me lo he leido todito, que por cierto esta muy bueno, ahora regresando al tema, ya se que te regresa el código fuente de una página web, si tienes una página por ejemplo.

http://www.pagina.com/index.php

y si index.php contiene este código.

<?php
echo "Hello World!";
?>

y si haces algo como

showmessage(idHTTP1.Get('http://www.pagina.com/index.php'));

Te regresará un bonito mensajito SOLO con la palabra Hello World
Si es a eso lo que te refieres lo tengo bien claro, pero si no es a eso, pues no he entendido su respuesta, y si es asi, sigo sin saber ¿Como podría bajarme el código fuente de una página web para luego parsearla?
Solo necesito todo el html

saludos!

Al González
27-09-2007, 02:53:29
Sí, sólo te regresará el HTML. :)

BlackDaemon
27-09-2007, 03:00:00
Hola Al,
Si, eso ya lo sé, pero entonces por que no me regresa TODO el código fuente html de la página que le paso en el idHTTP.get(URL) ??
Solo me regresa como la mitad mas o menos, hay alguna forma de que te regrese TODO el html ?

O no se entiende mi pregunta ? Si es asi me lo dicen y trataré de poner un ejemplo mas claro, y poner la página online mas la aplicación para que vean a que me refiero

Repito ¿como puedo obtener "todo" el código fuente html de una página y pegarla en un memo ?

saludos!

Al González
27-09-2007, 03:05:37
Se comprende el planteamiento, pero como no conozco la página en cuestión me sería difícil deducir la causa.

Una alternativa podría ser utilizar un componente TWebBrowser en lugar de TIdHTTP.

Saludos.

Al.

BlackDaemon
27-09-2007, 03:16:39
Hola Al.

Mira, la página en cuetión seria esta
http://casacimar.com.bo/tarea.html

ahora mi script es este

procedure TFrmPrincipal.Button1Click(Sender: TObject);
begin
memo1.text =: IdHTTP1.Get('http://casacimar.com.bo/tarea.html');
end;

Ahora como podrás ver solo me copia un poco mas de la mitad del html en el memo, eso a que se debe ? o como puedo hacer que me lo copie TODO el html ?

saludos!

dec
27-09-2007, 04:21:09
Hola,

No sé realmente porqué ocurre, porque, los navegadores que he probado "pueden con ello", pero, en el archivo en cuestión parece darse un problema en la línea 191, columna 7. En ese punto puede verse lo siguiente (examinando el código fuente desde Firefox):


<td ?owrap align=right>


Y es a partir del signo de interrogación donde deja de descargar (o no puede mostrar... ya digo que no estoy seguro de qué ocurre realmente) el componente IdHttp. Debe tratarse de un problema con la condificación de caracteres... aunque ya digo que los navegadores que he probado se lo tragan, el propio archivo parece tener algunos problemas.

He probado a usar WinInet (tal como muestra seoane (http://www.clubdelphi.com/foros/showpost.php?p=139416&postcount=5)), pero, sigue produciéndose el mismo problema. También he probado con "UrlMon.URLDownloadToFile()", pero, igual, el mismo caso.

Pero, para usar URLMon he tenido que descargar un archivo, y me ha dado por revisarlo... y, efectivamente, se descarga el código completamente (superando el error que contiene el archivo HTML), y entonces me he dicho, leche, pues es el Memo, que no puede mostrar el código fuente a partir del "error" (línea 191, etc.).

Pero no... no es del todo el Memo. Porque si pruebas con algo como esto:


procedure TForm2.Button1Click(Sender: TObject);
var
t: TStrings;
begin
t := TStringList.Create();
try
t.Text := IdHTTP1.Get('http://casacimar.com.bo/tarea.html');
t.SaveToFile('C:\test.txt');
finally
t.Free();
end;
end;


... verás que tampoco descargas todo el código fuente del archivo, sino que se "queda" en el punto exacto del supuesto error. Vale. ¿Y entonces qué? Pues el caso es que el archivo se descarga completamente. Fíjate que viene a ocupar unos 12 KB, y estas son las cabeceras que envía la respuesta HTTP:


Date: Thu, 27 Sep 2007 02:05:00 GMT
Server: NOYB
Last-Modified: Thu, 27 Sep 2007 01:05:42 GMT
ETag: "32c454-3139-91b7c580"
Accept-Ranges: bytes
Content-Length: 12601
Content-Type: text/html


O sea, que el problema lo tenemos en Delphi, que parece "cortar" el contenido del archivo en cuanto llegamos al error de marras. He probado con String, AnsiString, WideString, PChar... pero, nada. No pasa del error. Como se ve el archivo se descarga completamente, pero, no es posible mostrarlo en un Memo, ni copiarlo al portapeles, ni guardarlo en un archivo mediante un TStrings.

Por el momento no se me ocurre qué más hacer. Si tengo que quedarme con algo... tal vez con URLMon, puesto que consigue descargar el archivo completo... ¡pero IdHTTP también, lo que ocurre es que no hay manera de obtener el contenido más allá de donde se localiza el error del archivo y por tanto no podemos guardarlo (como hace URLMon... por su cuenta... a saber cómo)!

Y, por otro lado... de qué te serviría tener el archivo con su contenido completo (aunque erróneo, o problemático, cuando menos), si no hay manera de cargarlo en un Memo, por ejemplo... Pero yo lo dejo aquí, por el momento, a ver si alguien a partir de esto puede aportar alguna otra cosa. Si a mí se me ocurre alguna la comentaré por aquí.

Siento no poder dar una respuesta válida, pero, espero al menos que se entendiera el rollo que he soltado, que, puesto que he ido escribiéndolo según hacía pruebas, lo mismo no ha quedado del todo "cuadrado". :)

Al González
27-09-2007, 05:53:18
Creo que se trata del típico caso del carácter ASCII 0 (#0). Si una cadena (String) lo contiene, Delphi lo toma como fin de la misma al utilizar dicha cadena como expresión en cualquier sentencia.

En este caso a Demonio Negro le convendría usar la versión sobrecargada:


procedure Get(AURL: string; const AResponseContent: TStream);


Y obtener la respuesta en un flujo (stream) de tipo TMemoryStream, el cual es mejor que una variable String para manejar cualquier cadena de bytes textual o binaria.

Estoy casi seguro que esa es la situación que se presenta. No dejes de comentarnos cómo te fue. :)

Un abrazo binario.

Al González. :)

dec
27-09-2007, 06:00:54
Hola,

Ops... me temo que también probé de esa forma Al... a lo menos con un "TStringStream"... pero, no funcionó... tal vez porque no sea el "flujo" indicado... :(

Al González
27-09-2007, 06:11:56
Hola,

Ops... me temo que también probé de esa forma Al... a lo menos con un "TStringStream"... pero, no funcionó... tal vez porque no sea el "flujo" indicado... :(
Bueno, ya que andas despierto tan temprano ;), prueba con TMemoryStream y dime cuál es el valor de los dos últimos bytes del flujo.

dec
27-09-2007, 06:28:12
Hola,

Me temo que no voy a poder hacer lo que me dices Al... no llego a tanto. Lo que es seguro es que haciendo algo así:


procedure TForm2.Button1Click(Sender: TObject);
var
t: TMemoryStream;
begin
t := TMemoryStream.Create();
try
IdHTTP1.Get('http://casacimar.com.bo/tarea.html',t);

{...}

finally
t.Free();
end;
end;


Efectivamente, en "t" contamos con el contenido del archivo que nos interesa: todo el contenido, es decir, que si guardo "t" en un archivo... en este se verá todo el código fuente del documento HTML en cuestión.

Ahora bien... ¿cómo poner en un Memo el contenido de "t"? Ni idea... con "Memo1.Lines.LoadFromStream(t)" no funciona tal como espero..., por ejemplo, aunque, me temo que pasará igual que antes: que el Memo no podrá mostrar más allá de donde se encuentra el problema en el archivo...

dec
27-09-2007, 06:32:09
Hola,

Pero hay que decir una cosa... supongamos esto:


procedure TForm2.Button1Click(Sender: TObject);
var
t: TStringStream;
begin
t := TStringStream.Create('');
try
IdHTTP1.Get('http://casacimar.com.bo/tarea.html',t);

if Pos('Copyright &copy;', t.DataString) <> 0 then
ShowMessage('Eureka!');

finally
t.Free();
end;
end;


O incluso simplemente esto:


procedure TForm2.Button1Click(Sender: TObject);
var
s: string;
begin
s := IdHTTP1.Get('http://casacimar.com.bo/tarea.html');
if Pos('Copyright &copy;', s) <> 0 then
ShowMessage('Eureka!');
end;


En ambos casos exclamaremos eureka,... y lo que se está buscando está al final del contenido en cuestión... más allá del error, lo que quiere decir que al cabo, al cabo, estamos descargando todo el HTML, salvo que no podemos mostrarlo en un Memo... por ejemplo, pero,... tal vez esto sea lo de menos, en un momento dado.

O dicho de otro modo, tal vez nos baste con el código HTML descargado, y a partir de ahí trabajar, lo mismo no es necesario mostrarlo en un Memo, sino que el compañero lo hacía por "probar", pero, en la práctica, ya digo, a lo mejor no es necesario hacerlo, porque, si se busca algo... puede buscarse directamente en la cadena que contiene el HTML, no es preciso que esté en un Memo.

Al González
27-09-2007, 06:50:36
Tienes toda la razón David. :)

BlackDaemon: ¿servido?

Un abrazo.

Al González. :)

seoane
27-09-2007, 11:47:04
Vaya, aquí los dos maestros ya tuvieron en cuenta todo, la codificación, los ceros cabroncetes, la solución de los streams ... así no hay quien meta baza.

Yo lo que haría seria bajar la pagina a un stream, usando Indy, wininet o lo que prefieras, y luego utilizar utf8Decode para convertir la pagina de utf8 a una codificación normal.

BlackDaemon
27-09-2007, 15:02:25
woooww.. miren, acabo de despertar (8:51 a.m.) en mi pais y me encuentro con un chorro de respuestas, me las he leido todas y la verdad es que he aprendido mucho, ya se que podría ser cuando me pase otra vez el mismo error, y bien como dice el señor dec en si, se baja TODO el código fuente de la página, pero NO se puede mostrarlo, creo que al principio lo he dicho mal, no era la palabra correcta "bajarme", creo que dado el caso sería "mostrarlo" o visualizarlo, etc xD ya que en si ese es el problema.

Y como dice el señor dec

O dicho de otro modo, tal vez nos baste con el código HTML descargado, y a partir de ahí trabajar, lo mismo no es necesario mostrarlo en un Memo, sino que el compañero lo hacía por "probar", pero, en la práctica, ya digo, a lo mejor no es necesario hacerlo, porque, si se busca algo... puede buscarse directamente en la cadena que contiene el HTML, no es preciso que esté en un Memo.

La verdad es que si, "no es necesario mostrarlo en un Memo" y si, lo hacia por probar, y tambien tiene razón de que si busco algo (eso hago) lo puedo hacer "creo" directamente en el código html guardado en memória y sin necesidad de mostrarlo en un memo u otro componente.
En este momento no he probado de buscar algunas cadenas en todo el html sin necesidad de mostrarlo, pero estoy "casi" seguro que si se podrá hacerlo, ya que como muestra el señor dec SI esta hay el código fuente COMPLETO, pero no se puede mostrarlo.

Creo que ya esta solucionado mi problema, muchísimas gracias al señor dec y a Al, y a otros como seoane que siempre anda sando soluciones óptimas y trabaja muy bien con internet xD

pero me queda una duda que no se me ha aclarado, por que no se muestra todo el código fuente de la página en un memo ? Es por lo que dice el señor Al de lo que delphi toma el signo '?' como fin de string ? o a que se debe ?

saludos!

seoane
27-09-2007, 15:59:44
Vamos a ver, el problema es que la pagina suelta un #0 en medio del texto, sin venir a cuento (al menos yo no veo porque lo hace). El carácter #0 (o carácter nulo) se utiliza para indicar el final de una cadena de texto, en delphi, en C y en muchos otros lenguajes. Cuando tu le pasas ese texto a un memo windows interpreta el #0 como el final del texto, por eso no muestra el resto de la cadena.

Una solución rápida es sustituir el carácter #0 por, por ejemplo, un espacio:

uses WinInet;

function DownloadToStream(Url: string; Stream: TStream): Boolean;
var
hNet: HINTERNET;
hUrl: HINTERNET;
Buffer: PChar;
BytesRead: DWORD;
i: Integer;
begin
Result := FALSE;
hNet := InternetOpen('agent', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if (hNet <> nil) then
begin
hUrl := InternetOpenUrl(hNet, PChar(Url), nil, 0,
INTERNET_FLAG_RELOAD, 0);
if (hUrl <> nil) then
begin
GetMem(Buffer,100*1024);
try
while (InternetReadFile(hUrl, Buffer, 100*1024, BytesRead)) do
begin
if (BytesRead = 0) then
begin
Result := TRUE;
break;
end;
// Aqui sustituimos el caracter nulo por un espacio
for i:= 0 to BytesRead - 1 do
if Buffer[i] = #0 then
Buffer[i]:= #32;
Stream.WriteBuffer(Buffer^,BytesRead);
end;
finally
FreeMem(Buffer);
end;
InternetCloseHandle(hUrl);
end;
InternetCloseHandle(hNet);
end;
end;

// Por ejemplo
var
Stream: TStringStream;
begin
Stream:= TStringStream.Create('');
try
DownloadToStream('http://casacimar.com.bo/tarea.html',Stream);
Memo1.Lines.Text:= Stream.DataString;
finally
Stream.Free;
end;
end;

BlackDaemon
27-09-2007, 16:45:57
Hola Seoane:

Bueno, ahora si me ha quedado muy claro el asunto, y muy buena explicación y todo :)


saludos!

dec
27-09-2007, 19:04:14
Hola,

La madre que lo parió. Digo al #0, no a Domingo. :D :D :D